xref: /aosp_15_r20/external/mesa3d/src/gallium/drivers/zink/zink_device_info.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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