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