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