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 os import path 28from xml.etree import ElementTree 29from zink_extensions import Extension,Layer,ExtensionRegistry,Version 30import sys 31 32# constructor: Extension(name, conditions=[], nonstandard=False) 33# The attributes: 34# - conditions: If the extension is provided by the Vulkan implementation, then 35# these are the extra conditions needed to enable the extension. 36# - nonstandard: Disables validation (cross-checking with vk.xml) if True. 37EXTENSIONS = [ 38 Extension("VK_EXT_debug_utils"), 39 Extension("VK_KHR_get_physical_device_properties2"), 40 Extension("VK_KHR_external_memory_capabilities"), 41 Extension("VK_MVK_moltenvk", 42 nonstandard=True), 43 Extension("VK_KHR_surface"), 44 Extension("VK_EXT_headless_surface"), 45 Extension("VK_KHR_wayland_surface"), 46 Extension("VK_KHR_xcb_surface", 47 conditions=["!instance_info->disable_xcb_surface"]), 48 Extension("VK_KHR_win32_surface"), 49] 50 51# constructor: Layer(name, conditions=[]) 52# - conditions: See documentation of EXTENSIONS. 53LAYERS = [ 54 # if we have debug_util, allow a validation layer to be added. 55 Layer("VK_LAYER_KHRONOS_validation", 56 conditions=["zink_debug & ZINK_DEBUG_VALIDATION"]), 57 Layer("VK_LAYER_LUNARG_standard_validation", 58 conditions=["zink_debug & ZINK_DEBUG_VALIDATION", "!have_layer_KHRONOS_validation"]), 59] 60 61REPLACEMENTS = { 62 "VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES2_EXTENSION_NAME" : "VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME" 63} 64 65header_code = """ 66#ifndef ZINK_INSTANCE_H 67#define ZINK_INSTANCE_H 68 69#include "os/os_process.h" 70 71#include <vulkan/vulkan.h> 72 73#if defined(__APPLE__) 74// Source of MVK_VERSION 75#include "MoltenVK/vk_mvk_moltenvk.h" 76#endif 77 78struct pipe_screen; 79struct zink_screen; 80 81struct zink_instance_info { 82 uint32_t loader_version; 83 bool disable_xcb_surface; 84 85%for ext in extensions: 86 bool have_${ext.name_with_vendor()}; 87%endfor 88 89%for layer in layers: 90 bool have_layer_${layer.pure_name()}; 91%endfor 92}; 93 94bool 95zink_create_instance(struct zink_screen *screen); 96 97void 98zink_verify_instance_extensions(struct zink_screen *screen); 99 100/* stub functions that get inserted into the dispatch table if they are not 101 * properly loaded. 102 */ 103%for ext in extensions: 104%if registry.in_registry(ext.name): 105%for cmd in registry.get_registry_entry(ext.name).instance_commands: 106void zink_stub_${cmd.lstrip("vk")}(void); 107%endfor 108%for cmd in registry.get_registry_entry(ext.name).pdevice_commands: 109void zink_stub_${cmd.lstrip("vk")}(void); 110%endfor 111%endif 112%endfor 113 114struct pipe_screen; 115struct pipe_resource; 116 117#endif 118""" 119 120impl_code = """ 121#include "vk_enum_to_str.h" 122#include "zink_instance.h" 123#include "zink_screen.h" 124 125bool 126zink_create_instance(struct zink_screen *screen) 127{ 128 struct zink_instance_info *instance_info = &screen->instance_info; 129 130 /* reserve one slot for MoltenVK */ 131 const char *layers[${len(layers) + 1}] = {0}; 132 uint32_t num_layers = 0; 133 134 const char *extensions[${len(extensions) + 1}] = {0}; 135 uint32_t num_extensions = 0; 136 137%for ext in extensions: 138 bool have_${ext.name_with_vendor()} = false; 139%endfor 140 141%for layer in layers: 142 bool have_layer_${layer.pure_name()} = false; 143%endfor 144 145#if defined(MVK_VERSION) 146 bool have_moltenvk_layer = false; 147#endif 148 149 GET_PROC_ADDR_INSTANCE_LOCAL(screen, NULL, EnumerateInstanceExtensionProperties); 150 GET_PROC_ADDR_INSTANCE_LOCAL(screen, NULL, EnumerateInstanceLayerProperties); 151 if (!vk_EnumerateInstanceExtensionProperties || 152 !vk_EnumerateInstanceLayerProperties) 153 return false; 154 155 // Build up the extensions from the reported ones but only for the unnamed layer 156 uint32_t extension_count = 0; 157 if (vk_EnumerateInstanceExtensionProperties(NULL, &extension_count, NULL) != VK_SUCCESS) { 158 mesa_loge("ZINK: vkEnumerateInstanceExtensionProperties failed"); 159 } else { 160 VkExtensionProperties *extension_props = malloc(extension_count * sizeof(VkExtensionProperties)); 161 if (extension_props) { 162 if (vk_EnumerateInstanceExtensionProperties(NULL, &extension_count, extension_props) != VK_SUCCESS) { 163 mesa_loge("ZINK: vkEnumerateInstanceExtensionProperties failed"); 164 } else { 165 for (uint32_t i = 0; i < extension_count; i++) { 166 %for ext in extensions: 167 if (!strcmp(extension_props[i].extensionName, ${ext.extension_name_literal()})) { 168 have_${ext.name_with_vendor()} = true; 169 } 170 %endfor 171 } 172 } 173 free(extension_props); 174 } 175 } 176 177 // Build up the layers from the reported ones 178 uint32_t layer_count = 0; 179 180 if (vk_EnumerateInstanceLayerProperties(&layer_count, NULL) != VK_SUCCESS) { 181 mesa_loge("ZINK: vkEnumerateInstanceLayerProperties failed"); 182 } else { 183 VkLayerProperties *layer_props = malloc(layer_count * sizeof(VkLayerProperties)); 184 if (layer_props) { 185 if (vk_EnumerateInstanceLayerProperties(&layer_count, layer_props) != VK_SUCCESS) { 186 mesa_loge("ZINK: vkEnumerateInstanceLayerProperties failed"); 187 } else { 188 for (uint32_t i = 0; i < layer_count; i++) { 189%for layer in layers: 190 if (!strcmp(layer_props[i].layerName, ${layer.extension_name_literal()})) { 191 have_layer_${layer.pure_name()} = true; 192 } 193%endfor 194#if defined(MVK_VERSION) 195 if (!strcmp(layer_props[i].layerName, "MoltenVK")) { 196 have_moltenvk_layer = true; 197 layers[num_layers++] = "MoltenVK"; 198 } 199#endif 200 } 201 } 202 free(layer_props); 203 } 204 } 205 206%for ext in extensions: 207<% 208 conditions = "" 209 if ext.enable_conds: 210 for cond in ext.enable_conds: 211 conditions += "&& (" + cond + ") " 212 conditions = conditions.strip() 213%>\ 214 if (have_${ext.name_with_vendor()} ${conditions}) { 215 instance_info->have_${ext.name_with_vendor()} = have_${ext.name_with_vendor()}; 216 extensions[num_extensions++] = ${ext.extension_name_literal()}; 217 } 218%endfor 219 220%for layer in layers: 221<% 222 conditions = "" 223 if layer.enable_conds: 224 for cond in layer.enable_conds: 225 conditions += "&& (" + cond + ") " 226 conditions = conditions.strip() 227%>\ 228 if (have_layer_${layer.pure_name()} ${conditions}) { 229 layers[num_layers++] = ${layer.extension_name_literal()}; 230 instance_info->have_layer_${layer.pure_name()} = true; 231 } 232%endfor 233 234 VkApplicationInfo ai = {0}; 235 ai.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 236 237 char proc_name[128]; 238 if (os_get_process_name(proc_name, ARRAY_SIZE(proc_name))) 239 ai.pApplicationName = proc_name; 240 else 241 ai.pApplicationName = "unknown"; 242 243 ai.pEngineName = "mesa zink"; 244 ai.apiVersion = instance_info->loader_version; 245 246 VkInstanceCreateInfo ici = {0}; 247 ici.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 248 ici.pApplicationInfo = &ai; 249 ici.ppEnabledExtensionNames = extensions; 250 ici.enabledExtensionCount = num_extensions; 251 ici.ppEnabledLayerNames = layers; 252 ici.enabledLayerCount = num_layers; 253 254 GET_PROC_ADDR_INSTANCE_LOCAL(screen, NULL, CreateInstance); 255 assert(vk_CreateInstance); 256 257 VkResult err = vk_CreateInstance(&ici, NULL, &screen->instance); 258 if (err != VK_SUCCESS) { 259 mesa_loge("ZINK: vkCreateInstance failed (%s)", vk_Result_to_str(err)); 260 return false; 261 } 262 263 return true; 264} 265 266void 267zink_verify_instance_extensions(struct zink_screen *screen) 268{ 269%for ext in extensions: 270%if registry.in_registry(ext.name): 271%if ext.platform_guard: 272#ifdef ${ext.platform_guard} 273%endif 274 if (screen->instance_info.have_${ext.name_with_vendor()}) { 275%for cmd in registry.get_registry_entry(ext.name).instance_commands: 276 if (!screen->vk.${cmd.lstrip("vk")}) { 277#ifndef NDEBUG 278 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")}; 279#else 280 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded; 281#endif 282 } 283%endfor 284%for cmd in registry.get_registry_entry(ext.name).pdevice_commands: 285 if (!screen->vk.${cmd.lstrip("vk")}) { 286#ifndef NDEBUG 287 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_${cmd.lstrip("vk")}; 288#else 289 screen->vk.${cmd.lstrip("vk")} = (PFN_${cmd})zink_stub_function_not_loaded; 290#endif 291 } 292%endfor 293 } 294%endif 295%if ext.platform_guard: 296#endif 297%endif 298%endfor 299} 300 301#ifndef NDEBUG 302/* generated stub functions */ 303## see zink_device_info.py for why this is needed 304<% generated_funcs = set() %> 305 306%for ext in extensions: 307%if registry.in_registry(ext.name): 308%for cmd in registry.get_registry_entry(ext.name).instance_commands + registry.get_registry_entry(ext.name).pdevice_commands: 309%if cmd in generated_funcs: 310 <% continue %> 311%else: 312 <% generated_funcs.add(cmd) %> 313%endif 314%if ext.platform_guard: 315#ifdef ${ext.platform_guard} 316%endif 317void 318zink_stub_${cmd.lstrip("vk")}() 319{ 320 mesa_loge("ZINK: ${cmd} is not loaded properly!"); 321 abort(); 322} 323%if ext.platform_guard: 324#endif 325%endif 326%endfor 327%endif 328%endfor 329 330#endif 331""" 332 333 334def replace_code(code: str, replacement: dict): 335 for (k, v) in replacement.items(): 336 code = code.replace(k, v) 337 338 return code 339 340 341if __name__ == "__main__": 342 try: 343 header_path = sys.argv[1] 344 impl_path = sys.argv[2] 345 vkxml_path = sys.argv[3] 346 347 header_path = path.abspath(header_path) 348 impl_path = path.abspath(impl_path) 349 vkxml_path = path.abspath(vkxml_path) 350 except: 351 print("usage: %s <path to .h> <path to .c> <path to vk.xml>" % sys.argv[0]) 352 exit(1) 353 354 registry = ExtensionRegistry(vkxml_path) 355 356 extensions = EXTENSIONS 357 layers = LAYERS 358 replacement = REPLACEMENTS 359 360 # Perform extension validation and set core_since for the extension if available 361 error_count = 0 362 for ext in extensions: 363 if not registry.in_registry(ext.name): 364 # disable validation for nonstandard extensions 365 if ext.is_nonstandard: 366 continue 367 368 error_count += 1 369 print("The extension {} is not registered in vk.xml - a typo?".format(ext.name)) 370 continue 371 372 entry = registry.get_registry_entry(ext.name) 373 374 if entry.ext_type != "instance": 375 error_count += 1 376 print("The extension {} is {} extension - expected an instance extension.".format(ext.name, entry.ext_type)) 377 continue 378 379 if entry.promoted_in: 380 ext.core_since = Version((*entry.promoted_in, 0)) 381 382 if entry.platform_guard: 383 ext.platform_guard = entry.platform_guard 384 385 if error_count > 0: 386 print("zink_instance.py: Found {} error(s) in total. Quitting.".format(error_count)) 387 exit(1) 388 389 with open(header_path, "w") as header_file: 390 header = Template(header_code).render(extensions=extensions, layers=layers, registry=registry).strip() 391 header = replace_code(header, replacement) 392 print(header, file=header_file) 393 394 with open(impl_path, "w") as impl_file: 395 impl = Template(impl_code).render(extensions=extensions, layers=layers, registry=registry).strip() 396 impl = replace_code(impl, replacement) 397 print(impl, file=impl_file) 398