Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_device_info.py
4570 views
1
# Copyright © 2020 Hoe Hao Cheng
2
#
3
# Permission is hereby granted, free of charge, to any person obtaining a
4
# copy of this software and associated documentation files (the "Software"),
5
# to deal in the Software without restriction, including without limitation
6
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
# and/or sell copies of the Software, and to permit persons to whom the
8
# Software is furnished to do so, subject to the following conditions:
9
#
10
# The above copyright notice and this permission notice (including the next
11
# paragraph) shall be included in all copies or substantial portions of the
12
# Software.
13
#
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20
# IN THE SOFTWARE.
21
#
22
# Authors:
23
# Hoe Hao Cheng <[email protected]>
24
#
25
26
from mako.template import Template
27
from mako.lookup import TemplateLookup
28
from os import path
29
from zink_extensions import Extension,ExtensionRegistry,Version
30
import 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.
61
EXTENSIONS = [
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_EXT_provoking_vertex",
69
alias="pv",
70
features=True,
71
properties=True,
72
conditions=["$feats.provokingVertexLast"]),
73
Extension("VK_EXT_shader_viewport_index_layer"),
74
Extension("VK_EXT_post_depth_coverage"),
75
Extension("VK_KHR_driver_properties",
76
alias="driver",
77
properties=True),
78
Extension("VK_EXT_memory_budget"),
79
Extension("VK_KHR_draw_indirect_count"),
80
Extension("VK_EXT_fragment_shader_interlock",
81
alias="interlock",
82
features=True,
83
conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]),
84
Extension("VK_EXT_sample_locations",
85
alias="sample_locations",
86
properties=True),
87
Extension("VK_EXT_conservative_rasterization",
88
alias="cons_raster",
89
properties=True,
90
conditions=["$props.fullyCoveredFragmentShaderInputVariable"]),
91
Extension("VK_KHR_shader_draw_parameters"),
92
Extension("VK_KHR_sampler_mirror_clamp_to_edge"),
93
Extension("VK_EXT_conditional_rendering",
94
alias="cond_render",
95
features=True,
96
conditions=["$feats.conditionalRendering"]),
97
Extension("VK_EXT_transform_feedback",
98
alias="tf",
99
properties=True,
100
features=True,
101
conditions=["$feats.transformFeedback"]),
102
Extension("VK_EXT_index_type_uint8",
103
alias="index_uint8",
104
features=True,
105
conditions=["$feats.indexTypeUint8"]),
106
Extension("VK_EXT_robustness2",
107
alias="rb2",
108
properties=True,
109
features=True,
110
conditions=["$feats.nullDescriptor"]),
111
Extension("VK_EXT_image_drm_format_modifier"),
112
Extension("VK_EXT_vertex_attribute_divisor",
113
alias="vdiv",
114
properties=True,
115
features=True,
116
conditions=["$feats.vertexAttributeInstanceRateDivisor"]),
117
Extension("VK_EXT_calibrated_timestamps"),
118
Extension("VK_KHR_shader_clock",
119
alias="shader_clock",
120
features=True,
121
conditions=["$feats.shaderSubgroupClock"]),
122
Extension("VK_EXT_shader_subgroup_ballot"),
123
Extension("VK_EXT_sampler_filter_minmax",
124
alias="reduction",
125
properties=True),
126
Extension("VK_EXT_custom_border_color",
127
alias="border_color",
128
properties=True,
129
features=True,
130
conditions=["$feats.customBorderColors"]),
131
Extension("VK_EXT_blend_operation_advanced",
132
alias="blend",
133
properties=True,
134
# TODO: we can probably support non-premul here with some work?
135
conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]),
136
Extension("VK_EXT_extended_dynamic_state",
137
alias="dynamic_state",
138
features=True,
139
conditions=["$feats.extendedDynamicState"]),
140
Extension("VK_EXT_pipeline_creation_cache_control",
141
alias="pipeline_cache_control",
142
features=True,
143
conditions=["$feats.pipelineCreationCacheControl"]),
144
Extension("VK_EXT_shader_stencil_export",
145
alias="stencil_export"),
146
Extension("VK_EXTX_portability_subset",
147
alias="portability_subset_extx",
148
nonstandard=True,
149
properties=True,
150
features=True,
151
guard=True),
152
Extension("VK_KHR_timeline_semaphore"),
153
Extension("VK_EXT_4444_formats",
154
alias="format_4444",
155
features=True),
156
Extension("VK_EXT_scalar_block_layout",
157
alias="scalar_block_layout",
158
features=True,
159
conditions=["$feats.scalarBlockLayout"]),
160
Extension("VK_KHR_swapchain"),
161
Extension("VK_KHR_shader_float16_int8",
162
alias="shader_float16_int8",
163
features=True),
164
Extension("VK_EXT_multi_draw",
165
alias="multidraw",
166
features=True,
167
properties=True,
168
conditions=["$feats.multiDraw"]),
169
Extension("VK_KHR_push_descriptor",
170
alias="push",
171
properties=True),
172
Extension("VK_KHR_descriptor_update_template",
173
alias="template"),
174
Extension("VK_EXT_line_rasterization",
175
alias="line_rast",
176
properties=True,
177
features=True),
178
]
179
180
# constructor: Versions(device_version(major, minor, patch), struct_version(major, minor))
181
# The attributes:
182
# - device_version: Vulkan version, as tuple, to use with
183
# VK_MAKE_VERSION(version_major, version_minor, version_patch)
184
#
185
# - struct_version: Vulkan version, as tuple, to use with structures and macros
186
VERSIONS = [
187
# VkPhysicalDeviceVulkan11Properties and VkPhysicalDeviceVulkan11Features is new from Vk 1.2, not Vk 1.1
188
# https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#_new_structures
189
Version((1,2,0), (1,1)),
190
Version((1,2,0), (1,2)),
191
]
192
193
# There exists some inconsistencies regarding the enum constants, fix them.
194
# This is basically generated_code.replace(key, value).
195
REPLACEMENTS = {
196
"ROBUSTNESS2": "ROBUSTNESS_2",
197
"PROPERTIES_PROPERTIES": "PROPERTIES",
198
}
199
200
201
# This template provides helper functions for the other templates.
202
# Right now, the following functions are defined:
203
# - guard(ext) : surrounds the body with an if-def guard according to
204
# `ext.extension_name()` if `ext.guard` is True.
205
include_template = """
206
<%def name="guard_(ext, body)">
207
%if ext.guard:
208
#ifdef ${ext.extension_name()}
209
%endif
210
${capture(body)|trim}
211
%if ext.guard:
212
#endif
213
%endif
214
</%def>
215
216
## This ugliness is here to prevent mako from adding tons of excessive whitespace
217
<%def name="guard(ext)">${capture(guard_, ext, body=caller.body).strip('\\r\\n')}</%def>
218
"""
219
220
header_code = """
221
<%namespace name="helpers" file="helpers"/>
222
223
#ifndef ZINK_DEVICE_INFO_H
224
#define ZINK_DEVICE_INFO_H
225
226
#include "util/u_memory.h"
227
228
#include <vulkan/vulkan.h>
229
230
struct zink_screen;
231
232
struct zink_device_info {
233
uint32_t device_version;
234
235
%for ext in extensions:
236
<%helpers:guard ext="${ext}">
237
bool have_${ext.name_with_vendor()};
238
</%helpers:guard>
239
%endfor
240
%for version in versions:
241
bool have_vulkan${version.struct()};
242
%endfor
243
244
VkPhysicalDeviceFeatures2 feats;
245
%for version in versions:
246
VkPhysicalDeviceVulkan${version.struct()}Features feats${version.struct()};
247
%endfor
248
249
VkPhysicalDeviceProperties props;
250
%for version in versions:
251
VkPhysicalDeviceVulkan${version.struct()}Properties props${version.struct()};
252
%endfor
253
254
VkPhysicalDeviceMemoryProperties mem_props;
255
256
%for ext in extensions:
257
<%helpers:guard ext="${ext}">
258
%if ext.has_features:
259
${ext.physical_device_struct("Features")} ${ext.field("feats")};
260
%endif
261
%if ext.has_properties:
262
${ext.physical_device_struct("Properties")} ${ext.field("props")};
263
%endif
264
</%helpers:guard>
265
%endfor
266
267
const char *extensions[${len(extensions)}];
268
uint32_t num_extensions;
269
};
270
271
bool
272
zink_get_physical_device_info(struct zink_screen *screen);
273
274
void
275
zink_verify_device_extensions(struct zink_screen *screen);
276
277
/* stub functions that get inserted into the dispatch table if they are not
278
* properly loaded.
279
*/
280
%for ext in extensions:
281
%if registry.in_registry(ext.name):
282
%for cmd in registry.get_registry_entry(ext.name).device_commands:
283
void zink_stub_${cmd.lstrip("vk")}(void);
284
%endfor
285
%endif
286
%endfor
287
288
#endif
289
"""
290
291
292
impl_code = """
293
<%namespace name="helpers" file="helpers"/>
294
295
#include "zink_device_info.h"
296
#include "zink_screen.h"
297
298
bool
299
zink_get_physical_device_info(struct zink_screen *screen)
300
{
301
struct zink_device_info *info = &screen->info;
302
%for ext in extensions:
303
<%helpers:guard ext="${ext}">
304
bool support_${ext.name_with_vendor()} = false;
305
</%helpers:guard>
306
%endfor
307
uint32_t num_extensions = 0;
308
309
// get device memory properties
310
vkGetPhysicalDeviceMemoryProperties(screen->pdev, &info->mem_props);
311
312
// enumerate device supported extensions
313
if (vkEnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, NULL) == VK_SUCCESS) {
314
if (num_extensions > 0) {
315
VkExtensionProperties *extensions = MALLOC(sizeof(VkExtensionProperties) * num_extensions);
316
if (!extensions) goto fail;
317
vkEnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, extensions);
318
319
for (uint32_t i = 0; i < num_extensions; ++i) {
320
%for ext in extensions:
321
<%helpers:guard ext="${ext}">
322
if (!strcmp(extensions[i].extensionName, "${ext.name}")) {
323
%if ext.core_since:
324
%for version in versions:
325
%if ext.core_since.struct_version == version.struct_version:
326
if (${version.version()} >= screen->vk_version) {
327
%if not (ext.has_features or ext.has_properties):
328
info->have_${ext.name_with_vendor()} = true;
329
%else:
330
support_${ext.name_with_vendor()} = true;
331
%endif
332
} else {
333
%if not (ext.has_features or ext.has_properties):
334
info->have_${ext.name_with_vendor()} = true;
335
%else:
336
support_${ext.name_with_vendor()} = true;
337
%endif
338
}
339
%endif
340
%endfor
341
%else:
342
%if not (ext.has_features or ext.has_properties):
343
info->have_${ext.name_with_vendor()} = true;
344
%else:
345
support_${ext.name_with_vendor()} = true;
346
%endif
347
%endif
348
}
349
</%helpers:guard>
350
%endfor
351
}
352
353
FREE(extensions);
354
}
355
}
356
357
// get device features
358
if (screen->vk.GetPhysicalDeviceFeatures2) {
359
// check for device extension features
360
info->feats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
361
362
%for version in versions:
363
if (${version.version()} <= screen->vk_version) {
364
info->feats${version.struct()}.sType = ${version.stype("FEATURES")};
365
info->feats${version.struct()}.pNext = info->feats.pNext;
366
info->feats.pNext = &info->feats${version.struct()};
367
info->have_vulkan${version.struct()} = true;
368
}
369
%endfor
370
371
%for ext in extensions:
372
%if ext.has_features:
373
<%helpers:guard ext="${ext}">
374
if (support_${ext.name_with_vendor()}) {
375
info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")};
376
info->${ext.field("feats")}.pNext = info->feats.pNext;
377
info->feats.pNext = &info->${ext.field("feats")};
378
}
379
</%helpers:guard>
380
%endif
381
%endfor
382
383
screen->vk.GetPhysicalDeviceFeatures2(screen->pdev, &info->feats);
384
} else {
385
vkGetPhysicalDeviceFeatures(screen->pdev, &info->feats.features);
386
}
387
388
// check for device properties
389
if (screen->vk.GetPhysicalDeviceProperties2) {
390
VkPhysicalDeviceProperties2 props = {0};
391
props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
392
393
%for version in versions:
394
if (${version.version()} <= screen->vk_version) {
395
info->props${version.struct()}.sType = ${version.stype("PROPERTIES")};
396
info->props${version.struct()}.pNext = props.pNext;
397
props.pNext = &info->props${version.struct()};
398
}
399
%endfor
400
401
%for ext in extensions:
402
%if ext.has_properties:
403
<%helpers:guard ext="${ext}">
404
if (support_${ext.name_with_vendor()}) {
405
info->${ext.field("props")}.sType = ${ext.stype("PROPERTIES")};
406
info->${ext.field("props")}.pNext = props.pNext;
407
props.pNext = &info->${ext.field("props")};
408
}
409
</%helpers:guard>
410
%endif
411
%endfor
412
413
// note: setting up local VkPhysicalDeviceProperties2.
414
screen->vk.GetPhysicalDeviceProperties2(screen->pdev, &props);
415
}
416
417
// enable the extensions if they match the conditions given by ext.enable_conds
418
if (screen->vk.GetPhysicalDeviceProperties2) {
419
%for ext in extensions:
420
<%helpers:guard ext="${ext}">
421
<%
422
conditions = ""
423
if ext.enable_conds:
424
for cond in ext.enable_conds:
425
cond = cond.replace("$feats", "info->" + ext.field("feats"))
426
cond = cond.replace("$props", "info->" + ext.field("props"))
427
conditions += "&& (" + cond + ")\\n"
428
conditions = conditions.strip()
429
%>\
430
info->have_${ext.name_with_vendor()} |= support_${ext.name_with_vendor()}
431
${conditions};
432
</%helpers:guard>
433
%endfor
434
}
435
436
// generate extension list
437
num_extensions = 0;
438
439
%for ext in extensions:
440
<%helpers:guard ext="${ext}">
441
if (info->have_${ext.name_with_vendor()}) {
442
info->extensions[num_extensions++] = "${ext.name}";
443
%if ext.is_required:
444
} else {
445
debug_printf("ZINK: ${ext.name} required!\\n");
446
goto fail;
447
%endif
448
}
449
</%helpers:guard>
450
%endfor
451
452
info->num_extensions = num_extensions;
453
454
return true;
455
456
fail:
457
return false;
458
}
459
460
void
461
zink_verify_device_extensions(struct zink_screen *screen)
462
{
463
%for ext in extensions:
464
%if registry.in_registry(ext.name):
465
if (screen->info.have_${ext.name_with_vendor()}) {
466
%for cmd in registry.get_registry_entry(ext.name).device_commands:
467
if (!screen->vk.${cmd.lstrip("vk")}) {
468
#ifndef NDEBUG
469
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")};
470
#else
471
screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded;
472
#endif
473
}
474
%endfor
475
}
476
%endif
477
%endfor
478
}
479
480
#ifndef NDEBUG
481
/* generated stub functions */
482
## remember the stub functions that are already generated
483
<% generated_funcs = set() %>
484
485
%for ext in extensions:
486
%if registry.in_registry(ext.name):
487
%for cmd in registry.get_registry_entry(ext.name).device_commands:
488
##
489
## some functions are added by multiple extensions, which creates duplication
490
## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR)
491
##
492
%if cmd in generated_funcs:
493
<% continue %>
494
%else:
495
<% generated_funcs.add(cmd) %>
496
%endif
497
void
498
zink_stub_${cmd.lstrip("vk")}()
499
{
500
mesa_loge("ZINK: ${cmd} is not loaded properly!");
501
abort();
502
}
503
%endfor
504
%endif
505
%endfor
506
#endif
507
"""
508
509
510
def replace_code(code: str, replacement: dict):
511
for (k, v) in replacement.items():
512
code = code.replace(k, v)
513
514
return code
515
516
517
if __name__ == "__main__":
518
try:
519
header_path = sys.argv[1]
520
impl_path = sys.argv[2]
521
vkxml_path = sys.argv[3]
522
523
header_path = path.abspath(header_path)
524
impl_path = path.abspath(impl_path)
525
vkxml_path = path.abspath(vkxml_path)
526
except:
527
print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0])
528
exit(1)
529
530
registry = ExtensionRegistry(vkxml_path)
531
532
extensions = EXTENSIONS
533
versions = VERSIONS
534
replacement = REPLACEMENTS
535
536
# Perform extension validation and set core_since for the extension if available
537
error_count = 0
538
for ext in extensions:
539
if not registry.in_registry(ext.name):
540
# disable validation for nonstandard extensions
541
if ext.is_nonstandard:
542
continue
543
544
error_count += 1
545
print("The extension {} is not registered in vk.xml - a typo?".format(ext.name))
546
continue
547
548
entry = registry.get_registry_entry(ext.name)
549
550
if entry.ext_type != "device":
551
error_count += 1
552
print("The extension {} is {} extension - expected a device extension.".format(ext.name, entry.ext_type))
553
continue
554
555
if ext.has_features:
556
if not (entry.features_struct and ext.physical_device_struct("Features") == entry.features_struct):
557
error_count += 1
558
print("The extension {} does not provide a features struct.".format(ext.name))
559
560
if ext.has_properties:
561
if not (entry.properties_struct and ext.physical_device_struct("Properties") == entry.properties_struct):
562
error_count += 1
563
print("The extension {} does not provide a properties struct.".format(ext.name))
564
print(entry.properties_struct, ext.physical_device_struct("Properties"))
565
566
if entry.promoted_in:
567
ext.core_since = Version((*entry.promoted_in, 0))
568
569
if error_count > 0:
570
print("zink_device_info.py: Found {} error(s) in total. Quitting.".format(error_count))
571
exit(1)
572
573
lookup = TemplateLookup()
574
lookup.put_string("helpers", include_template)
575
576
with open(header_path, "w") as header_file:
577
header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip()
578
header = replace_code(header, replacement)
579
print(header, file=header_file)
580
581
with open(impl_path, "w") as impl_file:
582
impl = Template(impl_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip()
583
impl = replace_code(impl, replacement)
584
print(impl, file=impl_file)
585
586