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 <[email protected]> 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_maintenance7", 76 alias="maint7", 77 features=True, properties=True), 78 Extension("VK_KHR_external_memory"), 79 Extension("VK_KHR_external_memory_fd"), 80 Extension("VK_KHR_vulkan_memory_model"), 81 Extension("VK_KHR_workgroup_memory_explicit_layout", alias="explicit_layout", features=True), 82 Extension("VK_KHR_pipeline_executable_properties", 83 alias="pipestats", 84 features=True), 85 Extension("VK_KHR_external_semaphore_fd"), 86 Extension("VK_KHR_create_renderpass2", 87 required=True), 88 Extension("VK_KHR_synchronization2", 89 alias="sync2", 90 features=True), 91 Extension("VK_KHR_external_memory_win32"), 92 Extension("VK_KHR_external_semaphore_win32"), 93 Extension("VK_EXT_external_memory_dma_buf"), 94 Extension("VK_KHR_buffer_device_address", 95 alias="bda", 96 features=True), 97 Extension("VK_EXT_external_memory_host", alias="ext_host_mem", properties=True), 98 Extension("VK_EXT_queue_family_foreign"), 99 Extension("VK_KHR_swapchain_mutable_format"), 100 Extension("VK_KHR_incremental_present"), 101 Extension("VK_EXT_provoking_vertex", 102 alias="pv", 103 features=True, 104 properties=True, 105 conditions=["$feats.provokingVertexLast"]), 106 Extension("VK_EXT_shader_viewport_index_layer"), 107 Extension("VK_KHR_get_memory_requirements2"), 108 Extension("VK_EXT_post_depth_coverage"), 109 Extension("VK_EXT_depth_clip_control", 110 alias="clip_control", 111 features=True), 112 Extension("VK_EXT_depth_clamp_zero_one", 113 alias="clamp_01", 114 features=True), 115 Extension("VK_EXT_shader_subgroup_ballot"), 116 Extension("VK_EXT_shader_subgroup_vote"), 117 Extension("VK_EXT_legacy_vertex_attributes", alias="legacyverts", features=True, properties=True), 118 Extension("VK_EXT_shader_atomic_float", 119 alias="atomic_float", 120 features=True), 121 Extension("VK_KHR_shader_atomic_int64", 122 alias="atomic_int", 123 features=True), 124 Extension("VK_KHR_8bit_storage", 125 alias="storage_8bit", 126 features=True, 127 conditions=["$feats.storageBuffer8BitAccess"]), 128 Extension("VK_KHR_16bit_storage", 129 alias="storage_16bit", 130 features=True, 131 conditions=["$feats.storageBuffer16BitAccess"]), 132 Extension("VK_EXT_image_2d_view_of_3d", 133 alias="view2d", 134 features=True), 135 Extension("VK_KHR_driver_properties", 136 alias="driver", 137 properties=True), 138 Extension("VK_EXT_memory_budget"), 139 Extension("VK_EXT_memory_priority", alias="memprio", features=True), 140 Extension("VK_EXT_pageable_device_local_memory", alias="mempage", features=True), 141 Extension("VK_KHR_draw_indirect_count"), 142 Extension("VK_EXT_dynamic_rendering_unused_attachments", alias="unused", features=True), 143 Extension("VK_EXT_shader_object", alias="shobj", features=True, properties=True), 144 Extension("VK_EXT_attachment_feedback_loop_layout", 145 alias="feedback_loop", 146 features=True), 147 Extension("VK_EXT_attachment_feedback_loop_dynamic_state", alias="feedback_dyn", features=True), 148 Extension("VK_EXT_fragment_shader_interlock", 149 alias="interlock", 150 features=True, 151 conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]), 152 Extension("VK_EXT_sample_locations", 153 alias="sample_locations", 154 properties=True), 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 Extension("VK_KHR_format_feature_flags2"), 330] 331 332# constructor: Versions(device_version(major, minor, patch), struct_version(major, minor)) 333# The attributes: 334# - device_version: Vulkan version, as tuple, to use with 335# VK_MAKE_VERSION(version_major, version_minor, version_patch) 336# 337# - struct_version: Vulkan version, as tuple, to use with structures and macros 338VERSIONS = [ 339 Version((1,1,0), (1,1)), 340 Version((1,2,0), (1,2)), 341 Version((1,3,0), (1,3)), 342] 343 344# There exists some inconsistencies regarding the enum constants, fix them. 345# This is basically generated_code.replace(key, value). 346REPLACEMENTS = { 347 "PROPERTIES_PROPERTIES": "PROPERTIES", 348} 349 350 351# This template provides helper functions for the other templates. 352# Right now, the following functions are defined: 353# - guard(ext) : surrounds the body with an if-def guard according to 354# `ext.extension_name()` if `ext.guard` is True. 355include_template = """ 356<%def name="guard_(ext, body)"> 357%if ext.guard: 358#ifdef ${ext.extension_name()} 359%endif 360 ${capture(body)|trim} 361%if ext.guard: 362#endif 363%endif 364</%def> 365 366## This ugliness is here to prevent mako from adding tons of excessive whitespace 367<%def name="guard(ext)">${capture(guard_, ext, body=caller.body).strip('\\r\\n')}</%def> 368""" 369 370header_code = """ 371<%namespace name="helpers" file="helpers"/> 372 373#ifndef ZINK_DEVICE_INFO_H 374#define ZINK_DEVICE_INFO_H 375 376#include "util/u_memory.h" 377 378#include <vulkan/vulkan_core.h> 379 380#ifdef VK_ENABLE_BETA_EXTENSIONS 381#include <vulkan/vulkan_beta.h> 382#endif 383 384#ifdef _WIN32 385#include <windows.h> 386#include <vulkan/vulkan_win32.h> 387#endif 388 389struct zink_screen; 390 391struct zink_device_info { 392 uint32_t device_version; 393 394%for ext in extensions: 395<%helpers:guard ext="${ext}"> 396 bool have_${ext.name_with_vendor()}; 397</%helpers:guard> 398%endfor 399%for version in versions: 400 bool have_vulkan${version.struct()}; 401%endfor 402 403 VkPhysicalDeviceFeatures2 feats; 404 VkPhysicalDeviceSubgroupProperties subgroup; 405%for version in versions: 406 VkPhysicalDeviceVulkan${version.struct()}Features feats${version.struct()}; 407%endfor 408 409 VkPhysicalDeviceProperties props; 410 VkPhysicalDeviceProperties vk_layered_props; 411 VkPhysicalDeviceLayeredApiPropertiesKHR layered_props; 412 VkPhysicalDeviceDriverPropertiesKHR vk_layered_driver_props; 413%for version in versions: 414 VkPhysicalDeviceVulkan${version.struct()}Properties props${version.struct()}; 415%endfor 416 417 VkPhysicalDeviceMemoryProperties mem_props; 418 VkPhysicalDeviceIDProperties deviceid_props; 419 420%for ext in extensions: 421<%helpers:guard ext="${ext}"> 422%if ext.has_features: 423 ${ext.physical_device_struct("Features")} ${ext.field("feats")}; 424%endif 425%if ext.has_properties: 426 ${ext.physical_device_struct("Properties")} ${ext.field("props")}; 427%endif 428</%helpers:guard> 429%endfor 430 431 const char *extensions[${len(extensions)}]; 432 uint32_t num_extensions; 433}; 434 435bool 436zink_get_physical_device_info(struct zink_screen *screen); 437 438void 439zink_verify_device_extensions(struct zink_screen *screen); 440 441/* stub functions that get inserted into the dispatch table if they are not 442 * properly loaded. 443 */ 444%for ext in extensions: 445%if registry.in_registry(ext.name): 446%for cmd in registry.get_registry_entry(ext.name).device_commands: 447void VKAPI_PTR zink_stub_${cmd.lstrip("vk")}(void); 448%endfor 449%endif 450%endfor 451 452#endif 453""" 454 455 456impl_code = """ 457<%namespace name="helpers" file="helpers"/> 458 459#include "vk_enum_to_str.h" 460#include "zink_device_info.h" 461#include "zink_screen.h" 462 463bool 464zink_get_physical_device_info(struct zink_screen *screen) 465{ 466 struct zink_device_info *info = &screen->info; 467%for ext in extensions: 468<%helpers:guard ext="${ext}"> 469 bool support_${ext.name_with_vendor()} = false; 470</%helpers:guard> 471%endfor 472 uint32_t num_extensions = 0; 473 474 // get device memory properties 475 screen->vk.GetPhysicalDeviceMemoryProperties(screen->pdev, &info->mem_props); 476 477 // enumerate device supported extensions 478 VkResult result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, NULL); 479 if (result != VK_SUCCESS) { 480 if (!screen->driver_name_is_inferred) 481 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 482 } else { 483 if (num_extensions > 0) { 484 VkExtensionProperties *extensions = MALLOC(sizeof(VkExtensionProperties) * num_extensions); 485 if (!extensions) goto fail; 486 result = screen->vk.EnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, extensions); 487 if (result != VK_SUCCESS) { 488 if (!screen->driver_name_is_inferred) 489 mesa_loge("ZINK: vkEnumerateDeviceExtensionProperties failed (%s)", vk_Result_to_str(result)); 490 } 491 492 for (uint32_t i = 0; i < num_extensions; ++i) { 493 %for ext in extensions: 494 <%helpers:guard ext="${ext}"> 495 if (!strcmp(extensions[i].extensionName, "${ext.name}")) { 496 %if not (ext.has_features or ext.has_properties): 497 info->have_${ext.name_with_vendor()} = true; 498 %else: 499 support_${ext.name_with_vendor()} = true; 500 %endif 501 } 502 </%helpers:guard> 503 %endfor 504 } 505 506 FREE(extensions); 507 } 508 } 509 510 // get device features 511 if (screen->vk.GetPhysicalDeviceFeatures2) { 512 // check for device extension features 513 info->feats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2; 514 515%for version in versions: 516%if version.device_version < (1,2,0): 517 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 518 /* VkPhysicalDeviceVulkan11Features was added in 1.2, not 1.1 as one would think */ 519%else: 520 if (${version.version()} <= screen->vk_version) { 521%endif 522 info->feats${version.struct()}.sType = ${version.stype("FEATURES")}; 523 info->feats${version.struct()}.pNext = info->feats.pNext; 524 info->feats.pNext = &info->feats${version.struct()}; 525 info->have_vulkan${version.struct()} = true; 526 } 527%endfor 528 529%for ext in extensions: 530%if ext.has_features: 531<%helpers:guard ext="${ext}"> 532%if ext.features_promoted: 533 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 534%else: 535 if (support_${ext.name_with_vendor()}) { 536%endif 537 info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")}; 538 info->${ext.field("feats")}.pNext = info->feats.pNext; 539 info->feats.pNext = &info->${ext.field("feats")}; 540 } 541</%helpers:guard> 542%endif 543%endfor 544 545 screen->vk.GetPhysicalDeviceFeatures2(screen->pdev, &info->feats); 546 } else { 547 screen->vk.GetPhysicalDeviceFeatures(screen->pdev, &info->feats.features); 548 } 549 550 // check for device properties 551 bool copy_layered_props = false; 552 if (screen->vk.GetPhysicalDeviceProperties2) { 553 VkPhysicalDeviceProperties2 props = {0}; 554 props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 555 556%for version in versions: 557%if version.device_version < (1,2,0): 558 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 559 /* VkPhysicalDeviceVulkan11Properties was added in 1.2, not 1.1 as one would think */ 560%else: 561 if (${version.version()} <= screen->vk_version) { 562%endif 563 info->props${version.struct()}.sType = ${version.stype("PROPERTIES")}; 564 info->props${version.struct()}.pNext = props.pNext; 565 props.pNext = &info->props${version.struct()}; 566 } 567%endfor 568 569%for ext in extensions: 570%if ext.has_properties: 571<%helpers:guard ext="${ext}"> 572%if ext.properties_promoted: 573 if (support_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 574%else: 575 if (support_${ext.name_with_vendor()}) { 576%endif 577 info->${ext.field("props")}.sType = ${ext.stype("PROPERTIES")}; 578 info->${ext.field("props")}.pNext = props.pNext; 579 props.pNext = &info->${ext.field("props")}; 580 } 581</%helpers:guard> 582%endif 583%endfor 584 585 if (screen->vk_version < VK_MAKE_VERSION(1,2,0) && screen->instance_info.have_KHR_external_memory_capabilities) { 586 info->deviceid_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES; 587 info->deviceid_props.pNext = props.pNext; 588 props.pNext = &info->deviceid_props; 589 } 590 591 if (screen->vk_version >= VK_MAKE_VERSION(1,1,0)) { 592 info->subgroup.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES; 593 info->subgroup.pNext = props.pNext; 594 props.pNext = &info->subgroup; 595 } 596 597 /* set up structs to capture underlying driver info */ 598 VkPhysicalDeviceLayeredApiVulkanPropertiesKHR vk_layered_props = { 599 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_VULKAN_PROPERTIES_KHR, 600 }; 601 vk_layered_props.properties.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2; 602 info->vk_layered_driver_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES; 603 if (support_KHR_driver_properties || info->have_vulkan12) 604 vk_layered_props.properties.pNext = &info->vk_layered_driver_props; 605 info->layered_props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR; 606 info->layered_props.pNext = &vk_layered_props; 607 VkPhysicalDeviceLayeredApiPropertiesListKHR layered_props_list = { 608 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_LIST_KHR, 609 props.pNext, 610 1, 611 &info->layered_props 612 }; 613 if (support_KHR_maintenance7) 614 props.pNext = &layered_props_list; 615 616 // note: setting up local VkPhysicalDeviceProperties2. 617 screen->vk.GetPhysicalDeviceProperties2(screen->pdev, &props); 618 619 if (support_KHR_maintenance7 && layered_props_list.layeredApiCount) { 620 info->vk_layered_props = vk_layered_props.properties.properties; 621 } else { 622 info->vk_layered_props = info->props; 623 copy_layered_props = true; 624 } 625 } 626 627 /* We re-apply the fields from VkPhysicalDeviceVulkanXYFeatures struct 628 * onto their respective fields in the VkPhysicalDeviceExtensionNameFeatures 629 * struct if the former is provided by the VK implementation. 630 * 631 * As for why this is done: the spec mentions that once an extension is 632 * promoted to core and its feature fields are added in VulkanXYFeatures, 633 * including both ExtensionNameFeatures and VulkanXYFeatures at the same 634 * time is prohibited when using vkGetPhysicalDeviceFeatures2. 635 */ 636%for ext in extensions: 637%if ext.features_promoted: 638 if (info->have_vulkan${ext.core_since.struct()}) { 639 %for field in registry.get_registry_entry(ext.name).features_fields: 640 info->${ext.field("feats")}.${field} = info->feats${ext.core_since.struct()}.${field}; 641 %endfor 642 } 643%endif 644%endfor 645 646 /* See above, but for VulkanXYProperties. 647 * Unlike VulkanXYFeatures with all the booleans, VulkanXYProperties can 648 * contain different types of data, including arrays. The C language hates us 649 * when we assign an array to another array, therefore we use an memcpy here. 650 */ 651%for ext in extensions: 652%if ext.properties_promoted: 653 if (info->have_vulkan${ext.core_since.struct()}) { 654 %for field in registry.get_registry_entry(ext.name).properties_fields: 655 memcpy(&info->${ext.field("props")}.${field}, 656 &info->props${ext.core_since.struct()}.${field}, 657 sizeof(info->${ext.field("props")}.${field})); 658 %endfor 659 } 660%endif 661%endfor 662 663 if (copy_layered_props) 664 info->vk_layered_driver_props = info->driver_props; 665 666 // enable the extensions if they match the conditions given by ext.enable_conds 667 if (screen->vk.GetPhysicalDeviceProperties2) { 668 %for ext in extensions: 669<%helpers:guard ext="${ext}"> 670<% 671 conditions = "" 672 if ext.enable_conds: 673 for cond in ext.enable_conds: 674 cond = cond.replace("$feats", "info->" + ext.field("feats")) 675 cond = cond.replace("$props", "info->" + ext.field("props")) 676 conditions += "&& (" + cond + ")\\n" 677 conditions = conditions.strip() 678%>\ 679 info->have_${ext.name_with_vendor()} |= support_${ext.name_with_vendor()} 680 ${conditions}; 681</%helpers:guard> 682 %endfor 683 } 684 685 // generate extension list 686 num_extensions = 0; 687 688%for ext in extensions: 689<%helpers:guard ext="${ext}"> 690 if (info->have_${ext.name_with_vendor()}) { 691 info->extensions[num_extensions++] = "${ext.name}"; 692%if ext.is_required: 693 } else { 694 debug_printf("ZINK: ${ext.name} required!\\n"); 695 goto fail; 696%endif 697 } 698</%helpers:guard> 699%endfor 700 701 info->num_extensions = num_extensions; 702 703 info->feats.pNext = NULL; 704 705%for version in versions: 706%if version.device_version < (1,2,0): 707 if (VK_MAKE_VERSION(1,2,0) <= screen->vk_version) { 708 /* VkPhysicalDeviceVulkan11Features was added in 1.2, not 1.1 as one would think */ 709%else: 710 if (${version.version()} <= screen->vk_version) { 711%endif 712 info->feats${version.struct()}.pNext = info->feats.pNext; 713 info->feats.pNext = &info->feats${version.struct()}; 714 } 715%endfor 716 717%for ext in extensions: 718%if ext.has_features: 719<%helpers:guard ext="${ext}"> 720%if ext.features_promoted: 721 if (info->have_${ext.name_with_vendor()} && !info->have_vulkan${ext.core_since.struct()}) { 722%else: 723 if (info->have_${ext.name_with_vendor()}) { 724%endif 725 info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")}; 726 info->${ext.field("feats")}.pNext = info->feats.pNext; 727 info->feats.pNext = &info->${ext.field("feats")}; 728 } 729</%helpers:guard> 730%endif 731%endfor 732 733 return true; 734 735fail: 736 return false; 737} 738 739void 740zink_verify_device_extensions(struct zink_screen *screen) 741{ 742%for ext in extensions: 743%if registry.in_registry(ext.name): 744<%helpers:guard ext="${ext}"> 745 if (screen->info.have_${ext.name_with_vendor()}) { 746%for cmd in registry.get_registry_entry(ext.name).device_commands: 747%if cmd.find("win32"): 748#ifdef _WIN32 749%endif 750 if (!screen->vk.${cmd.lstrip("vk")}) { 751#ifndef NDEBUG 752 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")}; 753#else 754 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded; 755#endif 756 } 757%if cmd.find("win32"): 758#endif 759%endif 760%endfor 761 } 762</%helpers:guard> 763%endif 764%endfor 765} 766 767#ifndef NDEBUG 768/* generated stub functions */ 769## remember the stub functions that are already generated 770<% generated_funcs = set() %> 771 772%for ext in extensions: 773%if registry.in_registry(ext.name): 774%for cmd in registry.get_registry_entry(ext.name).device_commands: 775## 776## some functions are added by multiple extensions, which creates duplication 777## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR) 778## 779%if cmd in generated_funcs: 780 <% continue %> 781%else: 782 <% generated_funcs.add(cmd) %> 783%endif 784void VKAPI_PTR 785zink_stub_${cmd.lstrip("vk")}() 786{ 787 mesa_loge("ZINK: ${cmd} is not loaded properly!"); 788 abort(); 789} 790%endfor 791%endif 792%endfor 793#endif 794""" 795 796 797def replace_code(code: str, replacement: dict): 798 for (k, v) in replacement.items(): 799 code = code.replace(k, v) 800 801 return code 802 803 804if __name__ == "__main__": 805 try: 806 header_path = sys.argv[1] 807 impl_path = sys.argv[2] 808 vkxml_path = sys.argv[3] 809 810 header_path = path.abspath(header_path) 811 impl_path = path.abspath(impl_path) 812 vkxml_path = path.abspath(vkxml_path) 813 except: 814 print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0]) 815 exit(1) 816 817 registry = ExtensionRegistry(vkxml_path) 818 819 extensions = EXTENSIONS 820 versions = VERSIONS 821 replacement = REPLACEMENTS 822 823 # Perform extension validation and set core_since for the extension if available 824 error_count = 0 825 for ext in extensions: 826 if not registry.in_registry(ext.name): 827 # disable validation for nonstandard extensions 828 if ext.is_nonstandard: 829 continue 830 831 error_count += 1 832 print("The extension {} is not registered in vk.xml - a typo?".format(ext.name)) 833 continue 834 835 entry = registry.get_registry_entry(ext.name) 836 837 if entry.ext_type != "device": 838 error_count += 1 839 print("The extension {} is {} extension - expected a device extension.".format(ext.name, entry.ext_type)) 840 continue 841 842 if ext.has_features: 843 if not (entry.features_struct and ext.physical_device_struct("Features") == entry.features_struct): 844 error_count += 1 845 print("The extension {} does not provide a features struct.".format(ext.name)) 846 ext.features_promoted = entry.features_promoted 847 848 if ext.has_properties: 849 if not (entry.properties_struct and ext.physical_device_struct("Properties") == entry.properties_struct): 850 error_count += 1 851 print("The extension {} does not provide a properties struct.".format(ext.name)) 852 ext.properties_promoted = entry.properties_promoted 853 854 if entry.promoted_in and entry.promoted_in <= versions[-1].struct_version: 855 ext.core_since = Version((*entry.promoted_in, 0)) 856 else: 857 # even if the ext is promoted in a newer VK version, consider it 858 # unpromoted until there's an entry for that VK version in VERSIONS 859 ext.features_promoted = False 860 ext.properties_promoted = False 861 862 if error_count > 0: 863 print("zink_device_info.py: Found {} error(s) in total. Quitting.".format(error_count)) 864 exit(1) 865 866 lookup = TemplateLookup() 867 lookup.put_string("helpers", include_template) 868 869 with open(header_path, "w", encoding='utf-8') as header_file: 870 header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 871 header = replace_code(header, replacement) 872 print(header, file=header_file) 873 874 with open(impl_path, "w", encoding='utf-8') as impl_file: 875 impl = Template(impl_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip() 876 impl = replace_code(impl, replacement) 877 print(impl, file=impl_file) 878