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_maintenance4", 67 alias="maint4", 68 features=True), 69 Extension("VK_KHR_maintenance5", 70 alias="maint5", 71 features=True, properties=True), 72 Extension("VK_KHR_maintenance6", 73 alias="maint6", 74 features=True, properties=True), 75 Extension("VK_KHR_external_memory"), 76 Extension("VK_KHR_external_memory_fd"), 77 Extension("VK_KHR_vulkan_memory_model"), 78 Extension("VK_KHR_workgroup_memory_explicit_layout", alias="explicit_layout", features=True), 79 Extension("VK_KHR_pipeline_executable_properties", 80 alias="pipestats", 81 features=True), 82 Extension("VK_KHR_external_semaphore_fd"), 83 Extension("VK_KHR_create_renderpass2", 84 required=True), 85 Extension("VK_KHR_synchronization2", 86 alias="sync2", 87 features=True), 88 Extension("VK_KHR_external_memory_win32"), 89 Extension("VK_KHR_external_semaphore_win32"), 90 Extension("VK_EXT_external_memory_dma_buf"), 91 Extension("VK_KHR_buffer_device_address", 92 alias="bda", 93 features=True), 94 Extension("VK_EXT_external_memory_host", alias="ext_host_mem", properties=True), 95 Extension("VK_EXT_queue_family_foreign"), 96 Extension("VK_KHR_swapchain_mutable_format"), 97 Extension("VK_EXT_provoking_vertex", 98 alias="pv", 99 features=True, 100 properties=True, 101 conditions=["$feats.provokingVertexLast"]), 102 Extension("VK_EXT_shader_viewport_index_layer"), 103 Extension("VK_KHR_get_memory_requirements2"), 104 Extension("VK_EXT_post_depth_coverage"), 105 Extension("VK_EXT_depth_clip_control", 106 alias="clip_control", 107 features=True), 108 Extension("VK_EXT_depth_clamp_zero_one", 109 alias="clamp_01", 110 features=True), 111 Extension("VK_EXT_shader_subgroup_ballot"), 112 Extension("VK_EXT_shader_subgroup_vote"), 113 Extension("VK_EXT_shader_atomic_float", 114 alias="atomic_float", 115 features=True), 116 Extension("VK_KHR_shader_atomic_int64", 117 alias="atomic_int", 118 features=True), 119 Extension("VK_KHR_8bit_storage", 120 alias="storage_8bit", 121 features=True, 122 conditions=["$feats.storageBuffer8BitAccess"]), 123 Extension("VK_KHR_16bit_storage", 124 alias="storage_16bit", 125 features=True, 126 conditions=["$feats.storageBuffer16BitAccess"]), 127 Extension("VK_EXT_image_2d_view_of_3d", 128 alias="view2d", 129 features=True), 130 Extension("VK_KHR_driver_properties", 131 alias="driver", 132 properties=True), 133 Extension("VK_EXT_memory_budget"), 134 Extension("VK_EXT_memory_priority", alias="memprio", features=True), 135 Extension("VK_EXT_pageable_device_local_memory", alias="mempage", features=True), 136 Extension("VK_KHR_draw_indirect_count"), 137 Extension("VK_EXT_dynamic_rendering_unused_attachments", alias="unused", features=True), 138 Extension("VK_EXT_shader_object", alias="shobj", features=True, properties=True), 139 Extension("VK_EXT_attachment_feedback_loop_layout", 140 alias="feedback_loop", 141 features=True), 142 Extension("VK_EXT_attachment_feedback_loop_dynamic_state", alias="feedback_dyn", features=True), 143 Extension("VK_NV_device_generated_commands", alias="nv_dgc", features=True, properties=True), 144 Extension("VK_EXT_fragment_shader_interlock", 145 alias="interlock", 146 features=True, 147 conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]), 148 Extension("VK_EXT_sample_locations", 149 alias="sample_locations", 150 properties=True), 151 Extension("VK_EXT_conservative_rasterization", 152 alias="cons_raster", 153 properties=True, 154 conditions=["$props.fullyCoveredFragmentShaderInputVariable"]), 155 Extension("VK_KHR_shader_draw_parameters"), 156 Extension("VK_KHR_sampler_mirror_clamp_to_edge"), 157 Extension("VK_EXT_descriptor_buffer", alias="db", features=True, properties=True), 158 Extension("VK_EXT_conditional_rendering", 159 alias="cond_render", 160 features=True, 161 conditions=["$feats.conditionalRendering"]), 162 Extension("VK_EXT_transform_feedback", 163 alias="tf", 164 properties=True, 165 features=True, 166 conditions=["$feats.transformFeedback"]), 167 Extension("VK_EXT_index_type_uint8", 168 alias="index_uint8", 169 features=True, 170 conditions=["$feats.indexTypeUint8"]), 171 Extension("VK_KHR_image_format_list"), 172 Extension("VK_KHR_sampler_ycbcr_conversion"), 173 Extension("VK_KHR_imageless_framebuffer", 174 alias="imgless", 175 features=True, 176 required=True), 177 Extension("VK_EXT_robustness2", 178 alias="rb2", 179 properties=True, 180 features=True, 181 conditions=["$feats.nullDescriptor"]), 182 Extension("VK_EXT_image_robustness", 183 alias="rb_image", 184 features=True), 185 Extension("VK_EXT_image_drm_format_modifier"), 186 Extension("VK_EXT_vertex_attribute_divisor", 187 alias="vdiv", 188 properties=True, 189 features=True, 190 conditions=["$feats.vertexAttributeInstanceRateDivisor"]), 191 Extension("VK_EXT_calibrated_timestamps"), 192 Extension("VK_NV_linear_color_attachment", 193 alias="linear_color", 194 features=True), 195 Extension("VK_KHR_dynamic_rendering", 196 alias="dynamic_render", 197 features=True), 198 Extension("VK_KHR_dynamic_rendering_local_read", 199 alias="drlr", 200 features=True), 201 Extension("VK_EXT_multisampled_render_to_single_sampled", 202 alias="msrtss", 203 features=True), 204 Extension("VK_KHR_shader_clock", 205 alias="shader_clock", 206 features=True, 207 conditions=["$feats.shaderSubgroupClock"]), 208 Extension("VK_INTEL_shader_integer_functions2", 209 alias="shader_int_fns2", 210 features=True, 211 conditions=["$feats.shaderIntegerFunctions2"]), 212 Extension("VK_EXT_sampler_filter_minmax", 213 alias="reduction", 214 properties=True, 215 conditions=["$props.filterMinmaxSingleComponentFormats"]), 216 Extension("VK_EXT_custom_border_color", 217 alias="border_color", 218 properties=True, 219 features=True, 220 conditions=["$feats.customBorderColors"]), 221 Extension("VK_EXT_non_seamless_cube_map", 222 alias="nonseamless", 223 features=True), 224 Extension("VK_EXT_border_color_swizzle", 225 alias="border_swizzle", 226 features=True), 227 Extension("VK_EXT_blend_operation_advanced", 228 alias="blend", 229 properties=True, 230 # TODO: we can probably support non-premul here with some work? 231 conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]), 232 Extension("VK_EXT_extended_dynamic_state", 233 alias="dynamic_state", 234 features=True, 235 conditions=["$feats.extendedDynamicState"]), 236 Extension("VK_EXT_extended_dynamic_state2", 237 alias="dynamic_state2", 238 features=True, 239 conditions=["$feats.extendedDynamicState2"]), 240 Extension("VK_EXT_extended_dynamic_state3", 241 alias="dynamic_state3", 242 properties=True, 243 features=True), 244 Extension("VK_EXT_pipeline_creation_cache_control", 245 alias="pipeline_cache_control", 246 features=True, 247 conditions=["$feats.pipelineCreationCacheControl"]), 248 Extension("VK_EXT_shader_stencil_export", 249 alias="stencil_export"), 250 Extension("VK_KHR_portability_subset", 251 alias="portability_subset", 252 features=True, 253 guard=True), 254 Extension("VK_NV_compute_shader_derivatives", 255 alias="shader_derivs", 256 features=True, 257 conditions=["$feats.computeDerivativeGroupQuads", "$feats.computeDerivativeGroupLinear"]), 258 Extension("VK_KHR_timeline_semaphore", 259 alias="timeline", 260 features=True), 261 Extension("VK_EXT_color_write_enable", 262 alias="cwrite", 263 features=True), 264 Extension("VK_EXT_4444_formats", 265 alias="format_4444", 266 features=True), 267 Extension("VK_EXT_host_image_copy", 268 alias="hic", 269 features=True, 270 properties=True), 271 Extension("VK_EXT_scalar_block_layout", 272 alias="scalar_block_layout", 273 features=True, 274 conditions=["$feats.scalarBlockLayout"]), 275 Extension("VK_KHR_swapchain"), 276 Extension("VK_EXT_rasterization_order_attachment_access", 277 alias="rast_order_access", 278 features=True, 279 conditions=["$feats.rasterizationOrderColorAttachmentAccess"]), 280 Extension("VK_KHR_shader_float16_int8", 281 alias="shader_float16_int8", 282 features=True), 283 Extension("VK_EXT_multi_draw", 284 alias="multidraw", 285 features=True, 286 properties=True, 287 conditions=["$feats.multiDraw"]), 288 Extension("VK_EXT_primitives_generated_query", 289 alias="primgen", 290 features=True), 291 Extension("VK_KHR_pipeline_library"), 292 Extension("VK_EXT_graphics_pipeline_library", 293 alias="gpl", 294 features=True, 295 properties=True), 296 Extension("VK_KHR_push_descriptor", 297 alias="push", 298 properties=True), 299 Extension("VK_KHR_descriptor_update_template", 300 alias="template", required=True), 301 Extension("VK_EXT_line_rasterization", 302 alias="line_rast", 303 properties=True, 304 features=True), 305 Extension("VK_EXT_vertex_input_dynamic_state", 306 alias="vertex_input", 307 features=True, 308 conditions=["$feats.vertexInputDynamicState"]), 309 Extension("VK_EXT_primitive_topology_list_restart", 310 alias="list_restart", 311 features=True, 312 conditions=["$feats.primitiveTopologyListRestart"]), 313 Extension("VK_KHR_dedicated_allocation", 314 alias="dedicated"), 315 Extension("VK_EXT_descriptor_indexing", 316 alias="desc_indexing", 317 features=True, 318 properties=True, 319 conditions=["$feats.descriptorBindingPartiallyBound"]), 320 Extension("VK_EXT_depth_clip_enable", 321 alias="depth_clip_enable", 322 features=True), 323 Extension("VK_EXT_shader_demote_to_helper_invocation", 324 alias="demote", 325 features=True, 326 conditions=["$feats.shaderDemoteToHelperInvocation"]), 327 Extension("VK_KHR_shader_float_controls", 328 alias="float_controls") 329] 330 331# constructor: Versions(device_version(major, minor, patch), struct_version(major, minor)) 332# The attributes: 333# - device_version: Vulkan version, as tuple, to use with 334# VK_MAKE_VERSION(version_major, version_minor, version_patch) 335# 336# - struct_version: Vulkan version, as tuple, to use with structures and macros 337VERSIONS = [ 338 Version((1,1,0), (1,1)), 339 Version((1,2,0), (1,2)), 340 Version((1,3,0), (1,3)), 341] 342 343# There exists some inconsistencies regarding the enum constants, fix them. 344# This is basically generated_code.replace(key, value). 345REPLACEMENTS = { 346 "PROPERTIES_PROPERTIES": "PROPERTIES", 347} 348 349 350# This template provides helper functions for the other templates. 351# Right now, the following functions are defined: 352# - guard(ext) : surrounds the body with an if-def guard according to 353# `ext.extension_name()` if `ext.guard` is True. 354include_template = """ 355<%def name="guard_(ext, body)"> 356%if ext.guard: 357#ifdef ${ext.extension_name()} 358%endif 359 ${capture(body)|trim} 360%if ext.guard: 361#endif 362%endif 363</%def> 364 365## This ugliness is here to prevent mako from adding tons of excessive whitespace 366<%def name="guard(ext)">${capture(guard_, ext, body=caller.body).strip('\\r\\n')}</%def> 367""" 368 369header_code = """ 370<%namespace name="helpers" file="helpers"/> 371 372#ifndef ZINK_DEVICE_INFO_H 373#define ZINK_DEVICE_INFO_H 374 375#include "util/u_memory.h" 376 377#include <vulkan/vulkan_core.h> 378 379#ifdef VK_ENABLE_BETA_EXTENSIONS 380#include <vulkan/vulkan_beta.h> 381#endif 382 383#ifdef _WIN32 384#include <windows.h> 385#include <vulkan/vulkan_win32.h> 386#endif 387 388struct zink_screen; 389 390struct zink_device_info { 391 uint32_t device_version; 392 393%for ext in extensions: 394<%helpers:guard ext="${ext}"> 395 bool have_${ext.name_with_vendor()}; 396</%helpers:guard> 397%endfor 398%for version in versions: 399 bool have_vulkan${version.struct()}; 400%endfor 401 402 VkPhysicalDeviceFeatures2 feats; 403 VkPhysicalDeviceSubgroupProperties subgroup; 404%for version in versions: 405 VkPhysicalDeviceVulkan${version.struct()}Features feats${version.struct()}; 406%endfor 407 408 VkPhysicalDeviceProperties props; 409%for version in versions: 410 VkPhysicalDeviceVulkan${version.struct()}Properties props${version.struct()}; 411%endfor 412 413 VkPhysicalDeviceMemoryProperties mem_props; 414 VkPhysicalDeviceIDProperties deviceid_props; 415 416%for ext in extensions: 417<%helpers:guard ext="${ext}"> 418%if ext.has_features: 419 ${ext.physical_device_struct("Features")} ${ext.field("feats")}; 420%endif 421%if ext.has_properties: 422 ${ext.physical_device_struct("Properties")} ${ext.field("props")}; 423%endif 424</%helpers:guard> 425%endfor 426 427 const char *extensions[${len(extensions)}]; 428 uint32_t num_extensions; 429}; 430 431bool 432zink_get_physical_device_info(struct zink_screen *screen); 433 434void 435zink_verify_device_extensions(struct zink_screen *screen); 436 437/* stub functions that get inserted into the dispatch table if they are not 438 * properly loaded. 439 */ 440%for ext in extensions: 441%if registry.in_registry(ext.name): 442%for cmd in registry.get_registry_entry(ext.name).device_commands: 443void zink_stub_${cmd.lstrip("vk")}(void); 444%endfor 445%endif 446%endfor 447 448#endif 449""" 450 451 452impl_code = """ 453<%namespace name="helpers" file="helpers"/> 454 455#include "vk_enum_to_str.h" 456#include "zink_device_info.h" 457#include "zink_screen.h" 458 459bool 460zink_get_physical_device_info(struct zink_screen *screen) 461{ 462 struct zink_device_info *info = &screen->info; 463%for ext in extensions: 464<%helpers:guard ext="${ext}"> 465 bool support_${ext.name_with_vendor()} = false; 466</%helpers:guard> 467%endfor 468 uint32_t num_extensions = 0; 469 470 // get device memory properties 471 screen->vk.GetPhysicalDeviceMemoryProperties(screen->pdev, &info->mem_props); 472 473 // enumerate device supported extensions 474 VkResult result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, NULL); 475 if (result != VK_SUCCESS) { 476 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 477 } else { 478 if (num_extensions > 0) { 479 VkExtensionProperties *extensions = MALLOC(sizeof(VkExtensionProperties) * num_extensions); 480 if (!extensions) goto fail; 481 result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, extensions); 482 if (result != VK_SUCCESS) { 483 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 484 } 485 486 for (uint32_t i = 0; i < num_extensions; ++i) { 487 %for ext in extensions: 488 <%helpers:guard ext="${ext}"> 489 if (!strcmp(extensions[i].extensionName, "${ext.name}")) { 490 %if not (ext.has_features or ext.has_properties): 491 info->have_${ext.name_with_vendor()} = true; 492 %else: 493 support_${ext.name_with_vendor()} = true; 494 %endif 495 } 496 </%helpers:guard> 497 %endfor 498 } 499 500 FREE(extensions); 501 } 502 } 503 504 // get device features 505 if (screen->vk.GetPhysicalDeviceFeatures2) { 506 // check for device extension features 507 info->feats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 508 509%for version in versions: 510%if version.device_version < (1,2,0): 511 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 512 /* VkPhysicalDeviceVulkan11Features was added in 1.2, not 1.1 as one would think */ 513%else: 514 if (${version.version()} <= screen->vk_version) { 515%endif 516 info->feats${version.struct()}.sType = ${version.stype("FEATURES")}; 517 info->feats${version.struct()}.pNext = info->feats.pNext; 518 info->feats.pNext = &info->feats${version.struct()}; 519 info->have_vulkan${version.struct()} = true; 520 } 521%endfor 522 523%for ext in extensions: 524%if ext.has_features: 525<%helpers:guard ext="${ext}"> 526%if ext.features_promoted: 527 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 528%else: 529 if (support_${ext.name_with_vendor()}) { 530%endif 531 info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")}; 532 info->${ext.field("feats")}.pNext = info->feats.pNext; 533 info->feats.pNext = &info->${ext.field("feats")}; 534 } 535</%helpers:guard> 536%endif 537%endfor 538 539 screen->vk.GetPhysicalDeviceFeatures2(screen->pdev, &info->feats); 540 } else { 541 screen->vk.GetPhysicalDeviceFeatures(screen->pdev, &info->feats.features); 542 } 543 544 // check for device properties 545 if (screen->vk.GetPhysicalDeviceProperties2) { 546 VkPhysicalDeviceProperties2 props = {0}; 547 props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 548 549%for version in versions: 550%if version.device_version < (1,2,0): 551 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 552 /* VkPhysicalDeviceVulkan11Properties was added in 1.2, not 1.1 as one would think */ 553%else: 554 if (${version.version()} <= screen->vk_version) { 555%endif 556 info->props${version.struct()}.sType = ${version.stype("PROPERTIES")}; 557 info->props${version.struct()}.pNext = props.pNext; 558 props.pNext = &info->props${version.struct()}; 559 } 560%endfor 561 562%for ext in extensions: 563%if ext.has_properties: 564<%helpers:guard ext="${ext}"> 565%if ext.properties_promoted: 566 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 567%else: 568 if (support_${ext.name_with_vendor()}) { 569%endif 570 info->${ext.field("props")}.sType = ${ext.stype("PROPERTIES")}; 571 info->${ext.field("props")}.pNext = props.pNext; 572 props.pNext = &info->${ext.field("props")}; 573 } 574</%helpers:guard> 575%endif 576%endfor 577 578 if (screen->vk_version < VK_MAKE_VERSION(1,2,0) && screen->instance_info.have_KHR_external_memory_capabilities) { 579 info->deviceid_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; 580 info->deviceid_props.pNext = props.pNext; 581 props.pNext = &info->deviceid_props; 582 } 583 584 if (screen->vk_version >= VK_MAKE_VERSION(1,1,0)) { 585 info->subgroup.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; 586 info->subgroup.pNext = props.pNext; 587 props.pNext = &info->subgroup; 588 } 589 590 // note: setting up local VkPhysicalDeviceProperties2. 591 screen->vk.GetPhysicalDeviceProperties2(screen->pdev, &props); 592 } 593 594 /* We re-apply the fields from VkPhysicalDeviceVulkanXYFeatures struct 595 * onto their respective fields in the VkPhysicalDeviceExtensionNameFeatures 596 * struct if the former is provided by the VK implementation. 597 * 598 * As for why this is done: the spec mentions that once an extension is 599 * promoted to core and its feature fields are added in VulkanXYFeatures, 600 * including both ExtensionNameFeatures and VulkanXYFeatures at the same 601 * time is prohibited when using vkGetPhysicalDeviceFeatures2. 602 */ 603%for ext in extensions: 604%if ext.features_promoted: 605 if (info->have_vulkan${ext.core_since.struct()}) { 606 %for field in registry.get_registry_entry(ext.name).features_fields: 607 info->${ext.field("feats")}.${field} = info->feats${ext.core_since.struct()}.${field}; 608 %endfor 609 } 610%endif 611%endfor 612 613 /* See above, but for VulkanXYProperties. 614 * Unlike VulkanXYFeatures with all the booleans, VulkanXYProperties can 615 * contain different types of data, including arrays. The C language hates us 616 * when we assign an array to another array, therefore we use an memcpy here. 617 */ 618%for ext in extensions: 619%if ext.properties_promoted: 620 if (info->have_vulkan${ext.core_since.struct()}) { 621 %for field in registry.get_registry_entry(ext.name).properties_fields: 622 memcpy(&info->${ext.field("props")}.${field}, 623 &info->props${ext.core_since.struct()}.${field}, 624 sizeof(info->${ext.field("props")}.${field})); 625 %endfor 626 } 627%endif 628%endfor 629 630 // enable the extensions if they match the conditions given by ext.enable_conds 631 if (screen->vk.GetPhysicalDeviceProperties2) { 632 %for ext in extensions: 633<%helpers:guard ext="${ext}"> 634<% 635 conditions = "" 636 if ext.enable_conds: 637 for cond in ext.enable_conds: 638 cond = cond.replace("$feats", "info->" + ext.field("feats")) 639 cond = cond.replace("$props", "info->" + ext.field("props")) 640 conditions += "&& (" + cond + ")\\n" 641 conditions = conditions.strip() 642%>\ 643 info->have_${ext.name_with_vendor()} |= support_${ext.name_with_vendor()} 644 ${conditions}; 645</%helpers:guard> 646 %endfor 647 } 648 649 // generate extension list 650 num_extensions = 0; 651 652%for ext in extensions: 653<%helpers:guard ext="${ext}"> 654 if (info->have_${ext.name_with_vendor()}) { 655 info->extensions[num_extensions++] = "${ext.name}"; 656%if ext.is_required: 657 } else { 658 debug_printf("ZINK: ${ext.name} required!\\n"); 659 goto fail; 660%endif 661 } 662</%helpers:guard> 663%endfor 664 665 info->num_extensions = num_extensions; 666 667 return true; 668 669fail: 670 return false; 671} 672 673void 674zink_verify_device_extensions(struct zink_screen *screen) 675{ 676%for ext in extensions: 677%if registry.in_registry(ext.name): 678<%helpers:guard ext="${ext}"> 679 if (screen->info.have_${ext.name_with_vendor()}) { 680%for cmd in registry.get_registry_entry(ext.name).device_commands: 681%if cmd.find("win32"): 682#ifdef _WIN32 683%endif 684 if (!screen->vk.${cmd.lstrip("vk")}) { 685#ifndef NDEBUG 686 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")}; 687#else 688 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded; 689#endif 690 } 691%if cmd.find("win32"): 692#endif 693%endif 694%endfor 695 } 696</%helpers:guard> 697%endif 698%endfor 699} 700 701#ifndef NDEBUG 702/* generated stub functions */ 703## remember the stub functions that are already generated 704<% generated_funcs = set() %> 705 706%for ext in extensions: 707%if registry.in_registry(ext.name): 708%for cmd in registry.get_registry_entry(ext.name).device_commands: 709## 710## some functions are added by multiple extensions, which creates duplication 711## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR) 712## 713%if cmd in generated_funcs: 714 <% continue %> 715%else: 716 <% generated_funcs.add(cmd) %> 717%endif 718void 719zink_stub_${cmd.lstrip("vk")}() 720{ 721 mesa_loge("ZINK: ${cmd} is not loaded properly!"); 722 abort(); 723} 724%endfor 725%endif 726%endfor 727#endif 728""" 729 730 731def replace_code(code: str, replacement: dict): 732 for (k, v) in replacement.items(): 733 code = code.replace(k, v) 734 735 return code 736 737 738if __name__ == "__main__": 739 try: 740 header_path = sys.argv[1] 741 impl_path = sys.argv[2] 742 vkxml_path = sys.argv[3] 743 744 header_path = path.abspath(header_path) 745 impl_path = path.abspath(impl_path) 746 vkxml_path = path.abspath(vkxml_path) 747 except: 748 print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0]) 749 exit(1) 750 751 registry = ExtensionRegistry(vkxml_path) 752 753 extensions = EXTENSIONS 754 versions = VERSIONS 755 replacement = REPLACEMENTS 756 757 # Perform extension validation and set core_since for the extension if available 758 error_count = 0 759 for ext in extensions: 760 if not registry.in_registry(ext.name): 761 # disable validation for nonstandard extensions 762 if ext.is_nonstandard: 763 continue 764 765 error_count += 1 766 print("The extension {} is not registered in vk.xml - a typo?".format(ext.name)) 767 continue 768 769 entry = registry.get_registry_entry(ext.name) 770 771 if entry.ext_type != "device": 772 error_count += 1 773 print("The extension {} is {} extension - expected a device extension.".format(ext.name, entry.ext_type)) 774 continue 775 776 if ext.has_features: 777 if not (entry.features_struct and ext.physical_device_struct("Features") == entry.features_struct): 778 error_count += 1 779 print("The extension {} does not provide a features struct.".format(ext.name)) 780 ext.features_promoted = entry.features_promoted 781 782 if ext.has_properties: 783 if not (entry.properties_struct and ext.physical_device_struct("Properties") == entry.properties_struct): 784 error_count += 1 785 print("The extension {} does not provide a properties struct.".format(ext.name)) 786 ext.properties_promoted = entry.properties_promoted 787 788 if entry.promoted_in and entry.promoted_in <= versions[-1].struct_version: 789 ext.core_since = Version((*entry.promoted_in, 0)) 790 else: 791 # even if the ext is promoted in a newer VK version, consider it 792 # unpromoted until there's an entry for that VK version in VERSIONS 793 ext.features_promoted = False 794 ext.properties_promoted = False 795 796 if error_count > 0: 797 print("zink_device_info.py: Found {} error(s) in total. Quitting.".format(error_count)) 798 exit(1) 799 800 lookup = TemplateLookup() 801 lookup.put_string("helpers", include_template) 802 803 with open(header_path, "w", encoding='utf-8') as header_file: 804 header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 805 header = replace_code(header, replacement) 806 print(header, file=header_file) 807 808 with open(impl_path, "w", encoding='utf-8') as impl_file: 809 impl = Template(impl_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 810 impl = replace_code(impl, replacement) 811 print(impl, file=impl_file) 812