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