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