Path: blob/21.2-virgl/src/gallium/drivers/zink/zink_device_info.py
4570 views
# Copyright © 2020 Hoe Hao Cheng1#2# Permission is hereby granted, free of charge, to any person obtaining a3# copy of this software and associated documentation files (the "Software"),4# to deal in the Software without restriction, including without limitation5# the rights to use, copy, modify, merge, publish, distribute, sublicense,6# and/or sell copies of the Software, and to permit persons to whom the7# Software is furnished to do so, subject to the following conditions:8#9# The above copyright notice and this permission notice (including the next10# paragraph) shall be included in all copies or substantial portions of the11# Software.12#13# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR14# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,15# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL16# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER17# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING18# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS19# IN THE SOFTWARE.20#21# Authors:22# Hoe Hao Cheng <[email protected]>23#2425from mako.template import Template26from mako.lookup import TemplateLookup27from os import path28from zink_extensions import Extension,ExtensionRegistry,Version29import sys3031# constructor:32# Extension(name, alias="", required=False, properties=False, features=False, conditions=None, guard=False)33# The attributes:34# - required: the generated code debug_prints "ZINK: {name} required!" and35# returns NULL if the extension is unavailable.36#37# - properties: enable the detection of extension properties in a physical38# device in the generated code using vkGetPhysicalDeviceProperties2(),39# and store the returned properties struct inside40# `zink_device_info.{alias}_props`.41# Example: the properties for `VK_EXT_transform_feedback`, is stored in42# `VkPhysicalDeviceTransformFeedbackPropertiesEXT tf_props`.43#44# - features: enable the getting extension features in a45# device. Similar to `properties`, this stores the features46# struct inside `zink_device_info.{alias}_feats`.47#48# - conditions: criteria for enabling an extension. This is an array of strings,49# where each string is a condition, and all conditions have to be true50# for `zink_device_info.have_{name}` to be true.51#52# The code generator will replace "$feats" and "$props" with the53# respective variables, e.g. "$feats.nullDescriptor" becomes54# "info->rb2_feats.nullDescriptor" in the final code for VK_EXT_robustness2.55#56# When empty or None, the extension is enabled when the extensions57# given by vkEnumerateDeviceExtensionProperties() include the extension.58#59# - guard: adds a #if defined(`extension_name`)/#endif guard around the code generated for this Extension.60EXTENSIONS = [61Extension("VK_KHR_maintenance1",62required=True),63Extension("VK_KHR_maintenance2"),64Extension("VK_KHR_maintenance3"),65Extension("VK_KHR_external_memory"),66Extension("VK_KHR_external_memory_fd"),67Extension("VK_EXT_provoking_vertex",68alias="pv",69features=True,70properties=True,71conditions=["$feats.provokingVertexLast"]),72Extension("VK_EXT_shader_viewport_index_layer"),73Extension("VK_EXT_post_depth_coverage"),74Extension("VK_KHR_driver_properties",75alias="driver",76properties=True),77Extension("VK_EXT_memory_budget"),78Extension("VK_KHR_draw_indirect_count"),79Extension("VK_EXT_fragment_shader_interlock",80alias="interlock",81features=True,82conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]),83Extension("VK_EXT_sample_locations",84alias="sample_locations",85properties=True),86Extension("VK_EXT_conservative_rasterization",87alias="cons_raster",88properties=True,89conditions=["$props.fullyCoveredFragmentShaderInputVariable"]),90Extension("VK_KHR_shader_draw_parameters"),91Extension("VK_KHR_sampler_mirror_clamp_to_edge"),92Extension("VK_EXT_conditional_rendering",93alias="cond_render",94features=True,95conditions=["$feats.conditionalRendering"]),96Extension("VK_EXT_transform_feedback",97alias="tf",98properties=True,99features=True,100conditions=["$feats.transformFeedback"]),101Extension("VK_EXT_index_type_uint8",102alias="index_uint8",103features=True,104conditions=["$feats.indexTypeUint8"]),105Extension("VK_EXT_robustness2",106alias="rb2",107properties=True,108features=True,109conditions=["$feats.nullDescriptor"]),110Extension("VK_EXT_image_drm_format_modifier"),111Extension("VK_EXT_vertex_attribute_divisor",112alias="vdiv",113properties=True,114features=True,115conditions=["$feats.vertexAttributeInstanceRateDivisor"]),116Extension("VK_EXT_calibrated_timestamps"),117Extension("VK_KHR_shader_clock",118alias="shader_clock",119features=True,120conditions=["$feats.shaderSubgroupClock"]),121Extension("VK_EXT_shader_subgroup_ballot"),122Extension("VK_EXT_sampler_filter_minmax",123alias="reduction",124properties=True),125Extension("VK_EXT_custom_border_color",126alias="border_color",127properties=True,128features=True,129conditions=["$feats.customBorderColors"]),130Extension("VK_EXT_blend_operation_advanced",131alias="blend",132properties=True,133# TODO: we can probably support non-premul here with some work?134conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]),135Extension("VK_EXT_extended_dynamic_state",136alias="dynamic_state",137features=True,138conditions=["$feats.extendedDynamicState"]),139Extension("VK_EXT_pipeline_creation_cache_control",140alias="pipeline_cache_control",141features=True,142conditions=["$feats.pipelineCreationCacheControl"]),143Extension("VK_EXT_shader_stencil_export",144alias="stencil_export"),145Extension("VK_EXTX_portability_subset",146alias="portability_subset_extx",147nonstandard=True,148properties=True,149features=True,150guard=True),151Extension("VK_KHR_timeline_semaphore"),152Extension("VK_EXT_4444_formats",153alias="format_4444",154features=True),155Extension("VK_EXT_scalar_block_layout",156alias="scalar_block_layout",157features=True,158conditions=["$feats.scalarBlockLayout"]),159Extension("VK_KHR_swapchain"),160Extension("VK_KHR_shader_float16_int8",161alias="shader_float16_int8",162features=True),163Extension("VK_EXT_multi_draw",164alias="multidraw",165features=True,166properties=True,167conditions=["$feats.multiDraw"]),168Extension("VK_KHR_push_descriptor",169alias="push",170properties=True),171Extension("VK_KHR_descriptor_update_template",172alias="template"),173Extension("VK_EXT_line_rasterization",174alias="line_rast",175properties=True,176features=True),177]178179# constructor: Versions(device_version(major, minor, patch), struct_version(major, minor))180# The attributes:181# - device_version: Vulkan version, as tuple, to use with182# VK_MAKE_VERSION(version_major, version_minor, version_patch)183#184# - struct_version: Vulkan version, as tuple, to use with structures and macros185VERSIONS = [186# VkPhysicalDeviceVulkan11Properties and VkPhysicalDeviceVulkan11Features is new from Vk 1.2, not Vk 1.1187# https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#_new_structures188Version((1,2,0), (1,1)),189Version((1,2,0), (1,2)),190]191192# There exists some inconsistencies regarding the enum constants, fix them.193# This is basically generated_code.replace(key, value).194REPLACEMENTS = {195"ROBUSTNESS2": "ROBUSTNESS_2",196"PROPERTIES_PROPERTIES": "PROPERTIES",197}198199200# This template provides helper functions for the other templates.201# Right now, the following functions are defined:202# - guard(ext) : surrounds the body with an if-def guard according to203# `ext.extension_name()` if `ext.guard` is True.204include_template = """205<%def name="guard_(ext, body)">206%if ext.guard:207#ifdef ${ext.extension_name()}208%endif209${capture(body)|trim}210%if ext.guard:211#endif212%endif213</%def>214215## This ugliness is here to prevent mako from adding tons of excessive whitespace216<%def name="guard(ext)">${capture(guard_, ext, body=caller.body).strip('\\r\\n')}</%def>217"""218219header_code = """220<%namespace name="helpers" file="helpers"/>221222#ifndef ZINK_DEVICE_INFO_H223#define ZINK_DEVICE_INFO_H224225#include "util/u_memory.h"226227#include <vulkan/vulkan.h>228229struct zink_screen;230231struct zink_device_info {232uint32_t device_version;233234%for ext in extensions:235<%helpers:guard ext="${ext}">236bool have_${ext.name_with_vendor()};237</%helpers:guard>238%endfor239%for version in versions:240bool have_vulkan${version.struct()};241%endfor242243VkPhysicalDeviceFeatures2 feats;244%for version in versions:245VkPhysicalDeviceVulkan${version.struct()}Features feats${version.struct()};246%endfor247248VkPhysicalDeviceProperties props;249%for version in versions:250VkPhysicalDeviceVulkan${version.struct()}Properties props${version.struct()};251%endfor252253VkPhysicalDeviceMemoryProperties mem_props;254255%for ext in extensions:256<%helpers:guard ext="${ext}">257%if ext.has_features:258${ext.physical_device_struct("Features")} ${ext.field("feats")};259%endif260%if ext.has_properties:261${ext.physical_device_struct("Properties")} ${ext.field("props")};262%endif263</%helpers:guard>264%endfor265266const char *extensions[${len(extensions)}];267uint32_t num_extensions;268};269270bool271zink_get_physical_device_info(struct zink_screen *screen);272273void274zink_verify_device_extensions(struct zink_screen *screen);275276/* stub functions that get inserted into the dispatch table if they are not277* properly loaded.278*/279%for ext in extensions:280%if registry.in_registry(ext.name):281%for cmd in registry.get_registry_entry(ext.name).device_commands:282void zink_stub_${cmd.lstrip("vk")}(void);283%endfor284%endif285%endfor286287#endif288"""289290291impl_code = """292<%namespace name="helpers" file="helpers"/>293294#include "zink_device_info.h"295#include "zink_screen.h"296297bool298zink_get_physical_device_info(struct zink_screen *screen)299{300struct zink_device_info *info = &screen->info;301%for ext in extensions:302<%helpers:guard ext="${ext}">303bool support_${ext.name_with_vendor()} = false;304</%helpers:guard>305%endfor306uint32_t num_extensions = 0;307308// get device memory properties309vkGetPhysicalDeviceMemoryProperties(screen->pdev, &info->mem_props);310311// enumerate device supported extensions312if (vkEnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, NULL) == VK_SUCCESS) {313if (num_extensions > 0) {314VkExtensionProperties *extensions = MALLOC(sizeof(VkExtensionProperties) * num_extensions);315if (!extensions) goto fail;316vkEnumerateDeviceExtensionProperties(screen->pdev, NULL, &num_extensions, extensions);317318for (uint32_t i = 0; i < num_extensions; ++i) {319%for ext in extensions:320<%helpers:guard ext="${ext}">321if (!strcmp(extensions[i].extensionName, "${ext.name}")) {322%if ext.core_since:323%for version in versions:324%if ext.core_since.struct_version == version.struct_version:325if (${version.version()} >= screen->vk_version) {326%if not (ext.has_features or ext.has_properties):327info->have_${ext.name_with_vendor()} = true;328%else:329support_${ext.name_with_vendor()} = true;330%endif331} else {332%if not (ext.has_features or ext.has_properties):333info->have_${ext.name_with_vendor()} = true;334%else:335support_${ext.name_with_vendor()} = true;336%endif337}338%endif339%endfor340%else:341%if not (ext.has_features or ext.has_properties):342info->have_${ext.name_with_vendor()} = true;343%else:344support_${ext.name_with_vendor()} = true;345%endif346%endif347}348</%helpers:guard>349%endfor350}351352FREE(extensions);353}354}355356// get device features357if (screen->vk.GetPhysicalDeviceFeatures2) {358// check for device extension features359info->feats.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;360361%for version in versions:362if (${version.version()} <= screen->vk_version) {363info->feats${version.struct()}.sType = ${version.stype("FEATURES")};364info->feats${version.struct()}.pNext = info->feats.pNext;365info->feats.pNext = &info->feats${version.struct()};366info->have_vulkan${version.struct()} = true;367}368%endfor369370%for ext in extensions:371%if ext.has_features:372<%helpers:guard ext="${ext}">373if (support_${ext.name_with_vendor()}) {374info->${ext.field("feats")}.sType = ${ext.stype("FEATURES")};375info->${ext.field("feats")}.pNext = info->feats.pNext;376info->feats.pNext = &info->${ext.field("feats")};377}378</%helpers:guard>379%endif380%endfor381382screen->vk.GetPhysicalDeviceFeatures2(screen->pdev, &info->feats);383} else {384vkGetPhysicalDeviceFeatures(screen->pdev, &info->feats.features);385}386387// check for device properties388if (screen->vk.GetPhysicalDeviceProperties2) {389VkPhysicalDeviceProperties2 props = {0};390props.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;391392%for version in versions:393if (${version.version()} <= screen->vk_version) {394info->props${version.struct()}.sType = ${version.stype("PROPERTIES")};395info->props${version.struct()}.pNext = props.pNext;396props.pNext = &info->props${version.struct()};397}398%endfor399400%for ext in extensions:401%if ext.has_properties:402<%helpers:guard ext="${ext}">403if (support_${ext.name_with_vendor()}) {404info->${ext.field("props")}.sType = ${ext.stype("PROPERTIES")};405info->${ext.field("props")}.pNext = props.pNext;406props.pNext = &info->${ext.field("props")};407}408</%helpers:guard>409%endif410%endfor411412// note: setting up local VkPhysicalDeviceProperties2.413screen->vk.GetPhysicalDeviceProperties2(screen->pdev, &props);414}415416// enable the extensions if they match the conditions given by ext.enable_conds417if (screen->vk.GetPhysicalDeviceProperties2) {418%for ext in extensions:419<%helpers:guard ext="${ext}">420<%421conditions = ""422if ext.enable_conds:423for cond in ext.enable_conds:424cond = cond.replace("$feats", "info->" + ext.field("feats"))425cond = cond.replace("$props", "info->" + ext.field("props"))426conditions += "&& (" + cond + ")\\n"427conditions = conditions.strip()428%>\429info->have_${ext.name_with_vendor()} |= support_${ext.name_with_vendor()}430${conditions};431</%helpers:guard>432%endfor433}434435// generate extension list436num_extensions = 0;437438%for ext in extensions:439<%helpers:guard ext="${ext}">440if (info->have_${ext.name_with_vendor()}) {441info->extensions[num_extensions++] = "${ext.name}";442%if ext.is_required:443} else {444debug_printf("ZINK: ${ext.name} required!\\n");445goto fail;446%endif447}448</%helpers:guard>449%endfor450451info->num_extensions = num_extensions;452453return true;454455fail:456return false;457}458459void460zink_verify_device_extensions(struct zink_screen *screen)461{462%for ext in extensions:463%if registry.in_registry(ext.name):464if (screen->info.have_${ext.name_with_vendor()}) {465%for cmd in registry.get_registry_entry(ext.name).device_commands:466if (!screen->vk.${cmd.lstrip("vk")}) {467#ifndef NDEBUG468screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")};469#else470screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded;471#endif472}473%endfor474}475%endif476%endfor477}478479#ifndef NDEBUG480/* generated stub functions */481## remember the stub functions that are already generated482<% generated_funcs = set() %>483484%for ext in extensions:485%if registry.in_registry(ext.name):486%for cmd in registry.get_registry_entry(ext.name).device_commands:487##488## some functions are added by multiple extensions, which creates duplication489## and thus redefinition of stubs (eg. vkCmdPushDescriptorSetWithTemplateKHR)490##491%if cmd in generated_funcs:492<% continue %>493%else:494<% generated_funcs.add(cmd) %>495%endif496void497zink_stub_${cmd.lstrip("vk")}()498{499mesa_loge("ZINK: ${cmd} is not loaded properly!");500abort();501}502%endfor503%endif504%endfor505#endif506"""507508509def replace_code(code: str, replacement: dict):510for (k, v) in replacement.items():511code = code.replace(k, v)512513return code514515516if __name__ == "__main__":517try:518header_path = sys.argv[1]519impl_path = sys.argv[2]520vkxml_path = sys.argv[3]521522header_path = path.abspath(header_path)523impl_path = path.abspath(impl_path)524vkxml_path = path.abspath(vkxml_path)525except:526print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0])527exit(1)528529registry = ExtensionRegistry(vkxml_path)530531extensions = EXTENSIONS532versions = VERSIONS533replacement = REPLACEMENTS534535# Perform extension validation and set core_since for the extension if available536error_count = 0537for ext in extensions:538if not registry.in_registry(ext.name):539# disable validation for nonstandard extensions540if ext.is_nonstandard:541continue542543error_count += 1544print("The extension {} is not registered in vk.xml - a typo?".format(ext.name))545continue546547entry = registry.get_registry_entry(ext.name)548549if entry.ext_type != "device":550error_count += 1551print("The extension {} is {} extension - expected a device extension.".format(ext.name, entry.ext_type))552continue553554if ext.has_features:555if not (entry.features_struct and ext.physical_device_struct("Features") == entry.features_struct):556error_count += 1557print("The extension {} does not provide a features struct.".format(ext.name))558559if ext.has_properties:560if not (entry.properties_struct and ext.physical_device_struct("Properties") == entry.properties_struct):561error_count += 1562print("The extension {} does not provide a properties struct.".format(ext.name))563print(entry.properties_struct, ext.physical_device_struct("Properties"))564565if entry.promoted_in:566ext.core_since = Version((*entry.promoted_in, 0))567568if error_count > 0:569print("zink_device_info.py: Found {} error(s) in total. Quitting.".format(error_count))570exit(1)571572lookup = TemplateLookup()573lookup.put_string("helpers", include_template)574575with open(header_path, "w") as header_file:576header = Template(header_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip()577header = replace_code(header, replacement)578print(header, file=header_file)579580with open(impl_path, "w") as impl_file:581impl = Template(impl_code, lookup=lookup).render(extensions=extensions, versions=versions, registry=registry).strip()582impl = replace_code(impl, replacement)583print(impl, file=impl_file)584585586