1# Copyright © 2020 Hoe Hao Cheng 2# 3# Permission is hereby granted, free of charge, to any person obtaining a 4# copy of this software and associated documentation files (the "Software"), 5# to deal in the Software without restriction, including without limitation 6# the rights to use, copy, modify, merge, publish, distribute, sublicense, 7# and/or sell copies of the Software, and to permit persons to whom the 8# Software is furnished to do so, subject to the following conditions: 9# 10# The above copyright notice and this permission notice (including the next 11# paragraph) shall be included in all copies or substantial portions of the 12# Software. 13# 14# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20# IN THE SOFTWARE. 21# 22# Authors: 23# Hoe Hao Cheng <haochengho12907@gmail.com> 24# 25 26from mako.template import Template 27from mako.lookup import TemplateLookup 28from os import path 29from zink_extensions import Extension,ExtensionRegistry,Version 30import sys 31 32# constructor: 33# Extension(name, alias="", required=False, properties=False, features=False, conditions=None, guard=False) 34# The attributes: 35# - required: the generated code debug_prints "ZINK: {name} required!" and 36# returns NULL if the extension is unavailable. 37# 38# - properties: enable the detection of extension properties in a physical 39# device in the generated code using vkGetPhysicalDeviceProperties2(), 40# and store the returned properties struct inside 41# `zink_device_info.{alias}_props`. 42# Example: the properties for `VK_EXT_transform_feedback`, is stored in 43# `VkPhysicalDeviceTransformFeedbackPropertiesEXT tf_props`. 44# 45# - features: enable the getting extension features in a 46# device. Similar to `properties`, this stores the features 47# struct inside `zink_device_info.{alias}_feats`. 48# 49# - conditions: criteria for enabling an extension. This is an array of strings, 50# where each string is a condition, and all conditions have to be true 51# for `zink_device_info.have_{name}` to be true. 52# 53# The code generator will replace "$feats" and "$props" with the 54# respective variables, e.g. "$feats.nullDescriptor" becomes 55# "info->rb2_feats.nullDescriptor" in the final code for VK_EXT_robustness2. 56# 57# When empty or None, the extension is enabled when the extensions 58# given by vkEnumerateDeviceExtensionProperties() include the extension. 59# 60# - guard: adds a #if defined(`extension_name`)/#endif guard around the code generated for this Extension. 61EXTENSIONS = [ 62 Extension("VK_KHR_maintenance1", 63 required=True), 64 Extension("VK_KHR_maintenance2"), 65 Extension("VK_KHR_maintenance3"), 66 Extension("VK_KHR_external_memory"), 67 Extension("VK_KHR_external_memory_fd"), 68 Extension("VK_KHR_vulkan_memory_model"), 69 Extension("VK_KHR_external_semaphore_fd"), 70 Extension("VK_KHR_create_renderpass2", required=True), 71 Extension("VK_KHR_synchronization2", 72 alias="sync2", 73 features=True), 74 Extension("VK_KHR_external_memory_win32"), 75 Extension("VK_KHR_external_semaphore_win32"), 76 Extension("VK_EXT_external_memory_dma_buf"), 77 Extension("VK_EXT_queue_family_foreign"), 78 Extension("VK_KHR_swapchain_mutable_format"), 79 Extension("VK_EXT_provoking_vertex", 80 alias="pv", 81 features=True, 82 properties=True, 83 conditions=["$feats.provokingVertexLast"]), 84 Extension("VK_EXT_shader_viewport_index_layer"), 85 Extension("VK_KHR_get_memory_requirements2"), 86 Extension("VK_EXT_post_depth_coverage"), 87 Extension("VK_EXT_depth_clip_control", alias="clip_control", features=True), 88 Extension("VK_EXT_shader_subgroup_ballot"), 89 Extension("VK_EXT_shader_subgroup_vote"), 90 Extension("VK_EXT_shader_atomic_float", alias="atomic_float", features=True), 91 Extension("VK_KHR_8bit_storage", 92 alias="storage_8bit", 93 features=True, 94 conditions=["$feats.storageBuffer8BitAccess"]), 95 Extension("VK_KHR_16bit_storage", 96 alias="storage_16bit", 97 features=True, 98 conditions=["$feats.storageBuffer16BitAccess"]), 99 Extension("VK_EXT_image_2d_view_of_3d", 100 alias="view2d", 101 features=True), 102 Extension("VK_KHR_driver_properties", 103 alias="driver", 104 properties=True), 105 Extension("VK_EXT_memory_budget"), 106 Extension("VK_KHR_draw_indirect_count"), 107 Extension("VK_EXT_fragment_shader_interlock", 108 alias="interlock", 109 features=True, 110 conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]), 111 Extension("VK_EXT_sample_locations", 112 alias="sample_locations", 113 properties=True), 114 Extension("VK_EXT_conservative_rasterization", 115 alias="cons_raster", 116 properties=True, 117 conditions=["$props.fullyCoveredFragmentShaderInputVariable"]), 118 Extension("VK_KHR_shader_draw_parameters"), 119 Extension("VK_KHR_sampler_mirror_clamp_to_edge"), 120 Extension("VK_EXT_conditional_rendering", 121 alias="cond_render", 122 features=True, 123 conditions=["$feats.conditionalRendering"]), 124 Extension("VK_EXT_transform_feedback", 125 alias="tf", 126 properties=True, 127 features=True, 128 conditions=["$feats.transformFeedback"]), 129 Extension("VK_EXT_index_type_uint8", 130 alias="index_uint8", 131 features=True, 132 conditions=["$feats.indexTypeUint8"]), 133 Extension("VK_KHR_image_format_list"), 134 Extension("VK_KHR_sampler_ycbcr_conversion"), 135 Extension("VK_KHR_imageless_framebuffer", 136 alias="imgless", 137 features=True, 138 required=True), 139 Extension("VK_EXT_robustness2", 140 alias="rb2", 141 properties=True, 142 features=True, 143 conditions=["$feats.nullDescriptor"]), 144 Extension("VK_EXT_image_drm_format_modifier"), 145 Extension("VK_EXT_vertex_attribute_divisor", 146 alias="vdiv", 147 properties=True, 148 features=True, 149 conditions=["$feats.vertexAttributeInstanceRateDivisor"]), 150 Extension("VK_EXT_calibrated_timestamps"), 151 Extension("VK_NV_linear_color_attachment", 152 alias="linear_color", 153 features=True), 154 Extension("VK_KHR_dynamic_rendering", 155 alias="dynamic_render", 156 features=True), 157 Extension("VK_KHR_shader_clock", 158 alias="shader_clock", 159 features=True, 160 conditions=["$feats.shaderSubgroupClock"]), 161 Extension("VK_EXT_sampler_filter_minmax", 162 alias="reduction", 163 properties=True, 164 conditions=["$props.filterMinmaxSingleComponentFormats"]), 165 Extension("VK_EXT_custom_border_color", 166 alias="border_color", 167 properties=True, 168 features=True, 169 conditions=["$feats.customBorderColors"]), 170 Extension("VK_EXT_non_seamless_cube_map", 171 alias="nonseamless", 172 features=True), 173 Extension("VK_EXT_border_color_swizzle", 174 alias="border_swizzle", 175 features=True), 176 Extension("VK_EXT_blend_operation_advanced", 177 alias="blend", 178 properties=True, 179 # TODO: we can probably support non-premul here with some work? 180 conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]), 181 Extension("VK_EXT_extended_dynamic_state", 182 alias="dynamic_state", 183 features=True, 184 conditions=["$feats.extendedDynamicState"]), 185 Extension("VK_EXT_extended_dynamic_state2", 186 alias="dynamic_state2", 187 features=True, 188 conditions=["$feats.extendedDynamicState2"]), 189 Extension("VK_EXT_pipeline_creation_cache_control", 190 alias="pipeline_cache_control", 191 features=True, 192 conditions=["$feats.pipelineCreationCacheControl"]), 193 Extension("VK_EXT_shader_stencil_export", 194 alias="stencil_export"), 195 Extension("VK_KHR_portability_subset", 196 alias="portability_subset", 197 features=True, 198 guard=True), 199 Extension("VK_KHR_timeline_semaphore", alias="timeline", features=True), 200 Extension("VK_EXT_color_write_enable", alias="cwrite", features=True), 201 Extension("VK_EXT_4444_formats", 202 alias="format_4444", 203 features=True), 204 Extension("VK_EXT_scalar_block_layout", 205 alias="scalar_block_layout", 206 features=True, 207 conditions=["$feats.scalarBlockLayout"]), 208 Extension("VK_KHR_swapchain"), 209 Extension("VK_KHR_shader_float16_int8", 210 alias="shader_float16_int8", 211 features=True), 212 Extension("VK_EXT_multi_draw", 213 alias="multidraw", 214 features=True, 215 properties=True, 216 conditions=["$feats.multiDraw"]), 217 Extension("VK_EXT_primitives_generated_query", 218 alias="primgen", 219 features=True), 220 Extension("VK_KHR_push_descriptor", 221 alias="push", 222 properties=True), 223 Extension("VK_KHR_descriptor_update_template", 224 alias="template"), 225 Extension("VK_EXT_line_rasterization", 226 alias="line_rast", 227 properties=True, 228 features=True), 229 Extension("VK_EXT_vertex_input_dynamic_state", 230 alias="vertex_input", 231 features=True, 232 conditions=["$feats.vertexInputDynamicState"]), 233 Extension("VK_EXT_primitive_topology_list_restart", 234 alias="list_restart", 235 features=True, 236 conditions=["$feats.primitiveTopologyListRestart"]), 237 Extension("VK_KHR_dedicated_allocation", 238 alias="dedicated"), 239 Extension("VK_EXT_descriptor_indexing", 240 alias="desc_indexing", 241 features=True, 242 properties=True, 243 conditions=["$feats.descriptorBindingPartiallyBound"]), 244 Extension("VK_EXT_depth_clip_enable", 245 alias="depth_clip_enable", 246 features=True), 247] 248 249# constructor: Versions(device_version(major, minor, patch), struct_version(major, minor)) 250# The attributes: 251# - device_version: Vulkan version, as tuple, to use with 252# VK_MAKE_VERSION(version_major, version_minor, version_patch) 253# 254# - struct_version: Vulkan version, as tuple, to use with structures and macros 255VERSIONS = [ 256 Version((1,1,0), (1,1)), 257 Version((1,2,0), (1,2)), 258] 259 260# There exists some inconsistencies regarding the enum constants, fix them. 261# This is basically generated_code.replace(key, value). 262REPLACEMENTS = { 263 "PROPERTIES_PROPERTIES": "PROPERTIES", 264} 265 266 267# This template provides helper functions for the other templates. 268# Right now, the following functions are defined: 269# - guard(ext) : surrounds the body with an if-def guard according to 270# `ext.extension_name()` if `ext.guard` is True. 271include_template = """ 272<%def name="guard_(ext, body)"> 273%if ext.guard: 274#ifdef ${ext.extension_name()} 275%endif 276 ${capture(body)|trim} 277%if ext.guard: 278#endif 279%endif 280</%def> 281 282## This ugliness is here to prevent mako from adding tons of excessive whitespace 283<%def name="guard(ext)">${capture(guard_, ext, body=caller.body).strip('\\r\\n')}</%def> 284""" 285 286header_code = """ 287<%namespace name="helpers" file="helpers"/> 288 289#ifndef ZINK_DEVICE_INFO_H 290#define ZINK_DEVICE_INFO_H 291 292#include "util/u_memory.h" 293 294#include <vulkan/vulkan.h> 295 296struct zink_screen; 297 298struct zink_device_info { 299 uint32_t device_version; 300 301%for ext in extensions: 302<%helpers:guard ext="${ext}"> 303 bool have_${ext.name_with_vendor()}; 304</%helpers:guard> 305%endfor 306%for version in versions: 307 bool have_vulkan${version.struct()}; 308%endfor 309 310 VkPhysicalDeviceFeatures2 feats; 311 VkPhysicalDeviceSubgroupProperties subgroup; 312%for version in versions: 313 VkPhysicalDeviceVulkan${version.struct()}Features feats${version.struct()}; 314%endfor 315 316 VkPhysicalDeviceProperties props; 317%for version in versions: 318 VkPhysicalDeviceVulkan${version.struct()}Properties props${version.struct()}; 319%endfor 320 321 VkPhysicalDeviceMemoryProperties mem_props; 322 VkPhysicalDeviceIDProperties deviceid_props; 323 324%for ext in extensions: 325<%helpers:guard ext="${ext}"> 326%if ext.has_features: 327 ${ext.physical_device_struct("Features")} ${ext.field("feats")}; 328%endif 329%if ext.has_properties: 330 ${ext.physical_device_struct("Properties")} ${ext.field("props")}; 331%endif 332</%helpers:guard> 333%endfor 334 335 const char *extensions[${len(extensions)}]; 336 uint32_t num_extensions; 337}; 338 339bool 340zink_get_physical_device_info(struct zink_screen *screen); 341 342void 343zink_verify_device_extensions(struct zink_screen *screen); 344 345/* stub functions that get inserted into the dispatch table if they are not 346 * properly loaded. 347 */ 348%for ext in extensions: 349%if registry.in_registry(ext.name): 350%for cmd in registry.get_registry_entry(ext.name).device_commands: 351void zink_stub_${cmd.lstrip("vk")}(void); 352%endfor 353%endif 354%endfor 355 356#endif 357""" 358 359 360impl_code = """ 361<%namespace name="helpers" file="helpers"/> 362 363#include "vk_enum_to_str.h" 364#include "zink_device_info.h" 365#include "zink_screen.h" 366 367bool 368zink_get_physical_device_info(struct zink_screen *screen) 369{ 370 struct zink_device_info *info = &screen->info; 371%for ext in extensions: 372<%helpers:guard ext="${ext}"> 373 bool support_${ext.name_with_vendor()} = false; 374</%helpers:guard> 375%endfor 376 uint32_t num_extensions = 0; 377 378 // get device memory properties 379 screen->vk.GetPhysicalDeviceMemoryProperties(screen->pdev, &info->mem_props); 380 381 // enumerate device supported extensions 382 VkResult result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, NULL); 383 if (result != VK_SUCCESS) { 384 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 385 } else { 386 if (num_extensions > 0) { 387 VkExtensionProperties *extensions = MALLOC(sizeof(VkExtensionProperties) * num_extensions); 388 if (!extensions) goto fail; 389 result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, extensions); 390 if (result != VK_SUCCESS) { 391 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 392 } 393 394 for (uint32_t i = 0; i < num_extensions; ++i) { 395 %for ext in extensions: 396 <%helpers:guard ext="${ext}"> 397 if (!strcmp(extensions[i].extensionName, "${ext.name}")) { 398 %if not (ext.has_features or ext.has_properties): 399 info->have_${ext.name_with_vendor()} = true; 400 %else: 401 support_${ext.name_with_vendor()} = true; 402 %endif 403 } 404 </%helpers:guard> 405 %endfor 406 } 407 408 FREE(extensions); 409 } 410 } 411 412 // get device features 413 if (screen->vk.GetPhysicalDeviceFeatures2) { 414 // check for device extension features 415 info->feats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 416 417%for version in versions: 418%if version.device_version < (1,2,0): 419 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 420 /* VkPhysicalDeviceVulkan11Features was added in 1.2, not 1.1 as one would think */ 421%else: 422 if (${version.version()} <= screen->vk_version) { 423%endif 424 info->feats${version.struct()}.sType = ${version.stype("FEATURES")}; 425 info->feats${version.struct()}.pNext = info->feats.pNext; 426 info->feats.pNext = &info->feats${version.struct()}; 427 info->have_vulkan${version.struct()} = true; 428 } 429%endfor 430 431%for ext in extensions: 432%if ext.has_features: 433<%helpers:guard ext="${ext}"> 434%if ext.features_promoted: 435 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 436%else: 437 if (support_${ext.name_with_vendor()}) { 438%endif 439 info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")}; 440 info->${ext.field("feats")}.pNext = info->feats.pNext; 441 info->feats.pNext = &info->${ext.field("feats")}; 442 } 443</%helpers:guard> 444%endif 445%endfor 446 447 screen->vk.GetPhysicalDeviceFeatures2(screen->pdev, &info->feats); 448 } else { 449 screen->vk.GetPhysicalDeviceFeatures(screen->pdev, &info->feats.features); 450 } 451 452 // check for device properties 453 if (screen->vk.GetPhysicalDeviceProperties2) { 454 VkPhysicalDeviceProperties2 props = {0}; 455 props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 456 457%for version in versions: 458%if version.device_version < (1,2,0): 459 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 460 /* VkPhysicalDeviceVulkan11Properties was added in 1.2, not 1.1 as one would think */ 461%else: 462 if (${version.version()} <= screen->vk_version) { 463%endif 464 info->props${version.struct()}.sType = ${version.stype("PROPERTIES")}; 465 info->props${version.struct()}.pNext = props.pNext; 466 props.pNext = &info->props${version.struct()}; 467 } 468%endfor 469 470%for ext in extensions: 471%if ext.has_properties: 472<%helpers:guard ext="${ext}"> 473%if ext.properties_promoted: 474 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 475%else: 476 if (support_${ext.name_with_vendor()}) { 477%endif 478 info->${ext.field("props")}.sType = ${ext.stype("PROPERTIES")}; 479 info->${ext.field("props")}.pNext = props.pNext; 480 props.pNext = &info->${ext.field("props")}; 481 } 482</%helpers:guard> 483%endif 484%endfor 485 486 if (screen->vk_version < VK_MAKE_VERSION(1,2,0) && screen->instance_info.have_KHR_external_memory_capabilities) { 487 info->deviceid_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; 488 info->deviceid_props.pNext = props.pNext; 489 props.pNext = &info->deviceid_props; 490 } 491 492 if (screen->vk_version >= VK_MAKE_VERSION(1,1,0)) { 493 info->subgroup.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; 494 info->subgroup.pNext = props.pNext; 495 props.pNext = &info->subgroup; 496 } 497 498 // note: setting up local VkPhysicalDeviceProperties2. 499 screen->vk.GetPhysicalDeviceProperties2(screen->pdev, &props); 500 } 501 502 /* We re-apply the fields from VkPhysicalDeviceVulkanXYFeatures struct 503 * onto their respective fields in the VkPhysicalDeviceExtensionNameFeatures 504 * struct if the former is provided by the VK implementation. 505 * 506 * As for why this is done: the spec mentions that once an extension is 507 * promoted to core and its feature fields are added in VulkanXYFeatures, 508 * including both ExtensionNameFeatures and VulkanXYFeatures at the same 509 * time is prohibited when using vkGetPhysicalDeviceFeatures2. 510 */ 511%for ext in extensions: 512%if ext.features_promoted: 513 if (info->have_vulkan${ext.core_since.struct()}) { 514 %for field in registry.get_registry_entry(ext.name).features_fields: 515 info->${ext.field("feats")}.${field} = info->feats${ext.core_since.struct()}.${field}; 516 %endfor 517 } 518%endif 519%endfor 520 521 /* See above, but for VulkanXYProperties. 522 * Unlike VulkanXYFeatures with all the booleans, VulkanXYProperties can 523 * contain different types of data, including arrays. The C language hates us 524 * when we assign an array to another array, therefore we use an memcpy here. 525 */ 526%for ext in extensions: 527%if ext.properties_promoted: 528 if (info->have_vulkan${ext.core_since.struct()}) { 529 %for field in registry.get_registry_entry(ext.name).properties_fields: 530 memcpy(&info->${ext.field("props")}.${field}, 531 &info->props${ext.core_since.struct()}.${field}, 532 sizeof(info->${ext.field("props")}.${field})); 533 %endfor 534 } 535%endif 536%endfor 537 538 // enable the extensions if they match the conditions given by ext.enable_conds 539 if (screen->vk.GetPhysicalDeviceProperties2) { 540 %for ext in extensions: 541<%helpers:guard ext="${ext}"> 542<% 543 conditions = "" 544 if ext.enable_conds: 545 for cond in ext.enable_conds: 546 cond = cond.replace("$feats", "info->" + ext.field("feats")) 547 cond = cond.replace("$props", "info->" + ext.field("props")) 548 conditions += "&& (" + cond + ")\\n" 549 conditions = conditions.strip() 550%>\ 551 info->have_${ext.name_with_vendor()} |= support_${ext.name_with_vendor()} 552 ${conditions}; 553</%helpers:guard> 554 %endfor 555 } 556 557 // generate extension list 558 num_extensions = 0; 559 560%for ext in extensions: 561<%helpers:guard ext="${ext}"> 562 if (info->have_${ext.name_with_vendor()}) { 563 info->extensions[num_extensions++] = "${ext.name}"; 564%if ext.is_required: 565 } else { 566 debug_printf("ZINK: ${ext.name} required!\\n"); 567 goto fail; 568%endif 569 } 570</%helpers:guard> 571%endfor 572 573 info->num_extensions = num_extensions; 574 575 return true; 576 577fail: 578 return false; 579} 580 581void 582zink_verify_device_extensions(struct zink_screen *screen) 583{ 584%for ext in extensions: 585%if registry.in_registry(ext.name): 586<%helpers:guard ext="${ext}"> 587 if (screen->info.have_${ext.name_with_vendor()}) { 588%for cmd in registry.get_registry_entry(ext.name).device_commands: 589%if cmd.find("win32"): 590#ifdef _WIN32 591%endif 592 if (!screen->vk.${cmd.lstrip("vk")}) { 593#ifndef NDEBUG 594 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")}; 595#else 596 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded; 597#endif 598 } 599%if cmd.find("win32"): 600#endif 601%endif 602%endfor 603 } 604</%helpers:guard> 605%endif 606%endfor 607} 608 609#ifndef NDEBUG 610/* generated stub functions */ 611## remember the stub functions that are already generated 612<% generated_funcs = set() %> 613 614%for ext in extensions: 615%if registry.in_registry(ext.name): 616%for cmd in registry.get_registry_entry(ext.name).device_commands: 617## 618## some functions are added by multiple extensions, which creates duplication 619## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR) 620## 621%if cmd in generated_funcs: 622 <% continue %> 623%else: 624 <% generated_funcs.add(cmd) %> 625%endif 626void 627zink_stub_${cmd.lstrip("vk")}() 628{ 629 mesa_loge("ZINK: ${cmd} is not loaded properly!"); 630 abort(); 631} 632%endfor 633%endif 634%endfor 635#endif 636""" 637 638 639def replace_code(code: str, replacement: dict): 640 for (k, v) in replacement.items(): 641 code = code.replace(k, v) 642 643 return code 644 645 646if __name__ == "__main__": 647 try: 648 header_path = sys.argv[1] 649 impl_path = sys.argv[2] 650 vkxml_path = sys.argv[3] 651 652 header_path = path.abspath(header_path) 653 impl_path = path.abspath(impl_path) 654 vkxml_path = path.abspath(vkxml_path) 655 except: 656 print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0]) 657 exit(1) 658 659 registry = ExtensionRegistry(vkxml_path) 660 661 extensions = EXTENSIONS 662 versions = VERSIONS 663 replacement = REPLACEMENTS 664 665 # Perform extension validation and set core_since for the extension if available 666 error_count = 0 667 for ext in extensions: 668 if not registry.in_registry(ext.name): 669 # disable validation for nonstandard extensions 670 if ext.is_nonstandard: 671 continue 672 673 error_count += 1 674 print("The extension {} is not registered in vk.xml - a typo?".format(ext.name)) 675 continue 676 677 entry = registry.get_registry_entry(ext.name) 678 679 if entry.ext_type != "device": 680 error_count += 1 681 print("The extension {} is {} extension - expected a device extension.".format(ext.name, entry.ext_type)) 682 continue 683 684 if ext.has_features: 685 if not (entry.features_struct and ext.physical_device_struct("Features") == entry.features_struct): 686 error_count += 1 687 print("The extension {} does not provide a features struct.".format(ext.name)) 688 ext.features_promoted = entry.features_promoted 689 690 if ext.has_properties: 691 if not (entry.properties_struct and ext.physical_device_struct("Properties") == entry.properties_struct): 692 error_count += 1 693 print("The extension {} does not provide a properties struct.".format(ext.name)) 694 ext.properties_promoted = entry.properties_promoted 695 696 if entry.promoted_in and entry.promoted_in <= versions[-1].struct_version: 697 ext.core_since = Version((*entry.promoted_in, 0)) 698 else: 699 # even if the ext is promoted in a newer VK version, consider it 700 # unpromoted until there's an entry for that VK version in VERSIONS 701 ext.features_promoted = False 702 ext.properties_promoted = False 703 704 if error_count > 0: 705 print("zink_device_info.py: Found {} error(s) in total. Quitting.".format(error_count)) 706 exit(1) 707 708 lookup = TemplateLookup() 709 lookup.put_string("helpers", include_template) 710 711 with open(header_path, "w") as header_file: 712 header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 713 header = replace_code(header, replacement) 714 print(header, file=header_file) 715 716 with open(impl_path, "w") as impl_file: 717 impl = Template(impl_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 718 impl = replace_code(impl, replacement) 719 print(impl, file=impl_file) 720