From a36938d354a65b709f8f322d004478e1aeca1a19 Mon Sep 17 00:00:00 2001 From: Charles Giessen Date: Mon, 15 Sep 2025 10:20:33 -0500 Subject: scripts: Move generators into generator folder --- scripts/generators/mock_icd_generator.py | 1635 ++++++++++++++++++ .../vulkan_tools_helper_file_generator.py | 1240 ++++++++++++++ scripts/generators/vulkaninfo_generator.py | 1729 ++++++++++++++++++++ scripts/kvt_genvk.py | 6 +- scripts/mock_icd_generator.py | 1635 ------------------ scripts/vulkan_tools_helper_file_generator.py | 1240 -------------- scripts/vulkaninfo_generator.py | 1729 -------------------- 7 files changed, 4607 insertions(+), 4607 deletions(-) create mode 100644 scripts/generators/mock_icd_generator.py create mode 100644 scripts/generators/vulkan_tools_helper_file_generator.py create mode 100644 scripts/generators/vulkaninfo_generator.py delete mode 100644 scripts/mock_icd_generator.py delete mode 100644 scripts/vulkan_tools_helper_file_generator.py delete mode 100644 scripts/vulkaninfo_generator.py (limited to 'scripts') diff --git a/scripts/generators/mock_icd_generator.py b/scripts/generators/mock_icd_generator.py new file mode 100644 index 00000000..f64f4af0 --- /dev/null +++ b/scripts/generators/mock_icd_generator.py @@ -0,0 +1,1635 @@ +#!/usr/bin/python3 -i +# +# Copyright (c) 2015-2025 The Khronos Group Inc. +# Copyright (c) 2015-2025 Valve Corporation +# Copyright (c) 2015-2025 LunarG, Inc. +# Copyright (c) 2015-2025 Google Inc. +# Copyright (c) 2023-2025 RasterGrid Kft. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Tobin Ehlis +# +# This script generates a Mock ICD that intercepts almost all Vulkan +# functions. That layer is not intended to be useful or even compilable +# in its initial state. Rather it's intended to be a starting point that +# can be copied and customized to assist in creation of a new layer. + +import os,re,sys +from generator import * +from common_codegen import * + +CUSTOM_C_INTERCEPTS = { +'vkCreateInstance': ''' + // TODO: If loader ver <=4 ICD must fail with VK_ERROR_INCOMPATIBLE_DRIVER for all vkCreateInstance calls with + // apiVersion set to > Vulkan 1.0 because the loader is still at interface version <= 4. Otherwise, the + // ICD should behave as normal. + if (loader_interface_version <= 4) { + return VK_ERROR_INCOMPATIBLE_DRIVER; + } + *pInstance = (VkInstance)CreateDispObjHandle(); + for (auto& physical_device : physical_device_map[*pInstance]) + physical_device = (VkPhysicalDevice)CreateDispObjHandle(); + // TODO: If emulating specific device caps, will need to add intelligence here + return VK_SUCCESS; +''', +'vkDestroyInstance': ''' + if (instance) { + for (const auto physical_device : physical_device_map.at(instance)) { + display_map.erase(physical_device); + DestroyDispObjHandle((void*)physical_device); + } + physical_device_map.erase(instance); + DestroyDispObjHandle((void*)instance); + } +''', +'vkAllocateCommandBuffers': ''' + unique_lock_t lock(global_lock); + for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; ++i) { + pCommandBuffers[i] = (VkCommandBuffer)CreateDispObjHandle(); + command_pool_buffer_map[pAllocateInfo->commandPool].push_back(pCommandBuffers[i]); + } + return VK_SUCCESS; +''', +'vkFreeCommandBuffers': ''' + unique_lock_t lock(global_lock); + for (auto i = 0u; i < commandBufferCount; ++i) { + if (!pCommandBuffers[i]) { + continue; + } + + for (auto& pair : command_pool_buffer_map) { + auto& cbs = pair.second; + auto it = std::find(cbs.begin(), cbs.end(), pCommandBuffers[i]); + if (it != cbs.end()) { + cbs.erase(it); + } + } + + DestroyDispObjHandle((void*) pCommandBuffers[i]); + } +''', +'vkCreateCommandPool': ''' + unique_lock_t lock(global_lock); + *pCommandPool = (VkCommandPool)global_unique_handle++; + command_pool_map[device].insert(*pCommandPool); + return VK_SUCCESS; +''', +'vkDestroyCommandPool': ''' + // destroy command buffers for this pool + unique_lock_t lock(global_lock); + auto it = command_pool_buffer_map.find(commandPool); + if (it != command_pool_buffer_map.end()) { + for (auto& cb : it->second) { + DestroyDispObjHandle((void*) cb); + } + command_pool_buffer_map.erase(it); + } + command_pool_map[device].erase(commandPool); +''', +'vkEnumeratePhysicalDevices': ''' + VkResult result_code = VK_SUCCESS; + if (pPhysicalDevices) { + const auto return_count = (std::min)(*pPhysicalDeviceCount, icd_physical_device_count); + for (uint32_t i = 0; i < return_count; ++i) pPhysicalDevices[i] = physical_device_map.at(instance)[i]; + if (return_count < icd_physical_device_count) result_code = VK_INCOMPLETE; + *pPhysicalDeviceCount = return_count; + } else { + *pPhysicalDeviceCount = icd_physical_device_count; + } + return result_code; +''', +'vkCreateDevice': ''' + *pDevice = (VkDevice)CreateDispObjHandle(); + // TODO: If emulating specific device caps, will need to add intelligence here + return VK_SUCCESS; +''', +'vkDestroyDevice': ''' + unique_lock_t lock(global_lock); + // First destroy sub-device objects + // Destroy Queues + for (auto queue_family_map_pair : queue_map[device]) { + for (auto index_queue_pair : queue_map[device][queue_family_map_pair.first]) { + DestroyDispObjHandle((void*)index_queue_pair.second); + } + } + + for (auto& cp : command_pool_map[device]) { + for (auto& cb : command_pool_buffer_map[cp]) { + DestroyDispObjHandle((void*) cb); + } + command_pool_buffer_map.erase(cp); + } + command_pool_map[device].clear(); + + queue_map.erase(device); + buffer_map.erase(device); + image_memory_size_map.erase(device); + // Now destroy device + DestroyDispObjHandle((void*)device); + // TODO: If emulating specific device caps, will need to add intelligence here +''', +'vkGetDeviceQueue': ''' + unique_lock_t lock(global_lock); + auto queue = queue_map[device][queueFamilyIndex][queueIndex]; + if (queue) { + *pQueue = queue; + } else { + *pQueue = queue_map[device][queueFamilyIndex][queueIndex] = (VkQueue)CreateDispObjHandle(); + } + // TODO: If emulating specific device caps, will need to add intelligence here + return; +''', +'vkGetDeviceQueue2': ''' + GetDeviceQueue(device, pQueueInfo->queueFamilyIndex, pQueueInfo->queueIndex, pQueue); + // TODO: Add further support for GetDeviceQueue2 features +''', +'vkEnumerateInstanceLayerProperties': ''' + return VK_SUCCESS; +''', +'vkEnumerateInstanceVersion': ''' + *pApiVersion = VK_HEADER_VERSION_COMPLETE; + return VK_SUCCESS; +''', +'vkEnumerateDeviceLayerProperties': ''' + return VK_SUCCESS; +''', +'vkEnumerateInstanceExtensionProperties': ''' + // If requesting number of extensions, return that + if (!pLayerName) { + if (!pProperties) { + *pPropertyCount = (uint32_t)instance_extension_map.size(); + } else { + uint32_t i = 0; + for (const auto &name_ver_pair : instance_extension_map) { + if (i == *pPropertyCount) { + break; + } + std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName)); + pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0; + pProperties[i].specVersion = name_ver_pair.second; + ++i; + } + if (i != instance_extension_map.size()) { + return VK_INCOMPLETE; + } + } + } + // If requesting extension properties, fill in data struct for number of extensions + return VK_SUCCESS; +''', +'vkEnumerateDeviceExtensionProperties': ''' + // If requesting number of extensions, return that + if (!pLayerName) { + if (!pProperties) { + *pPropertyCount = (uint32_t)device_extension_map.size(); + } else { + uint32_t i = 0; + for (const auto &name_ver_pair : device_extension_map) { + if (i == *pPropertyCount) { + break; + } + std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName)); + pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0; + pProperties[i].specVersion = name_ver_pair.second; + ++i; + } + *pPropertyCount = i; + if (i != device_extension_map.size()) { + return VK_INCOMPLETE; + } + } + } + // If requesting extension properties, fill in data struct for number of extensions + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfacePresentModesKHR': ''' + // Currently always say that all present modes are supported + if (!pPresentModes) { + *pPresentModeCount = 6; + } else { + if (*pPresentModeCount >= 6) pPresentModes[5] = VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR; + if (*pPresentModeCount >= 5) pPresentModes[4] = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR; + if (*pPresentModeCount >= 4) pPresentModes[3] = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + if (*pPresentModeCount >= 3) pPresentModes[2] = VK_PRESENT_MODE_FIFO_KHR; + if (*pPresentModeCount >= 2) pPresentModes[1] = VK_PRESENT_MODE_MAILBOX_KHR; + if (*pPresentModeCount >= 1) pPresentModes[0] = VK_PRESENT_MODE_IMMEDIATE_KHR; + *pPresentModeCount = *pPresentModeCount < 6 ? *pPresentModeCount : 6; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfaceFormatsKHR': ''' + // Currently always say that RGBA8 & BGRA8 are supported + if (!pSurfaceFormats) { + *pSurfaceFormatCount = 2; + } else { + if (*pSurfaceFormatCount >= 2) { + pSurfaceFormats[1].format = VK_FORMAT_R8G8B8A8_UNORM; + pSurfaceFormats[1].colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + } + if (*pSurfaceFormatCount >= 1) { + pSurfaceFormats[0].format = VK_FORMAT_B8G8R8A8_UNORM; + pSurfaceFormats[0].colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + } + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfaceFormats2KHR': ''' + // Currently always say that RGBA8 & BGRA8 are supported + if (!pSurfaceFormats) { + *pSurfaceFormatCount = 2; + } else { + if (*pSurfaceFormatCount >= 2) { + pSurfaceFormats[1].pNext = nullptr; + pSurfaceFormats[1].surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM; + pSurfaceFormats[1].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + } + if (*pSurfaceFormatCount >= 1) { + pSurfaceFormats[1].pNext = nullptr; + pSurfaceFormats[0].surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; + pSurfaceFormats[0].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + } + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfaceSupportKHR': ''' + // Currently say that all surface/queue combos are supported + *pSupported = VK_TRUE; + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfaceCapabilitiesKHR': ''' + // In general just say max supported is available for requested surface + pSurfaceCapabilities->minImageCount = 1; + pSurfaceCapabilities->maxImageCount = 0; + pSurfaceCapabilities->currentExtent.width = 0xFFFFFFFF; + pSurfaceCapabilities->currentExtent.height = 0xFFFFFFFF; + pSurfaceCapabilities->minImageExtent.width = 1; + pSurfaceCapabilities->minImageExtent.height = 1; + pSurfaceCapabilities->maxImageExtent.width = 0xFFFF; + pSurfaceCapabilities->maxImageExtent.height = 0xFFFF; + pSurfaceCapabilities->maxImageArrayLayers = 128; + pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | + VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | + VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | + VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | + VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; + pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | + VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR | + VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR | + VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; + pSurfaceCapabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_STORAGE_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | + VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSurfaceCapabilities2KHR': ''' + GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, pSurfaceInfo->surface, &pSurfaceCapabilities->surfaceCapabilities); + + auto *present_mode_compatibility = lvl_find_mod_in_chain(pSurfaceCapabilities->pNext); + if (present_mode_compatibility) { + if (!present_mode_compatibility->pPresentModes) { + present_mode_compatibility->presentModeCount = 3; + } else { + // arbitrary + present_mode_compatibility->pPresentModes[0] = VK_PRESENT_MODE_IMMEDIATE_KHR; + present_mode_compatibility->pPresentModes[1] = VK_PRESENT_MODE_FIFO_KHR; + present_mode_compatibility->pPresentModes[2] = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR; + } + } + return VK_SUCCESS; +''', +'vkGetInstanceProcAddr': ''' + if (!negotiate_loader_icd_interface_called) { + loader_interface_version = 0; + } + const auto &item = name_to_funcptr_map.find(pName); + if (item != name_to_funcptr_map.end()) { + return reinterpret_cast(item->second); + } + // Mock should intercept all functions so if we get here just return null + return nullptr; +''', +'vkGetDeviceProcAddr': ''' + return GetInstanceProcAddr(nullptr, pName); +''', +'vkGetPhysicalDeviceMemoryProperties': ''' + pMemoryProperties->memoryTypeCount = 6; + // Host visible Coherent + pMemoryProperties->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + pMemoryProperties->memoryTypes[0].heapIndex = 0; + // Host visible Cached + pMemoryProperties->memoryTypes[1].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + pMemoryProperties->memoryTypes[1].heapIndex = 0; + // Device local and Host visible + pMemoryProperties->memoryTypes[2].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + pMemoryProperties->memoryTypes[2].heapIndex = 1; + // Device local lazily + pMemoryProperties->memoryTypes[3].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; + pMemoryProperties->memoryTypes[3].heapIndex = 1; + // Device local protected + pMemoryProperties->memoryTypes[4].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_PROTECTED_BIT; + pMemoryProperties->memoryTypes[4].heapIndex = 1; + // Device local only + pMemoryProperties->memoryTypes[5].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + pMemoryProperties->memoryTypes[5].heapIndex = 1; + pMemoryProperties->memoryHeapCount = 2; + pMemoryProperties->memoryHeaps[0].flags = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT; + pMemoryProperties->memoryHeaps[0].size = 8000000000; + pMemoryProperties->memoryHeaps[1].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; + pMemoryProperties->memoryHeaps[1].size = 8000000000; +''', +'vkGetPhysicalDeviceMemoryProperties2KHR': ''' + GetPhysicalDeviceMemoryProperties(physicalDevice, &pMemoryProperties->memoryProperties); +''', +'vkGetPhysicalDeviceQueueFamilyProperties': ''' + if (pQueueFamilyProperties) { + std::vector props2(*pQueueFamilyPropertyCount, { + VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR}); + GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount, props2.data()); + for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) { + pQueueFamilyProperties[i] = props2[i].queueFamilyProperties; + } + } else { + GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount, nullptr); + } +''', +'vkGetPhysicalDeviceQueueFamilyProperties2KHR': ''' + if (pQueueFamilyProperties) { + if (*pQueueFamilyPropertyCount >= 1) { + auto props = &pQueueFamilyProperties[0].queueFamilyProperties; + props->queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT + | VK_QUEUE_SPARSE_BINDING_BIT | VK_QUEUE_PROTECTED_BIT; + props->queueCount = 1; + props->timestampValidBits = 16; + props->minImageTransferGranularity = {1,1,1}; + } + if (*pQueueFamilyPropertyCount >= 2) { + auto props = &pQueueFamilyProperties[1].queueFamilyProperties; + props->queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT | VK_QUEUE_VIDEO_DECODE_BIT_KHR; + props->queueCount = 1; + props->timestampValidBits = 16; + props->minImageTransferGranularity = {1,1,1}; + + auto status_query_props = lvl_find_mod_in_chain(pQueueFamilyProperties[1].pNext); + if (status_query_props) { + status_query_props->queryResultStatusSupport = VK_TRUE; + } + auto video_props = lvl_find_mod_in_chain(pQueueFamilyProperties[1].pNext); + if (video_props) { + video_props->videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR + | VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR + | VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR; + } + } + if (*pQueueFamilyPropertyCount >= 3) { + auto props = &pQueueFamilyProperties[2].queueFamilyProperties; + props->queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT | VK_QUEUE_VIDEO_ENCODE_BIT_KHR; + props->queueCount = 1; + props->timestampValidBits = 16; + props->minImageTransferGranularity = {1,1,1}; + + auto status_query_props = lvl_find_mod_in_chain(pQueueFamilyProperties[2].pNext); + if (status_query_props) { + status_query_props->queryResultStatusSupport = VK_TRUE; + } + auto video_props = lvl_find_mod_in_chain(pQueueFamilyProperties[2].pNext); + if (video_props) { + video_props->videoCodecOperations = VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR + | VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR + | VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR; + } + } + if (*pQueueFamilyPropertyCount > 3) { + *pQueueFamilyPropertyCount = 3; + } + } else { + *pQueueFamilyPropertyCount = 3; + } +''', +'vkGetPhysicalDeviceFeatures': ''' + uint32_t num_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32); + VkBool32 *bool_array = &pFeatures->robustBufferAccess; + SetBoolArrayTrue(bool_array, num_bools); +''', +'vkGetPhysicalDeviceFeatures2KHR': ''' + GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features); + uint32_t num_bools = 0; // Count number of VkBool32s in extension structs + VkBool32* feat_bools = nullptr; + auto vk_1_1_features = lvl_find_mod_in_chain(pFeatures->pNext); + if (vk_1_1_features) { + vk_1_1_features->protectedMemory = VK_TRUE; + } + auto vk_1_3_features = lvl_find_mod_in_chain(pFeatures->pNext); + if (vk_1_3_features) { + vk_1_3_features->synchronization2 = VK_TRUE; + } + auto prot_features = lvl_find_mod_in_chain(pFeatures->pNext); + if (prot_features) { + prot_features->protectedMemory = VK_TRUE; + } + auto sync2_features = lvl_find_mod_in_chain(pFeatures->pNext); + if (sync2_features) { + sync2_features->synchronization2 = VK_TRUE; + } + auto video_maintenance1_features = lvl_find_mod_in_chain(pFeatures->pNext); + if (video_maintenance1_features) { + video_maintenance1_features->videoMaintenance1 = VK_TRUE; + } + const auto *desc_idx_features = lvl_find_in_chain(pFeatures->pNext); + if (desc_idx_features) { + const auto bool_size = sizeof(VkPhysicalDeviceDescriptorIndexingFeaturesEXT) - offsetof(VkPhysicalDeviceDescriptorIndexingFeaturesEXT, shaderInputAttachmentArrayDynamicIndexing); + num_bools = bool_size/sizeof(VkBool32); + feat_bools = (VkBool32*)&desc_idx_features->shaderInputAttachmentArrayDynamicIndexing; + SetBoolArrayTrue(feat_bools, num_bools); + } + const auto *blendop_features = lvl_find_in_chain(pFeatures->pNext); + if (blendop_features) { + const auto bool_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT) - offsetof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT, advancedBlendCoherentOperations); + num_bools = bool_size/sizeof(VkBool32); + feat_bools = (VkBool32*)&blendop_features->advancedBlendCoherentOperations; + SetBoolArrayTrue(feat_bools, num_bools); + } + const auto *host_image_copy_features = lvl_find_in_chain(pFeatures->pNext); + if (host_image_copy_features) { + feat_bools = (VkBool32*)&host_image_copy_features->hostImageCopy; + SetBoolArrayTrue(feat_bools, 1); + } +''', +'vkGetPhysicalDeviceFormatProperties': ''' + if (VK_FORMAT_UNDEFINED == format) { + *pFormatProperties = { 0x0, 0x0, 0x0 }; + } else { + // Default to a color format, skip DS bit + *pFormatProperties = { 0x00FFFDFF, 0x00FFFDFF, 0x00FFFDFF }; + switch (format) { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + // Don't set color bits for DS formats + *pFormatProperties = { 0x00FFFE7F, 0x00FFFE7F, 0x00FFFE7F }; + break; + case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: + case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: + case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: + case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: + case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: + // Set decode/encode bits for these formats + *pFormatProperties = { 0x1EFFFDFF, 0x1EFFFDFF, 0x00FFFDFF }; + break; + default: + break; + } + } +''', +'vkGetPhysicalDeviceFormatProperties2KHR': ''' + GetPhysicalDeviceFormatProperties(physicalDevice, format, &pFormatProperties->formatProperties); + VkFormatProperties3KHR *props_3 = lvl_find_mod_in_chain(pFormatProperties->pNext); + if (props_3) { + props_3->linearTilingFeatures = pFormatProperties->formatProperties.linearTilingFeatures; + props_3->optimalTilingFeatures = pFormatProperties->formatProperties.optimalTilingFeatures; + props_3->bufferFeatures = pFormatProperties->formatProperties.bufferFeatures; + props_3->optimalTilingFeatures |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT; + } +''', +'vkGetPhysicalDeviceImageFormatProperties': ''' + // A hardcoded unsupported format + if (format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) { + return VK_ERROR_FORMAT_NOT_SUPPORTED; + } + + // TODO: Just hard-coding some values for now + // TODO: If tiling is linear, limit the mips, levels, & sample count + if (VK_IMAGE_TILING_LINEAR == tiling) { + *pImageFormatProperties = { { 4096, 4096, 256 }, 1, 1, VK_SAMPLE_COUNT_1_BIT, 4294967296 }; + } else { + // We hard-code support for all sample counts except 64 bits. + *pImageFormatProperties = { { 4096, 4096, 256 }, 12, 256, 0x7F & ~VK_SAMPLE_COUNT_64_BIT, 4294967296 }; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceImageFormatProperties2KHR': ''' + auto *external_image_prop = lvl_find_mod_in_chain(pImageFormatProperties->pNext); + auto *external_image_format = lvl_find_in_chain(pImageFormatInfo->pNext); + if (external_image_prop && external_image_format) { + external_image_prop->externalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; + external_image_prop->externalMemoryProperties.compatibleHandleTypes = external_image_format->handleType; + } + + GetPhysicalDeviceImageFormatProperties(physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling, pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties); + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceSparseImageFormatProperties': ''' + if (!pProperties) { + *pPropertyCount = 1; + } else { + // arbitrary + pProperties->imageGranularity = {4, 4, 4}; + pProperties->flags = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT; + switch (format) { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D32_SFLOAT: + pProperties->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; + break; + case VK_FORMAT_S8_UINT: + pProperties->aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; + break; + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + pProperties->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; + break; + default: + pProperties->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + break; + } + } +''', +'vkGetPhysicalDeviceSparseImageFormatProperties2KHR': ''' + if (pPropertyCount && pProperties) { + GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling, pPropertyCount, &pProperties->properties); + } else { + GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling, pPropertyCount, nullptr); + } +''', +'vkGetPhysicalDeviceProperties': ''' + pProperties->apiVersion = VK_HEADER_VERSION_COMPLETE; + pProperties->driverVersion = 1; + pProperties->vendorID = 0xba5eba11; + pProperties->deviceID = 0xf005ba11; + pProperties->deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; + //std::string devName = "Vulkan Mock Device"; + strcpy(pProperties->deviceName, "Vulkan Mock Device"); + pProperties->pipelineCacheUUID[0] = 18; + pProperties->limits = SetLimits(&pProperties->limits); + pProperties->sparseProperties = { VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE }; +''', +'vkGetPhysicalDeviceProperties2KHR': ''' + // The only value that need to be set are those the Profile layer can't set + // see https://github.com/KhronosGroup/Vulkan-Profiles/issues/352 + // All values set are arbitrary + GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties); + + auto *props_11 = lvl_find_mod_in_chain(pProperties->pNext); + if (props_11) { + props_11->protectedNoFault = VK_FALSE; + } + + auto *props_12 = lvl_find_mod_in_chain(pProperties->pNext); + if (props_12) { + props_12->denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; + props_12->roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; + } + + auto *props_13 = lvl_find_mod_in_chain(pProperties->pNext); + if (props_13) { + props_13->storageTexelBufferOffsetSingleTexelAlignment = VK_TRUE; + props_13->uniformTexelBufferOffsetSingleTexelAlignment = VK_TRUE; + props_13->storageTexelBufferOffsetAlignmentBytes = 16; + props_13->uniformTexelBufferOffsetAlignmentBytes = 16; + } + + auto *protected_memory_props = lvl_find_mod_in_chain(pProperties->pNext); + if (protected_memory_props) { + protected_memory_props->protectedNoFault = VK_FALSE; + } + + auto *float_controls_props = lvl_find_mod_in_chain(pProperties->pNext); + if (float_controls_props) { + float_controls_props->denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; + float_controls_props->roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; + } + + auto *conservative_raster_props = lvl_find_mod_in_chain(pProperties->pNext); + if (conservative_raster_props) { + conservative_raster_props->primitiveOverestimationSize = 0.00195313f; + conservative_raster_props->conservativePointAndLineRasterization = VK_TRUE; + conservative_raster_props->degenerateTrianglesRasterized = VK_TRUE; + conservative_raster_props->degenerateLinesRasterized = VK_TRUE; + } + + auto *rt_pipeline_props = lvl_find_mod_in_chain(pProperties->pNext); + if (rt_pipeline_props) { + rt_pipeline_props->shaderGroupHandleSize = 32; + rt_pipeline_props->shaderGroupBaseAlignment = 64; + rt_pipeline_props->shaderGroupHandleCaptureReplaySize = 32; + } + + auto *rt_pipeline_nv_props = lvl_find_mod_in_chain(pProperties->pNext); + if (rt_pipeline_nv_props) { + rt_pipeline_nv_props->shaderGroupHandleSize = 32; + rt_pipeline_nv_props->shaderGroupBaseAlignment = 64; + } + + auto *texel_buffer_props = lvl_find_mod_in_chain(pProperties->pNext); + if (texel_buffer_props) { + texel_buffer_props->storageTexelBufferOffsetSingleTexelAlignment = VK_TRUE; + texel_buffer_props->uniformTexelBufferOffsetSingleTexelAlignment = VK_TRUE; + texel_buffer_props->storageTexelBufferOffsetAlignmentBytes = 16; + texel_buffer_props->uniformTexelBufferOffsetAlignmentBytes = 16; + } + + auto *descriptor_buffer_props = lvl_find_mod_in_chain(pProperties->pNext); + if (descriptor_buffer_props) { + descriptor_buffer_props->combinedImageSamplerDescriptorSingleArray = VK_TRUE; + descriptor_buffer_props->bufferlessPushDescriptors = VK_TRUE; + descriptor_buffer_props->allowSamplerImageViewPostSubmitCreation = VK_TRUE; + descriptor_buffer_props->descriptorBufferOffsetAlignment = 4; + } + + auto *mesh_shader_props = lvl_find_mod_in_chain(pProperties->pNext); + if (mesh_shader_props) { + mesh_shader_props->meshOutputPerVertexGranularity = 32; + mesh_shader_props->meshOutputPerPrimitiveGranularity = 32; + mesh_shader_props->prefersLocalInvocationVertexOutput = VK_TRUE; + mesh_shader_props->prefersLocalInvocationPrimitiveOutput = VK_TRUE; + mesh_shader_props->prefersCompactVertexOutput = VK_TRUE; + mesh_shader_props->prefersCompactPrimitiveOutput = VK_TRUE; + } + + auto *fragment_density_map2_props = lvl_find_mod_in_chain(pProperties->pNext); + if (fragment_density_map2_props) { + fragment_density_map2_props->subsampledLoads = VK_FALSE; + fragment_density_map2_props->subsampledCoarseReconstructionEarlyAccess = VK_FALSE; + fragment_density_map2_props->maxSubsampledArrayLayers = 2; + fragment_density_map2_props->maxDescriptorSetSubsampledSamplers = 1; + } + + auto *maintenance3_props = lvl_find_mod_in_chain(pProperties->pNext); + if (maintenance3_props) { + maintenance3_props->maxMemoryAllocationSize = 1073741824; + maintenance3_props->maxPerSetDescriptors = 1024; + } + + const uint32_t num_copy_layouts = 5; + const VkImageLayout HostCopyLayouts[]{ + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_GENERAL, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, + VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, + }; + + auto *host_image_copy_props = lvl_find_mod_in_chain(pProperties->pNext); + if (host_image_copy_props){ + if (host_image_copy_props->pCopyDstLayouts == nullptr) host_image_copy_props->copyDstLayoutCount = num_copy_layouts; + else { + uint32_t num_layouts = (std::min)(host_image_copy_props->copyDstLayoutCount, num_copy_layouts); + for (uint32_t i = 0; i < num_layouts; i++) { + host_image_copy_props->pCopyDstLayouts[i] = HostCopyLayouts[i]; + } + } + if (host_image_copy_props->pCopySrcLayouts == nullptr) host_image_copy_props->copySrcLayoutCount = num_copy_layouts; + else { + uint32_t num_layouts = (std::min)(host_image_copy_props->copySrcLayoutCount, num_copy_layouts); + for (uint32_t i = 0; i < num_layouts; i++) { + host_image_copy_props->pCopySrcLayouts[i] = HostCopyLayouts[i]; + } + } + } + + auto *driver_properties = lvl_find_mod_in_chain(pProperties->pNext); + if (driver_properties) { + std::strncpy(driver_properties->driverName, "Vulkan Mock Device", VK_MAX_DRIVER_NAME_SIZE); +#if defined(GIT_BRANCH_NAME) && defined(GIT_TAG_INFO) + std::strncpy(driver_properties->driverInfo, "Branch: " GIT_BRANCH_NAME " Tag Info: " GIT_TAG_INFO, VK_MAX_DRIVER_INFO_SIZE); +#else + std::strncpy(driver_properties->driverInfo, "Branch: --unknown-- Tag Info: --unknown--", VK_MAX_DRIVER_INFO_SIZE); +#endif + } + + auto *layered_properties = lvl_find_mod_in_chain(pProperties->pNext); + if (layered_properties) { + layered_properties->layeredApiCount = 1; + if (layered_properties->pLayeredApis) { + layered_properties->pLayeredApis[0] = VkPhysicalDeviceLayeredApiPropertiesKHR{ + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR, + nullptr, + 0xba5eba11, + 0xf005ba11, + VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR + }; + std::strncpy(layered_properties->pLayeredApis[0].deviceName, "Fake Driver", VK_MAX_PHYSICAL_DEVICE_NAME_SIZE); + } + } +''', +'vkGetPhysicalDeviceExternalSemaphoreProperties':''' + // Hard code support for all handle types and features + pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0x1F; + pExternalSemaphoreProperties->compatibleHandleTypes = 0x1F; + pExternalSemaphoreProperties->externalSemaphoreFeatures = 0x3; +''', +'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR':''' + GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); +''', +'vkGetPhysicalDeviceExternalFenceProperties':''' + // Hard-code support for all handle types and features + pExternalFenceProperties->exportFromImportedHandleTypes = 0xF; + pExternalFenceProperties->compatibleHandleTypes = 0xF; + pExternalFenceProperties->externalFenceFeatures = 0x3; +''', +'vkGetPhysicalDeviceExternalFencePropertiesKHR':''' + GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); +''', +'vkGetPhysicalDeviceExternalBufferProperties':''' + constexpr VkExternalMemoryHandleTypeFlags supported_flags = 0x1FF; + if (pExternalBufferInfo->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) { + // Can't have dedicated memory with AHB + pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; + pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = pExternalBufferInfo->handleType; + pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = pExternalBufferInfo->handleType; + } else if (pExternalBufferInfo->handleType & supported_flags) { + pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0x7; + pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = supported_flags; + pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = supported_flags; + } else { + pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0; + pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = 0; + // According to spec, handle type is always compatible with itself. Even if export/import + // not supported, it's important to properly implement self-compatibility property since + // application's control flow can rely on this. + pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = pExternalBufferInfo->handleType; + } +''', +'vkGetPhysicalDeviceExternalBufferPropertiesKHR':''' + GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); +''', +'vkGetBufferMemoryRequirements': ''' + // TODO: Just hard-coding reqs for now + pMemoryRequirements->size = 4096; + pMemoryRequirements->alignment = 1; + pMemoryRequirements->memoryTypeBits = 0xFFFF; + // Return a better size based on the buffer size from the create info. + unique_lock_t lock(global_lock); + auto d_iter = buffer_map.find(device); + if (d_iter != buffer_map.end()) { + auto iter = d_iter->second.find(buffer); + if (iter != d_iter->second.end()) { + pMemoryRequirements->size = ((iter->second.size + 4095) / 4096) * 4096; + } + } +''', +'vkGetBufferMemoryRequirements2KHR': ''' + GetBufferMemoryRequirements(device, pInfo->buffer, &pMemoryRequirements->memoryRequirements); +''', +'vkGetDeviceBufferMemoryRequirements': ''' + // TODO: Just hard-coding reqs for now + pMemoryRequirements->memoryRequirements.alignment = 1; + pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF; + + // Return a size based on the buffer size from the create info. + pMemoryRequirements->memoryRequirements.size = ((pInfo->pCreateInfo->size + 4095) / 4096) * 4096; +''', +'vkGetDeviceBufferMemoryRequirementsKHR': ''' + GetDeviceBufferMemoryRequirements(device, pInfo, pMemoryRequirements); +''', +'vkGetImageMemoryRequirements': ''' + pMemoryRequirements->size = 0; + pMemoryRequirements->alignment = 1; + + unique_lock_t lock(global_lock); + auto d_iter = image_memory_size_map.find(device); + if(d_iter != image_memory_size_map.end()){ + auto iter = d_iter->second.find(image); + if (iter != d_iter->second.end()) { + pMemoryRequirements->size = iter->second; + } + } + // Here we hard-code that the memory type at index 3 doesn't support this image. + pMemoryRequirements->memoryTypeBits = 0xFFFF & ~(0x1 << 3); +''', +'vkGetImageMemoryRequirements2KHR': ''' + GetImageMemoryRequirements(device, pInfo->image, &pMemoryRequirements->memoryRequirements); +''', +'vkGetDeviceImageMemoryRequirements': ''' + pMemoryRequirements->memoryRequirements.size = GetImageSizeFromCreateInfo(pInfo->pCreateInfo); + pMemoryRequirements->memoryRequirements.alignment = 1; + // Here we hard-code that the memory type at index 3 doesn't support this image. + pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF & ~(0x1 << 3); +''', +'vkGetDeviceImageMemoryRequirementsKHR': ''' + GetDeviceImageMemoryRequirements(device, pInfo, pMemoryRequirements); +''', +'vkMapMemory': ''' + unique_lock_t lock(global_lock); + if (VK_WHOLE_SIZE == size) { + if (allocated_memory_size_map.count(memory) != 0) + size = allocated_memory_size_map[memory] - offset; + else + size = 0x10000; + } + void* map_addr = malloc((size_t)size); + mapped_memory_map[memory].push_back(map_addr); + *ppData = map_addr; + return VK_SUCCESS; +''', +'vkMapMemory2KHR': ''' + return MapMemory(device, pMemoryMapInfo->memory, pMemoryMapInfo->offset, pMemoryMapInfo->size, pMemoryMapInfo->flags, ppData); +''', +'vkUnmapMemory': ''' + unique_lock_t lock(global_lock); + for (auto map_addr : mapped_memory_map[memory]) { + free(map_addr); + } + mapped_memory_map.erase(memory); +''', +'vkUnmapMemory2KHR': ''' + UnmapMemory(device, pMemoryUnmapInfo->memory); + return VK_SUCCESS; +''', +'vkGetImageSubresourceLayout': ''' + // Need safe values. Callers are computing memory offsets from pLayout, with no return code to flag failure. + *pLayout = VkSubresourceLayout(); // Default constructor zero values. +''', +'vkCreateSwapchainKHR': ''' + unique_lock_t lock(global_lock); + *pSwapchain = (VkSwapchainKHR)global_unique_handle++; + for(uint32_t i = 0; i < icd_swapchain_image_count; ++i){ + swapchain_image_map[*pSwapchain][i] = (VkImage)global_unique_handle++; + } + return VK_SUCCESS; +''', +'vkDestroySwapchainKHR': ''' + unique_lock_t lock(global_lock); + swapchain_image_map.clear(); +''', +'vkGetSwapchainImagesKHR': ''' + if (!pSwapchainImages) { + *pSwapchainImageCount = icd_swapchain_image_count; + } else { + unique_lock_t lock(global_lock); + for (uint32_t img_i = 0; img_i < (std::min)(*pSwapchainImageCount, icd_swapchain_image_count); ++img_i){ + pSwapchainImages[img_i] = swapchain_image_map.at(swapchain)[img_i]; + } + + if (*pSwapchainImageCount < icd_swapchain_image_count) return VK_INCOMPLETE; + else if (*pSwapchainImageCount > icd_swapchain_image_count) *pSwapchainImageCount = icd_swapchain_image_count; + } + return VK_SUCCESS; +''', +'vkAcquireNextImageKHR': ''' + *pImageIndex = 0; + return VK_SUCCESS; +''', +'vkAcquireNextImage2KHR': ''' + *pImageIndex = 0; + return VK_SUCCESS; +''', +'vkCreateBuffer': ''' + unique_lock_t lock(global_lock); + *pBuffer = (VkBuffer)global_unique_handle++; + buffer_map[device][*pBuffer] = { + pCreateInfo->size, + current_available_address + }; + current_available_address += pCreateInfo->size; + // Always align to next 64-bit pointer + const uint64_t alignment = current_available_address % 64; + if (alignment != 0) { + current_available_address += (64 - alignment); + } + return VK_SUCCESS; +''', +'vkDestroyBuffer': ''' + unique_lock_t lock(global_lock); + buffer_map[device].erase(buffer); +''', +'vkCreateImage': ''' + unique_lock_t lock(global_lock); + *pImage = (VkImage)global_unique_handle++; + image_memory_size_map[device][*pImage] = GetImageSizeFromCreateInfo(pCreateInfo); + return VK_SUCCESS; +''', +'vkDestroyImage': ''' + unique_lock_t lock(global_lock); + image_memory_size_map[device].erase(image); +''', +'vkEnumeratePhysicalDeviceGroupsKHR': ''' + if (!pPhysicalDeviceGroupProperties) { + *pPhysicalDeviceGroupCount = 1; + } else { + // arbitrary + pPhysicalDeviceGroupProperties->physicalDeviceCount = 1; + pPhysicalDeviceGroupProperties->physicalDevices[0] = physical_device_map.at(instance)[0]; + pPhysicalDeviceGroupProperties->subsetAllocation = VK_FALSE; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceMultisamplePropertiesEXT': ''' + if (pMultisampleProperties) { + // arbitrary + pMultisampleProperties->maxSampleLocationGridSize = {32, 32}; + } +''', +'vkGetPhysicalDeviceFragmentShadingRatesKHR': ''' + if (!pFragmentShadingRates) { + *pFragmentShadingRateCount = 1; + } else { + // arbitrary + pFragmentShadingRates->sampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT; + pFragmentShadingRates->fragmentSize = {8, 8}; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceCalibrateableTimeDomainsEXT': ''' + if (!pTimeDomains) { + *pTimeDomainCount = 1; + } else { + // arbitrary + *pTimeDomains = VK_TIME_DOMAIN_DEVICE_EXT; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceCalibrateableTimeDomainsKHR': ''' + if (!pTimeDomains) { + *pTimeDomainCount = 1; + } else { + // arbitrary + *pTimeDomains = VK_TIME_DOMAIN_DEVICE_KHR; + } + return VK_SUCCESS; +''', +'vkGetFenceWin32HandleKHR': ''' + *pHandle = (HANDLE)0x12345678; + return VK_SUCCESS; +''', +'vkGetFenceFdKHR': ''' + *pFd = 0x42; + return VK_SUCCESS; +''', +'vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR': ''' + if (!pCounters) { + *pCounterCount = 3; + } else { + if (*pCounterCount == 0){ + return VK_INCOMPLETE; + } + // arbitrary + pCounters[0].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; + pCounters[0].scope = VK_QUERY_SCOPE_COMMAND_BUFFER_KHR; + pCounters[0].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; + pCounters[0].uuid[0] = 0x01; + if (*pCounterCount == 1){ + return VK_INCOMPLETE; + } + pCounters[1].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; + pCounters[1].scope = VK_QUERY_SCOPE_RENDER_PASS_KHR; + pCounters[1].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; + pCounters[1].uuid[0] = 0x02; + if (*pCounterCount == 2){ + return VK_INCOMPLETE; + } + pCounters[2].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; + pCounters[2].scope = VK_QUERY_SCOPE_COMMAND_KHR; + pCounters[2].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; + pCounters[2].uuid[0] = 0x03; + *pCounterCount = 3; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR': ''' + if (pNumPasses) { + // arbitrary + *pNumPasses = 1; + } +''', +'vkGetShaderModuleIdentifierEXT': ''' + if (pIdentifier) { + // arbitrary + pIdentifier->identifierSize = 1; + pIdentifier->identifier[0] = 0x01; + } +''', +'vkGetImageSparseMemoryRequirements': ''' + if (!pSparseMemoryRequirements) { + *pSparseMemoryRequirementCount = 1; + } else { + // arbitrary + pSparseMemoryRequirements->imageMipTailFirstLod = 0; + pSparseMemoryRequirements->imageMipTailSize = 8; + pSparseMemoryRequirements->imageMipTailOffset = 0; + pSparseMemoryRequirements->imageMipTailStride = 4; + pSparseMemoryRequirements->formatProperties.imageGranularity = {4, 4, 4}; + pSparseMemoryRequirements->formatProperties.flags = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT; + // Would need to track the VkImage to know format for better value here + pSparseMemoryRequirements->formatProperties.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT; + } + +''', +'vkGetImageSparseMemoryRequirements2KHR': ''' + if (pSparseMemoryRequirementCount && pSparseMemoryRequirements) { + GetImageSparseMemoryRequirements(device, pInfo->image, pSparseMemoryRequirementCount, &pSparseMemoryRequirements->memoryRequirements); + } else { + GetImageSparseMemoryRequirements(device, pInfo->image, pSparseMemoryRequirementCount, nullptr); + } +''', +'vkGetBufferDeviceAddress': ''' + VkDeviceAddress address = 0; + auto d_iter = buffer_map.find(device); + if (d_iter != buffer_map.end()) { + auto iter = d_iter->second.find(pInfo->buffer); + if (iter != d_iter->second.end()) { + address = iter->second.address; + } + } + return address; +''', +'vkGetBufferDeviceAddressKHR': ''' + return GetBufferDeviceAddress(device, pInfo); +''', +'vkGetBufferDeviceAddressEXT': ''' + return GetBufferDeviceAddress(device, pInfo); +''', +'vkGetDescriptorSetLayoutSizeEXT': ''' + // Need to give something non-zero + *pLayoutSizeInBytes = 4; +''', +'vkGetAccelerationStructureBuildSizesKHR': ''' + // arbitrary + pSizeInfo->accelerationStructureSize = 4; + pSizeInfo->updateScratchSize = 4; + pSizeInfo->buildScratchSize = 4; +''', +'vkGetAccelerationStructureMemoryRequirementsNV': ''' + // arbitrary + pMemoryRequirements->memoryRequirements.size = 4096; + pMemoryRequirements->memoryRequirements.alignment = 1; + pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF; +''', +'vkGetAccelerationStructureDeviceAddressKHR': ''' + // arbitrary - need to be aligned to 256 bytes + return 0x262144; +''', +'vkGetVideoSessionMemoryRequirementsKHR': ''' + if (!pMemoryRequirements) { + *pMemoryRequirementsCount = 1; + } else { + // arbitrary + pMemoryRequirements[0].memoryBindIndex = 0; + pMemoryRequirements[0].memoryRequirements.size = 4096; + pMemoryRequirements[0].memoryRequirements.alignment = 1; + pMemoryRequirements[0].memoryRequirements.memoryTypeBits = 0xFFFF; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR': ''' + if (!pProperties) { + *pPropertyCount = 2; + } else { + // arbitrary + pProperties[0].MSize = 16; + pProperties[0].NSize = 16; + pProperties[0].KSize = 16; + pProperties[0].AType = VK_COMPONENT_TYPE_UINT32_KHR; + pProperties[0].BType = VK_COMPONENT_TYPE_UINT32_KHR; + pProperties[0].CType = VK_COMPONENT_TYPE_UINT32_KHR; + pProperties[0].ResultType = VK_COMPONENT_TYPE_UINT32_KHR; + pProperties[0].saturatingAccumulation = VK_FALSE; + pProperties[0].scope = VK_SCOPE_SUBGROUP_KHR; + + pProperties[1] = pProperties[0]; + pProperties[1].scope = VK_SCOPE_DEVICE_KHR; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceVideoCapabilitiesKHR': ''' + return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR; +''', +'vkGetPhysicalDeviceVideoFormatPropertiesKHR': ''' + return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR; +''', +'vkGetDescriptorSetLayoutSupport':''' + if (pSupport) { + pSupport->supported = VK_TRUE; + } +''', +'vkGetDescriptorSetLayoutSupportKHR':''' + GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); +''', +'vkGetRenderAreaGranularity': ''' + pGranularity->width = 1; + pGranularity->height = 1; +''', +'vkGetMemoryFdKHR': ''' + *pFd = 1; + return VK_SUCCESS; +''', +'vkGetMemoryHostPointerPropertiesEXT': ''' + pMemoryHostPointerProperties->memoryTypeBits = 1 << 5; // DEVICE_LOCAL only type + return VK_SUCCESS; +''', +'vkGetAndroidHardwareBufferPropertiesANDROID': ''' + pProperties->allocationSize = 65536; + pProperties->memoryTypeBits = 1 << 5; // DEVICE_LOCAL only type + + auto *format_prop = lvl_find_mod_in_chain(pProperties->pNext); + if (format_prop) { + // Likley using this format + format_prop->format = VK_FORMAT_R8G8B8A8_UNORM; + format_prop->externalFormat = 37; + } + + auto *format_resolve_prop = lvl_find_mod_in_chain(pProperties->pNext); + if (format_resolve_prop) { + format_resolve_prop->colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM; + } + return VK_SUCCESS; +''', +'vkGetPhysicalDeviceDisplayPropertiesKHR': ''' + if (!pProperties) { + *pPropertyCount = 1; + } else { + unique_lock_t lock(global_lock); + pProperties[0].display = (VkDisplayKHR)global_unique_handle++; + display_map[physicalDevice].insert(pProperties[0].display); + } + return VK_SUCCESS; +''', +'vkRegisterDisplayEventEXT': ''' + unique_lock_t lock(global_lock); + *pFence = (VkFence)global_unique_handle++; + return VK_SUCCESS; +''', +'vkQueueSubmit': ''' + // Special way to cause DEVICE_LOST + // Picked VkExportFenceCreateInfo because needed some struct that wouldn't get cleared by validation Safe Struct + // ... TODO - It would be MUCH nicer to have a layer or other setting control when this occured + // For now this is used to allow Validation Layers test reacting to device losts + if (submitCount > 0 && pSubmits) { + auto pNext = reinterpret_cast(pSubmits[0].pNext); + if (pNext && pNext->sType == VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO && pNext->pNext == nullptr) { + return VK_ERROR_DEVICE_LOST; + } + } + return VK_SUCCESS; +''', +'vkGetMemoryWin32HandlePropertiesKHR': ''' + pMemoryWin32HandleProperties->memoryTypeBits = 0xFFFF; + return VK_SUCCESS; +''', +'vkCreatePipelineBinariesKHR': ''' + unique_lock_t lock(global_lock); + for (uint32_t i = 0; i < pBinaries->pipelineBinaryCount; ++i) { + pBinaries->pPipelineBinaries[i] = (VkPipelineBinaryKHR)global_unique_handle++; + } + return VK_SUCCESS; +''' +} + +# MockICDGeneratorOptions - subclass of GeneratorOptions. +# +# Adds options used by MockICDOutputGenerator objects during Mock +# ICD generation. +# +# Additional members +# prefixText - list of strings to prefix generated header with +# (usually a copyright statement + calling convention macros). +# protectFile - True if multiple inclusion protection should be +# generated (based on the filename) around the entire header. +# protectFeature - True if #ifndef..#endif protection should be +# generated around a feature interface in the header file. +# genFuncPointers - True if function pointer typedefs should be +# generated +# protectProto - If conditional protection should be generated +# around prototype declarations, set to either '#ifdef' +# to require opt-in (#ifdef protectProtoStr) or '#ifndef' +# to require opt-out (#ifndef protectProtoStr). Otherwise +# set to None. +# protectProtoStr - #ifdef/#ifndef symbol to use around prototype +# declarations, if protectProto is set +# apicall - string to use for the function declaration prefix, +# such as APICALL on Windows. +# apientry - string to use for the calling convention macro, +# in typedefs, such as APIENTRY. +# apientryp - string to use for the calling convention macro +# in function pointer typedefs, such as APIENTRYP. +# indentFuncProto - True if prototype declarations should put each +# parameter on a separate line +# indentFuncPointer - True if typedefed function pointers should put each +# parameter on a separate line +# alignFuncParam - if nonzero and parameters are being put on a +# separate line, align parameter names at the specified column +class MockICDGeneratorOptions(GeneratorOptions): + def __init__(self, + conventions = None, + filename = None, + directory = '.', + genpath = None, + apiname = None, + profile = None, + versions = '.*', + emitversions = '.*', + defaultExtensions = None, + addExtensions = None, + removeExtensions = None, + emitExtensions = None, + sortProcedure = regSortFeatures, + prefixText = "", + genFuncPointers = True, + protectFile = True, + protectFeature = True, + protectProto = None, + protectProtoStr = None, + apicall = '', + apientry = '', + apientryp = '', + indentFuncProto = True, + indentFuncPointer = False, + alignFuncParam = 0, + expandEnumerants = True, + helper_file_type = ''): + GeneratorOptions.__init__(self, + conventions = conventions, + filename = filename, + directory = directory, + genpath = genpath, + apiname = apiname, + profile = profile, + versions = versions, + emitversions = emitversions, + defaultExtensions = defaultExtensions, + addExtensions = addExtensions, + removeExtensions = removeExtensions, + emitExtensions = emitExtensions, + sortProcedure = sortProcedure) + self.prefixText = prefixText + self.genFuncPointers = genFuncPointers + self.protectFile = protectFile + self.protectFeature = protectFeature + self.protectProto = protectProto + self.protectProtoStr = protectProtoStr + self.apicall = apicall + self.apientry = apientry + self.apientryp = apientryp + self.indentFuncProto = indentFuncProto + self.indentFuncPointer = indentFuncPointer + self.alignFuncParam = alignFuncParam + +# MockICDOutputGenerator - subclass of OutputGenerator. +# Generates a mock vulkan ICD. +# This is intended to be a minimal replacement for a vulkan device in order +# to enable Vulkan Validation testing. +# +# ---- methods ---- +# MockOutputGenerator(errFile, warnFile, diagFile) - args as for +# OutputGenerator. Defines additional internal state. +# ---- methods overriding base class ---- +# beginFile(genOpts) +# endFile() +# beginFeature(interface, emit) +# endFeature() +# genType(typeinfo,name) +# genStruct(typeinfo,name) +# genGroup(groupinfo,name) +# genEnum(enuminfo, name) +# genCmd(cmdinfo) +class MockICDOutputGenerator(OutputGenerator): + """Generate specified API interfaces in a specific style, such as a C header""" + # This is an ordered list of sections in the header file. + TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', + 'group', 'bitmask', 'funcpointer', 'struct'] + ALL_SECTIONS = TYPE_SECTIONS + ['command'] + def __init__(self, + errFile = sys.stderr, + warnFile = sys.stderr, + diagFile = sys.stdout): + OutputGenerator.__init__(self, errFile, warnFile, diagFile) + # Internal state - accumulators for different inner block text + self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) + self.intercepts = [] + self.function_declarations = False + + # Check if the parameter passed in is a pointer to an array + def paramIsArray(self, param): + return param.attrib.get('len') is not None + + # Check if the parameter passed in is a pointer + def paramIsPointer(self, param): + ispointer = False + for elem in param: + if ((elem.tag != 'type') and (elem.tail is not None)) and '*' in elem.tail: + ispointer = True + return ispointer + + # Check if an object is a non-dispatchable handle + def isHandleTypeNonDispatchable(self, handletype): + handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") + if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': + return True + else: + return False + + # Check if an object is a dispatchable handle + def isHandleTypeDispatchable(self, handletype): + handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") + if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE': + return True + else: + return False + + # Check that the target API is in the supported list for the extension + def checkExtensionAPISupport(self, supported): + return self.genOpts.apiname in supported.split(',') + + def beginFile(self, genOpts): + OutputGenerator.beginFile(self, genOpts) + # C-specific + # + # Multiple inclusion protection & C++ namespace. + if (genOpts.protectFile and self.genOpts.filename == "function_declarations.h"): + self.function_declarations = True + + # User-supplied prefix text, if any (list of strings) + if (genOpts.prefixText): + for s in genOpts.prefixText: + write(s, file=self.outFile) + + if self.function_declarations: + self.newline() + # Include all of the extensions in ICD except specific ignored ones + device_exts = [] + instance_exts = [] + # Ignore extensions that ICDs should not implement or are not safe to report + ignore_exts = ['VK_EXT_validation_cache', 'VK_KHR_portability_subset'] + for ext in self.registry.tree.findall("extensions/extension"): + if self.checkExtensionAPISupport(ext.attrib['supported']): # Only include API-relevant extensions + if (ext.attrib['name'] not in ignore_exts): + # Search for extension version enum + for enum in ext.findall('require/enum'): + if enum.get('name', '').endswith('_SPEC_VERSION'): + ext_version = enum.get('value') + if (ext.attrib.get('type') == 'instance'): + instance_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext_version)) + else: + device_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext_version)) + break + write('#pragma once\n',file=self.outFile) + write('#include ',file=self.outFile) + write('#include ',file=self.outFile) + write('#include ',file=self.outFile) + write('#include ',file=self.outFile) + write('#include ',file=self.outFile) + self.newline() + write('namespace vkmock {\n', file=self.outFile) + write('// Map of instance extension name to version', file=self.outFile) + write('static const std::unordered_map instance_extension_map = {', file=self.outFile) + write('\n'.join(instance_exts), file=self.outFile) + write('};', file=self.outFile) + write('// Map of device extension name to version', file=self.outFile) + write('static const std::unordered_map device_extension_map = {', file=self.outFile) + write('\n'.join(device_exts), file=self.outFile) + write('};', file=self.outFile) + else: + write('#pragma once\n',file=self.outFile) + write('#include "mock_icd.h"',file=self.outFile) + write('#include "function_declarations.h"\n',file=self.outFile) + write('namespace vkmock {', file=self.outFile) + + + def endFile(self): + # C-specific + # Finish C++ namespace + self.newline() + if self.function_declarations: + # record intercepted procedures + write('// Map of all APIs to be intercepted by this layer', file=self.outFile) + write('static const std::unordered_map name_to_funcptr_map = {', file=self.outFile) + write('\n'.join(self.intercepts), file=self.outFile) + write('};\n', file=self.outFile) + write('} // namespace vkmock', file=self.outFile) + self.newline() + + # Finish processing in superclass + OutputGenerator.endFile(self) + def beginFeature(self, interface, emit): + #write('// starting beginFeature', file=self.outFile) + # Start processing in superclass + OutputGenerator.beginFeature(self, interface, emit) + self.featureExtraProtect = GetFeatureProtect(interface) + # C-specific + # Accumulate includes, defines, types, enums, function pointer typedefs, + # end function prototypes separately for this feature. They're only + # printed in endFeature(). + self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) + #write('// ending beginFeature', file=self.outFile) + def endFeature(self): + # C-specific + # Actually write the interface to the output file. + #write('// starting endFeature', file=self.outFile) + if (self.emit): + self.newline() + if (self.genOpts.protectFeature): + write('#ifndef', self.featureName, file=self.outFile) + # If type declarations are needed by other features based on + # this one, it may be necessary to suppress the ExtraProtect, + # or move it below the 'for section...' loop. + #write('// endFeature looking at self.featureExtraProtect', file=self.outFile) + if (self.featureExtraProtect != None): + write('#ifdef', self.featureExtraProtect, file=self.outFile) + #write('#define', self.featureName, '1', file=self.outFile) + for section in self.TYPE_SECTIONS: + #write('// endFeature writing section'+section, file=self.outFile) + contents = self.sections[section] + if contents: + write('\n'.join(contents), file=self.outFile) + self.newline() + #write('// endFeature looking at self.sections[command]', file=self.outFile) + if (self.sections['command']): + write('\n'.join(self.sections['command']), end=u'', file=self.outFile) + self.newline() + if (self.featureExtraProtect != None): + write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) + if (self.genOpts.protectFeature): + write('#endif /*', self.featureName, '*/', file=self.outFile) + # Finish processing in superclass + OutputGenerator.endFeature(self) + #write('// ending endFeature', file=self.outFile) + # + # Append a definition to the specified section + def appendSection(self, section, text): + # self.sections[section].append('SECTION: ' + section + '\n') + self.sections[section].append(text) + # + # Type generation + def genType(self, typeinfo, name, alias): + pass + # + # Struct (e.g. C "struct" type) generation. + # This is a special case of the tag where the contents are + # interpreted as a set of tags instead of freeform C + # C type declarations. The tags are just like + # tags - they are a declaration of a struct or union member. + # Only simple member declarations are supported (no nested + # structs etc.) + def genStruct(self, typeinfo, typeName, alias): + OutputGenerator.genStruct(self, typeinfo, typeName, alias) + body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n' + # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam) + for member in typeinfo.elem.findall('.//member'): + body += self.makeCParamDecl(member, self.genOpts.alignFuncParam) + body += ';\n' + body += '} ' + typeName + ';\n' + self.appendSection('struct', body) + # + # Group (e.g. C "enum" type) generation. + # These are concatenated together with other types. + def genGroup(self, groupinfo, groupName, alias): + pass + # Enumerant generation + # tags may specify their values in several ways, but are usually + # just integers. + def genEnum(self, enuminfo, name, alias): + pass + # + # Command generation + def genCmd(self, cmdinfo, name, alias): + decls = self.makeCDecls(cmdinfo.elem) + if self.function_declarations: # In the header declare all intercepts + self.appendSection('command', '') + self.appendSection('command', 'static %s' % (decls[0])) + if (self.featureExtraProtect != None): + self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] + self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] + if (self.featureExtraProtect != None): + self.intercepts += [ '#endif' ] + return + + manual_functions = [ + # Include functions here to be intercepted w/ manually implemented function bodies + 'vkGetDeviceProcAddr', + 'vkGetInstanceProcAddr', + 'vkCreateDevice', + 'vkDestroyDevice', + 'vkCreateInstance', + 'vkDestroyInstance', + 'vkFreeCommandBuffers', + 'vkAllocateCommandBuffers', + 'vkDestroyCommandPool', + #'vkCreateDebugReportCallbackEXT', + #'vkDestroyDebugReportCallbackEXT', + 'vkEnumerateInstanceLayerProperties', + 'vkEnumerateInstanceVersion', + 'vkEnumerateInstanceExtensionProperties', + 'vkEnumerateDeviceLayerProperties', + 'vkEnumerateDeviceExtensionProperties', + ] + if name in manual_functions: + self.appendSection('command', '') + if name not in CUSTOM_C_INTERCEPTS: + self.appendSection('command', '// declare only') + self.appendSection('command', 'static %s' % (decls[0])) + self.appendSection('command', '// TODO: Implement custom intercept body') + else: + self.appendSection('command', 'static %s' % (decls[0][:-1])) + self.appendSection('command', '{\n%s}' % (CUSTOM_C_INTERCEPTS[name])) + self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] + return + # record that the function will be intercepted + if (self.featureExtraProtect != None): + self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] + self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] + if (self.featureExtraProtect != None): + self.intercepts += [ '#endif' ] + + OutputGenerator.genCmd(self, cmdinfo, name, alias) + # + self.appendSection('command', '') + self.appendSection('command', 'static %s' % (decls[0][:-1])) + if name in CUSTOM_C_INTERCEPTS: + self.appendSection('command', '{%s}' % (CUSTOM_C_INTERCEPTS[name])) + return + + # Declare result variable, if any. + resulttype = cmdinfo.elem.find('proto/type') + if (resulttype != None and resulttype.text == 'void'): + resulttype = None + # if the name w/ KHR postfix is in the CUSTOM_C_INTERCEPTS + # Call the KHR custom version instead of generating separate code + khr_name = name + "KHR" + if khr_name in CUSTOM_C_INTERCEPTS: + return_string = '' + if resulttype != None: + return_string = 'return ' + params = cmdinfo.elem.findall('param/name') + param_names = [] + for param in params: + param_names.append(param.text) + self.appendSection('command', '{\n %s%s(%s);\n}' % (return_string, khr_name[2:], ", ".join(param_names))) + return + self.appendSection('command', '{') + + api_function_name = cmdinfo.elem.attrib.get('name') + # GET THE TYPE OF FUNCTION + if any(api_function_name.startswith(ftxt) for ftxt in ('vkCreate', 'vkAllocate')): + # Get last param + last_param = cmdinfo.elem.findall('param')[-1] + lp_txt = last_param.find('name').text + lp_len = None + if ('len' in last_param.attrib): + lp_len = last_param.attrib['len'] + lp_len = lp_len.replace('::', '->') + lp_type = last_param.find('type').text + handle_type = 'dispatchable' + allocator_txt = 'CreateDispObjHandle()'; + if (self.isHandleTypeNonDispatchable(lp_type)): + handle_type = 'non-' + handle_type + allocator_txt = 'global_unique_handle++'; + # Need to lock in both cases + self.appendSection('command', ' unique_lock_t lock(global_lock);') + if (lp_len != None): + #print("%s last params (%s) has len %s" % (handle_type, lp_txt, lp_len)) + self.appendSection('command', ' for (uint32_t i = 0; i < %s; ++i) {' % (lp_len)) + self.appendSection('command', ' %s[i] = (%s)%s;' % (lp_txt, lp_type, allocator_txt)) + self.appendSection('command', ' }') + else: + #print("Single %s last param is '%s' w/ type '%s'" % (handle_type, lp_txt, lp_type)) + if 'AllocateMemory' in api_function_name: + # Store allocation size in case it's mapped + self.appendSection('command', ' allocated_memory_size_map[(VkDeviceMemory)global_unique_handle] = pAllocateInfo->allocationSize;') + self.appendSection('command', ' *%s = (%s)%s;' % (lp_txt, lp_type, allocator_txt)) + elif True in [ftxt in api_function_name for ftxt in ['Destroy', 'Free']]: + self.appendSection('command', '//Destroy object') + if 'FreeMemory' in api_function_name: + # If the memory is mapped, unmap it + self.appendSection('command', ' UnmapMemory(device, memory);') + # Remove from allocation map + self.appendSection('command', ' unique_lock_t lock(global_lock);') + self.appendSection('command', ' allocated_memory_size_map.erase(memory);') + else: + self.appendSection('command', '//Not a CREATE or DESTROY function') + + # Return result variable, if any. + if (resulttype != None): + if api_function_name == 'vkGetEventStatus': + self.appendSection('command', ' return VK_EVENT_SET;') + else: + self.appendSection('command', ' return VK_SUCCESS;') + self.appendSection('command', '}') + # + # override makeProtoName to drop the "vk" prefix + def makeProtoName(self, name, tail): + return self.genOpts.apientry + name[2:] + tail diff --git a/scripts/generators/vulkan_tools_helper_file_generator.py b/scripts/generators/vulkan_tools_helper_file_generator.py new file mode 100644 index 00000000..b0e486ef --- /dev/null +++ b/scripts/generators/vulkan_tools_helper_file_generator.py @@ -0,0 +1,1240 @@ +#!/usr/bin/python3 -i +# +# Copyright (c) 2015-2021 The Khronos Group Inc. +# Copyright (c) 2015-2021 Valve Corporation +# Copyright (c) 2015-2021 LunarG, Inc. +# Copyright (c) 2015-2021 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Mark Lobodzinski +# Author: Tobin Ehlis +# Author: John Zulauf + +import os,re,sys +import xml.etree.ElementTree as etree +from generator import * +from collections import namedtuple +from common_codegen import * + +# +# HelperFileOutputGeneratorOptions - subclass of GeneratorOptions. +class HelperFileOutputGeneratorOptions(GeneratorOptions): + def __init__(self, + conventions = None, + filename = None, + directory = '.', + genpath = None, + apiname = None, + profile = None, + versions = '.*', + emitversions = '.*', + defaultExtensions = None, + addExtensions = None, + removeExtensions = None, + emitExtensions = None, + sortProcedure = regSortFeatures, + prefixText = "", + genFuncPointers = True, + protectFile = True, + protectFeature = True, + apicall = '', + apientry = '', + apientryp = '', + alignFuncParam = 0, + library_name = '', + expandEnumerants = True, + helper_file_type = ''): + GeneratorOptions.__init__(self, + conventions = conventions, + filename = filename, + directory = directory, + genpath = genpath, + apiname = apiname, + profile = profile, + versions = versions, + emitversions = emitversions, + defaultExtensions = defaultExtensions, + addExtensions = addExtensions, + removeExtensions = removeExtensions, + emitExtensions = emitExtensions, + sortProcedure = sortProcedure) + self.prefixText = prefixText + self.genFuncPointers = genFuncPointers + self.protectFile = protectFile + self.protectFeature = protectFeature + self.apicall = apicall + self.apientry = apientry + self.apientryp = apientryp + self.alignFuncParam = alignFuncParam + self.library_name = library_name + self.helper_file_type = helper_file_type +# +# HelperFileOutputGenerator - subclass of OutputGenerator. Outputs Vulkan helper files +class HelperFileOutputGenerator(OutputGenerator): + """Generate helper file based on XML element attributes""" + def __init__(self, + errFile = sys.stderr, + warnFile = sys.stderr, + diagFile = sys.stdout): + OutputGenerator.__init__(self, errFile, warnFile, diagFile) + # Internal state - accumulators for different inner block text + self.enum_output = '' # string built up of enum string routines + # Internal state - accumulators for different inner block text + self.structNames = [] # List of Vulkan struct typenames + self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType + self.structMembers = [] # List of StructMemberData records for all Vulkan structs + self.object_types = [] # List of all handle types + self.object_type_aliases = [] # Aliases to handles types (for handles that were extensions) + self.debug_report_object_types = [] # Handy copy of debug_report_object_type enum data + self.core_object_types = [] # Handy copy of core_object_type enum data + self.device_extension_info = dict() # Dict of device extension name defines and ifdef values + self.instance_extension_info = dict() # Dict of instance extension name defines and ifdef values + + # Named tuples to store struct and command data + self.StructType = namedtuple('StructType', ['name', 'value']) + self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl']) + self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect']) + + self.custom_construct_params = { + # safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers + 'VkGraphicsPipelineCreateInfo' : + ', const bool uses_color_attachment, const bool uses_depthstencil_attachment', + # safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers + 'VkPipelineViewportStateCreateInfo' : + ', const bool is_dynamic_viewports, const bool is_dynamic_scissors', + } + # + # Called once at the beginning of each run + def beginFile(self, genOpts): + OutputGenerator.beginFile(self, genOpts) + # User-supplied prefix text, if any (list of strings) + self.helper_file_type = genOpts.helper_file_type + self.library_name = genOpts.library_name + # File Comment + file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' + file_comment += '// See vulkan_tools_helper_file_generator.py for modifications\n' + write(file_comment, file=self.outFile) + # Copyright Notice + copyright = '' + copyright += '\n' + copyright += '/***************************************************************************\n' + copyright += ' *\n' + copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n' + copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n' + copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n' + copyright += ' * Copyright (c) 2015-2017 Google Inc.\n' + copyright += ' *\n' + copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' + copyright += ' * you may not use this file except in compliance with the License.\n' + copyright += ' * You may obtain a copy of the License at\n' + copyright += ' *\n' + copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' + copyright += ' *\n' + copyright += ' * Unless required by applicable law or agreed to in writing, software\n' + copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' + copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' + copyright += ' * See the License for the specific language governing permissions and\n' + copyright += ' * limitations under the License.\n' + copyright += ' *\n' + copyright += ' * Author: Mark Lobodzinski \n' + copyright += ' * Author: Courtney Goeltzenleuchter \n' + copyright += ' * Author: Tobin Ehlis \n' + copyright += ' * Author: Chris Forbes \n' + copyright += ' * Author: John Zulauf\n' + copyright += ' *\n' + copyright += ' ****************************************************************************/\n' + write(copyright, file=self.outFile) + # + # Write generated file content to output file + def endFile(self): + dest_file = '' + dest_file += self.OutputDestFile() + # Remove blank lines at EOF + if dest_file.endswith('\n'): + dest_file = dest_file[:-1] + write(dest_file, file=self.outFile); + # Finish processing in superclass + OutputGenerator.endFile(self) + # + # Override parent class to be notified of the beginning of an extension + def beginFeature(self, interface, emit): + # Start processing in superclass + OutputGenerator.beginFeature(self, interface, emit) + self.featureExtraProtect = GetFeatureProtect(interface) + + if interface.tag != 'extension': + return + name = self.featureName + for enum in interface.findall('require/enum'): + if enum.get('name', '').endswith('EXTENSION_NAME'): + name_define = enum.get('name') + break + requires = interface.get('requires') + if requires is not None: + required_extensions = requires.split(',') + else: + required_extensions = list() + info = { 'define': name_define, 'ifdef':self.featureExtraProtect, 'reqs':required_extensions } + if interface.get('type') == 'instance': + self.instance_extension_info[name] = info + else: + self.device_extension_info[name] = info + + # + # Override parent class to be notified of the end of an extension + def endFeature(self): + # Finish processing in superclass + OutputGenerator.endFeature(self) + # + # Grab group (e.g. C "enum" type) info to output for enum-string conversion helper + def genGroup(self, groupinfo, groupName, alias): + OutputGenerator.genGroup(self, groupinfo, groupName, alias) + groupElem = groupinfo.elem + # For enum_string_header + if self.helper_file_type == 'enum_string_header': + value_set = set() + for elem in groupElem.findall('enum'): + if elem.get('supported') != 'disabled' and elem.get('alias') == None: + value_set.add(elem.get('name')) + self.enum_output += self.GenerateEnumStringConversion(groupName, value_set) + elif self.helper_file_type == 'object_types_header': + if groupName == 'VkDebugReportObjectTypeEXT': + for elem in groupElem.findall('enum'): + if elem.get('supported') != 'disabled': + item_name = elem.get('name') + self.debug_report_object_types.append(item_name) + elif groupName == 'VkObjectType': + for elem in groupElem.findall('enum'): + if elem.get('supported') != 'disabled': + item_name = elem.get('name') + self.core_object_types.append(item_name) + + # + # Called for each type -- if the type is a struct/union, grab the metadata + def genType(self, typeinfo, name, alias): + OutputGenerator.genType(self, typeinfo, name, alias) + typeElem = typeinfo.elem + # If the type is a struct type, traverse the imbedded tags generating a structure. + # Otherwise, emit the tag text. + category = typeElem.get('category') + if category == 'handle': + if alias: + self.object_type_aliases.append((name,alias)) + else: + self.object_types.append(name) + elif (category == 'struct' or category == 'union'): + self.structNames.append(name) + self.genStruct(typeinfo, name, alias) + # + # Check if the parameter passed in is a pointer + def paramIsPointer(self, param): + ispointer = False + for elem in param: + if ((elem.tag != 'type') and (elem.tail is not None)) and '*' in elem.tail: + ispointer = True + return ispointer + # + # Check if the parameter passed in is a static array + def paramIsStaticArray(self, param): + isstaticarray = 0 + paramname = param.find('name') + if (paramname.tail is not None) and ('[' in paramname.tail): + isstaticarray = paramname.tail.count('[') + return isstaticarray + # + # Retrieve the type and name for a parameter + def getTypeNameTuple(self, param): + type = '' + name = '' + for elem in param: + if elem.tag == 'type': + type = noneStr(elem.text) + elif elem.tag == 'name': + name = noneStr(elem.text) + return (type, name) + # + # Retrieve the value of the len tag + def getLen(self, param): + result = None + len = param.attrib.get('len') + if len and len != 'null-terminated': + # For string arrays, 'len' can look like 'count,null-terminated', indicating that we + # have a null terminated array of strings. We strip the null-terminated from the + # 'len' field and only return the parameter specifying the string count + if 'null-terminated' in len: + result = len.split(',')[0] + else: + result = len + if 'altlen' in param.attrib: + # Elements with latexmath 'len' also contain a C equivalent 'altlen' attribute + # Use indexing operator instead of get() so we fail if the attribute is missing + result = param.attrib['altlen'] + # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol + result = str(result).replace('::', '->') + return result + # + # Check if a structure is or contains a dispatchable (dispatchable = True) or + # non-dispatchable (dispatchable = False) handle + def TypeContainsObjectHandle(self, handle_type, dispatchable): + if dispatchable: + type_key = 'VK_DEFINE_HANDLE' + else: + type_key = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE' + handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") + if handle is not None and handle.find('type').text == type_key: + return True + # if handle_type is a struct, search its members + if handle_type in self.structNames: + member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None) + if member_index is not None: + for item in self.structMembers[member_index].members: + handle = self.registry.tree.find("types/type/[name='" + item.type + "'][@category='handle']") + if handle is not None and handle.find('type').text == type_key: + return True + return False + # + # Generate local ready-access data describing Vulkan structures and unions from the XML metadata + def genStruct(self, typeinfo, typeName, alias): + OutputGenerator.genStruct(self, typeinfo, typeName, alias) + members = typeinfo.elem.findall('.//member') + # Iterate over members once to get length parameters for arrays + lens = set() + for member in members: + len = self.getLen(member) + if len: + lens.add(len) + # Generate member info + membersInfo = [] + for member in members: + # Get the member's type and name + info = self.getTypeNameTuple(member) + type = info[0] + name = info[1] + cdecl = self.makeCParamDecl(member, 1) + # Process VkStructureType + if type == 'VkStructureType': + # Extract the required struct type value from the comments + # embedded in the original text defining the 'typeinfo' element + rawXml = etree.tostring(typeinfo.elem).decode('ascii') + result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) + if result: + value = result.group(0) + # Store the required type value + self.structTypes[typeName] = self.StructType(name=name, value=value) + # Store pointer/array/string info + isstaticarray = self.paramIsStaticArray(member) + membersInfo.append(self.CommandParam(type=type, + name=name, + ispointer=self.paramIsPointer(member), + isstaticarray=isstaticarray, + isconst=True if 'const' in cdecl else False, + iscount=True if name in lens else False, + len=self.getLen(member), + extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None, + cdecl=cdecl)) + self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo, ifdef_protect=self.featureExtraProtect)) + # + # Enum_string_header: Create a routine to convert an enumerated value into a string + def GenerateEnumStringConversion(self, groupName, value_list): + outstring = '\n' + outstring += 'static inline const char* string_%s(%s input_value)\n' % (groupName, groupName) + outstring += '{\n' + outstring += ' switch ((%s)input_value)\n' % groupName + outstring += ' {\n' + for item in value_list: + outstring += ' case %s:\n' % item + outstring += ' return "%s";\n' % item + outstring += ' default:\n' + outstring += ' return "Unhandled %s";\n' % groupName + outstring += ' }\n' + outstring += '}\n' + return outstring + # + # Tack on a helper which, given an index into a VkPhysicalDeviceFeatures structure, will print the corresponding feature name + def DeIndexPhysDevFeatures(self): + pdev_members = None + for name, members, ifdef in self.structMembers: + if name == 'VkPhysicalDeviceFeatures': + pdev_members = members + break + deindex = '\n' + deindex += 'static inline const char * GetPhysDevFeatureString(uint32_t index) {\n' + deindex += ' const char * IndexToPhysDevFeatureString[] = {\n' + for feature in pdev_members: + deindex += ' "%s",\n' % feature.name + deindex += ' };\n\n' + deindex += ' return IndexToPhysDevFeatureString[index];\n' + deindex += '}\n' + return deindex + # + # Combine enum string helper header file preamble with body text and return + def GenerateEnumStringHelperHeader(self): + enum_string_helper_header = '\n' + enum_string_helper_header += '#pragma once\n' + enum_string_helper_header += '#ifdef _WIN32\n' + enum_string_helper_header += '#pragma warning( disable : 4065 )\n' + enum_string_helper_header += '#endif\n' + enum_string_helper_header += '\n' + enum_string_helper_header += '#include \n' + enum_string_helper_header += '\n' + enum_string_helper_header += self.enum_output + enum_string_helper_header += self.DeIndexPhysDevFeatures() + return enum_string_helper_header + # + # Helper function for declaring a counter variable only once + def DeclareCounter(self, string_var, declare_flag): + if declare_flag == False: + string_var += ' uint32_t i = 0;\n' + declare_flag = True + return string_var, declare_flag + # + # Combine safe struct helper header file preamble with body text and return + def GenerateSafeStructHelperHeader(self): + safe_struct_helper_header = '\n' + safe_struct_helper_header += '#pragma once\n' + safe_struct_helper_header += '#include \n' + safe_struct_helper_header += '\n' + safe_struct_helper_header += self.GenerateSafeStructHeader() + return safe_struct_helper_header + # + # safe_struct header: build function prototypes for header file + def GenerateSafeStructHeader(self): + safe_struct_header = '' + for item in self.structMembers: + if self.NeedSafeStruct(item) == True: + safe_struct_header += '\n' + if item.ifdef_protect != None: + safe_struct_header += '#ifdef %s\n' % item.ifdef_protect + safe_struct_header += 'struct safe_%s {\n' % (item.name) + for member in item.members: + if member.type in self.structNames: + member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) + if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: + if member.ispointer: + safe_struct_header += ' safe_%s* %s;\n' % (member.type, member.name) + else: + safe_struct_header += ' safe_%s %s;\n' % (member.type, member.name) + continue + if member.len is not None and (self.TypeContainsObjectHandle(member.type, True) or self.TypeContainsObjectHandle(member.type, False)): + safe_struct_header += ' %s* %s;\n' % (member.type, member.name) + else: + safe_struct_header += '%s;\n' % member.cdecl + safe_struct_header += ' safe_%s(const %s* in_struct%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, '')) + safe_struct_header += ' safe_%s(const safe_%s& src);\n' % (item.name, item.name) + safe_struct_header += ' safe_%s& operator=(const safe_%s& src);\n' % (item.name, item.name) + safe_struct_header += ' safe_%s();\n' % item.name + safe_struct_header += ' ~safe_%s();\n' % item.name + safe_struct_header += ' void initialize(const %s* in_struct%s);\n' % (item.name, self.custom_construct_params.get(item.name, '')) + safe_struct_header += ' void initialize(const safe_%s* src);\n' % (item.name) + safe_struct_header += ' %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name) + safe_struct_header += ' %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name) + safe_struct_header += '};\n' + if item.ifdef_protect != None: + safe_struct_header += '#endif // %s\n' % item.ifdef_protect + return safe_struct_header + # + # Generate extension helper header file + def GenerateExtensionHelperHeader(self): + + V_1_0_instance_extensions_promoted_to_core = [ + 'vk_khr_device_group_creation', + 'vk_khr_external_fence_capabilities', + 'vk_khr_external_memory_capabilities', + 'vk_khr_external_semaphore_capabilities', + 'vk_khr_get_physical_device_properties_2', + ] + + V_1_0_device_extensions_promoted_to_core = [ + 'vk_khr_16bit_storage', + 'vk_khr_bind_memory_2', + 'vk_khr_dedicated_allocation', + 'vk_khr_descriptor_update_template', + 'vk_khr_device_group', + 'vk_khr_external_fence', + 'vk_khr_external_memory', + 'vk_khr_external_semaphore', + 'vk_khr_get_memory_requirements_2', + 'vk_khr_maintenance1', + 'vk_khr_maintenance2', + 'vk_khr_maintenance3', + 'vk_khr_multiview', + 'vk_khr_relaxed_block_layout', + 'vk_khr_sampler_ycbcr_conversion', + 'vk_khr_shader_draw_parameters', + 'vk_khr_storage_buffer_storage_class', + 'vk_khr_variable_pointers', + ] + + output = [ + '', + '#ifndef VK_EXTENSION_HELPER_H_', + '#define VK_EXTENSION_HELPER_H_', + '#include ', + '#include ', + '#include ', + '', + '#include ', + ''] + + def guarded(ifdef, value): + if ifdef is not None: + return '\n'.join([ '#ifdef %s' % ifdef, value, '#endif' ]) + else: + return value + + for type in ['Instance', 'Device']: + struct_type = '%sExtensions' % type + if type == 'Instance': + extension_dict = self.instance_extension_info + promoted_ext_list = V_1_0_instance_extensions_promoted_to_core + struct_decl = 'struct %s {' % struct_type + instance_struct_type = struct_type + else: + extension_dict = self.device_extension_info + promoted_ext_list = V_1_0_device_extensions_promoted_to_core + struct_decl = 'struct %s : public %s {' % (struct_type, instance_struct_type) + + extension_items = sorted(extension_dict.items()) + + field_name = { ext_name: re.sub('_extension_name', '', info['define'].lower()) for ext_name, info in extension_items } + if type == 'Instance': + instance_field_name = field_name + instance_extension_dict = extension_dict + else: + # Get complete field name and extension data for both Instance and Device extensions + field_name.update(instance_field_name) + extension_dict = extension_dict.copy() # Don't modify the self. we're pointing to + extension_dict.update(instance_extension_dict) + + # Output the data member list + struct = [struct_decl] + struct.extend([ ' bool %s{false};' % field_name[ext_name] for ext_name, info in extension_items]) + + # Construct the extension information map -- mapping name to data member (field), and required extensions + # The map is contained within a static function member for portability reasons. + info_type = '%sInfo' % type + info_map_type = '%sMap' % info_type + req_type = '%sReq' % type + req_vec_type = '%sVec' % req_type + struct.extend([ + '', + ' struct %s {' % req_type, + ' const bool %s::* enabled;' % struct_type, + ' const char *name;', + ' };', + ' typedef std::vector<%s> %s;' % (req_type, req_vec_type), + ' struct %s {' % info_type, + ' %s(bool %s::* state_, const %s requires_): state(state_), requires(requires_) {}' % ( info_type, struct_type, req_vec_type), + ' bool %s::* state;' % struct_type, + ' %s requires;' % req_vec_type, + ' };', + '', + ' typedef std::unordered_map %s;' % (info_type, info_map_type), + ' static const %s &get_info(const char *name) {' %info_type, + ' static const %s info_map = {' % info_map_type ]) + + field_format = '&' + struct_type + '::%s' + req_format = '{' + field_format+ ', %s}' + req_indent = '\n ' + req_join = ',' + req_indent + info_format = (' std::make_pair(%s, ' + info_type + '(' + field_format + ', {%s})),') + def format_info(ext_name, info): + reqs = req_join.join([req_format % (field_name[req], extension_dict[req]['define']) for req in info['reqs']]) + return info_format % (info['define'], field_name[ext_name], '{%s}' % (req_indent + reqs) if reqs else '') + + struct.extend([guarded(info['ifdef'], format_info(ext_name, info)) for ext_name, info in extension_items]) + struct.extend([ + ' };', + '', + ' static const %s empty_info {nullptr, %s()};' % (info_type, req_vec_type), + ' %s::const_iterator info = info_map.find(name);' % info_map_type, + ' if ( info != info_map.cend()) {', + ' return info->second;', + ' }', + ' return empty_info;', + ' }', + '']) + + if type == 'Instance': + struct.extend([ + ' uint32_t NormalizeApiVersion(uint32_t specified_version) {', + ' uint32_t api_version = (specified_version < VK_API_VERSION_1_1) ? VK_API_VERSION_1_0 : VK_API_VERSION_1_1;', + ' return api_version;', + ' }', + '', + ' uint32_t InitFromInstanceCreateInfo(uint32_t requested_api_version, const VkInstanceCreateInfo *pCreateInfo) {']) + else: + struct.extend([ + ' %s() = default;' % struct_type, + ' %s(const %s& instance_ext) : %s(instance_ext) {}' % (struct_type, instance_struct_type, instance_struct_type), + '', + ' uint32_t InitFromDeviceCreateInfo(const %s *instance_extensions, uint32_t requested_api_version,' % instance_struct_type, + ' const VkDeviceCreateInfo *pCreateInfo) {', + ' // Initialize: this to defaults, base class fields to input.', + ' assert(instance_extensions);', + ' *this = %s(*instance_extensions);' % struct_type]) + + struct.extend([ + '', + ' static const std::vector V_1_0_promoted_%s_extensions = {' % type.lower() ]) + struct.extend([' %s_EXTENSION_NAME,' % ext_name.upper() for ext_name in promoted_ext_list]) + struct.extend([ + ' };', + '', + ' // Initialize struct data, robust to invalid pCreateInfo', + ' if (pCreateInfo->ppEnabledExtensionNames) {', + ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {', + ' if (!pCreateInfo->ppEnabledExtensionNames[i]) continue;', + ' auto info = get_info(pCreateInfo->ppEnabledExtensionNames[i]);', + ' if(info.state) this->*(info.state) = true;', + ' }', + ' }', + ' uint32_t api_version = NormalizeApiVersion(requested_api_version);', + ' if (api_version >= VK_API_VERSION_1_1) {', + ' for (auto promoted_ext : V_1_0_promoted_%s_extensions) {' % type.lower(), + ' auto info = get_info(promoted_ext);', + ' assert(info.state);', + ' if (info.state) this->*(info.state) = true;', + ' }', + ' }', + ' return api_version;', + ' }', + '};']) + + # Output reference lists of instance/device extension names + struct.extend(['', 'static const char * const k%sExtensionNames = ' % type]) + struct.extend([guarded(info['ifdef'], ' %s' % info['define']) for ext_name, info in extension_items]) + struct.extend([';', '']) + output.extend(struct) + + output.extend(['', '#endif // VK_EXTENSION_HELPER_H_']) + return '\n'.join(output) + # + # Combine object types helper header file preamble with body text and return + def GenerateObjectTypesHelperHeader(self): + object_types_helper_header = '\n' + object_types_helper_header += '#pragma once\n' + object_types_helper_header += '\n' + object_types_helper_header += '#include \n\n' + object_types_helper_header += self.GenerateObjectTypesHeader() + return object_types_helper_header + # + # Object types header: create object enum type header file + def GenerateObjectTypesHeader(self): + object_types_header = '' + object_types_header += '// Object Type enum for validation layer internal object handling\n' + object_types_header += 'typedef enum VulkanObjectType {\n' + object_types_header += ' kVulkanObjectTypeUnknown = 0,\n' + enum_num = 1 + type_list = []; + enum_entry_map = {} + + # Output enum definition as each handle is processed, saving the names to use for the conversion routine + for item in self.object_types: + fixup_name = item[2:] + enum_entry = 'kVulkanObjectType%s' % fixup_name + enum_entry_map[item] = enum_entry + object_types_header += ' ' + enum_entry + object_types_header += ' = %d,\n' % enum_num + enum_num += 1 + type_list.append(enum_entry) + object_types_header += ' kVulkanObjectTypeMax = %d,\n' % enum_num + object_types_header += ' // Aliases for backwards compatibilty of "promoted" types\n' + for (name, alias) in self.object_type_aliases: + fixup_name = name[2:] + object_types_header += ' kVulkanObjectType{} = {},\n'.format(fixup_name, enum_entry_map[alias]) + object_types_header += '} VulkanObjectType;\n\n' + + # Output name string helper + object_types_header += '// Array of object name strings for OBJECT_TYPE enum conversion\n' + object_types_header += 'static const char * const object_string[kVulkanObjectTypeMax] = {\n' + object_types_header += ' "Unknown",\n' + for item in self.object_types: + fixup_name = item[2:] + object_types_header += ' "%s",\n' % fixup_name + object_types_header += '};\n' + + # Key creation helper for map comprehensions that convert between k and VK symbols + def to_key(regex, raw_key): return re.search(regex, raw_key).group(1).lower().replace("_","") + + # Output a conversion routine from the layer object definitions to the debug report definitions + # As the VK_DEBUG_REPORT types are not being updated, specify UNKNOWN for unmatched types + object_types_header += '\n' + object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n' + object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n' + object_types_header += ' VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown\n' + + dbg_re = '^VK_DEBUG_REPORT_OBJECT_TYPE_(.*)_EXT$' + dbg_map = {to_key(dbg_re, dbg) : dbg for dbg in self.debug_report_object_types} + dbg_default = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT' + for object_type in type_list: + vk_object_type = dbg_map.get(object_type.replace("kVulkanObjectType", "").lower(), dbg_default) + object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) + object_types_header += '};\n' + + # Output a conversion routine from the layer object definitions to the core object type definitions + # This will intentionally *fail* for unmatched types as the VK_OBJECT_TYPE list should match the kVulkanObjectType list + object_types_header += '\n' + object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n' + object_types_header += 'const VkObjectType get_object_type_enum[] = {\n' + object_types_header += ' VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown\n' + + vko_re = '^VK_OBJECT_TYPE_(.*)' + vko_map = {to_key(vko_re, vko) : vko for vko in self.core_object_types} + for object_type in type_list: + vk_object_type = vko_map[object_type.replace("kVulkanObjectType", "").lower()] + object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) + object_types_header += '};\n' + + # Create a function to convert from VkDebugReportObjectTypeEXT to VkObjectType + object_types_header += '\n' + object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n' + object_types_header += 'static inline VkObjectType convertDebugReportObjectToCoreObject(VkDebugReportObjectTypeEXT debug_report_obj){\n' + object_types_header += ' if (debug_report_obj == VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) {\n' + object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n' + for core_object_type in self.core_object_types: + core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower() + core_target_type = core_target_type.replace("_", "") + for dr_object_type in self.debug_report_object_types: + dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower() + dr_target_type = dr_target_type[:-4] + dr_target_type = dr_target_type.replace("_", "") + if core_target_type == dr_target_type: + object_types_header += ' } else if (debug_report_obj == %s) {\n' % dr_object_type + object_types_header += ' return %s;\n' % core_object_type + break + object_types_header += ' }\n' + object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n' + object_types_header += '}\n' + + # Create a function to convert from VkObjectType to VkDebugReportObjectTypeEXT + object_types_header += '\n' + object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n' + object_types_header += 'static inline VkDebugReportObjectTypeEXT convertCoreObjectToDebugReportObject(VkObjectType core_report_obj){\n' + object_types_header += ' if (core_report_obj == VK_OBJECT_TYPE_UNKNOWN) {\n' + object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n' + for core_object_type in self.core_object_types: + core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower() + core_target_type = core_target_type.replace("_", "") + for dr_object_type in self.debug_report_object_types: + dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower() + dr_target_type = dr_target_type[:-4] + dr_target_type = dr_target_type.replace("_", "") + if core_target_type == dr_target_type: + object_types_header += ' } else if (core_report_obj == %s) {\n' % core_object_type + object_types_header += ' return %s;\n' % dr_object_type + break + object_types_header += ' }\n' + object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n' + object_types_header += '}\n' + return object_types_header + # + # Determine if a structure needs a safe_struct helper function + # That is, it has an sType or one of its members is a pointer + def NeedSafeStruct(self, structure): + if 'sType' == structure.name: + return True + for member in structure.members: + if member.ispointer == True: + return True + return False + # + # Combine safe struct helper source file preamble with body text and return + def GenerateSafeStructHelperSource(self): + safe_struct_helper_source = '\n' + safe_struct_helper_source += '#include "vk_safe_struct.h"\n' + safe_struct_helper_source += '#include \n' + safe_struct_helper_source += '#ifdef VK_USE_PLATFORM_ANDROID_KHR\n' + safe_struct_helper_source += '#if __ANDROID_API__ < __ANDROID_API_O__\n' + safe_struct_helper_source += 'struct AHardwareBuffer {};\n' + safe_struct_helper_source += '#endif\n' + safe_struct_helper_source += '#endif\n' + + safe_struct_helper_source += '\n' + safe_struct_helper_source += self.GenerateSafeStructSource() + return safe_struct_helper_source + # + # safe_struct source -- create bodies of safe struct helper functions + def GenerateSafeStructSource(self): + safe_struct_body = [] + wsi_structs = ['VkXlibSurfaceCreateInfoKHR', + 'VkXcbSurfaceCreateInfoKHR', + 'VkWaylandSurfaceCreateInfoKHR', + 'VkMirSurfaceCreateInfoKHR', + 'VkAndroidSurfaceCreateInfoKHR', + 'VkWin32SurfaceCreateInfoKHR' + ] + for item in self.structMembers: + if self.NeedSafeStruct(item) == False: + continue + if item.name in wsi_structs: + continue + if item.ifdef_protect != None: + safe_struct_body.append("#ifdef %s\n" % item.ifdef_protect) + ss_name = "safe_%s" % item.name + init_list = '' # list of members in struct constructor initializer + default_init_list = '' # Default constructor just inits ptrs to nullptr in initializer + init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members + construct_txt = '' # Body of constuctor as well as body of initialize() func following init_func_txt + destruct_txt = '' + + custom_construct_txt = { + # VkWriteDescriptorSet is special case because pointers may be non-null but ignored + 'VkWriteDescriptorSet' : + ' switch (descriptorType) {\n' + ' case VK_DESCRIPTOR_TYPE_SAMPLER:\n' + ' case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n' + ' case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n' + ' case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n' + ' case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n' + ' if (descriptorCount && in_struct->pImageInfo) {\n' + ' pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n' + ' for (uint32_t i=0; ipImageInfo[i];\n' + ' }\n' + ' }\n' + ' break;\n' + ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n' + ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n' + ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n' + ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n' + ' if (descriptorCount && in_struct->pBufferInfo) {\n' + ' pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n' + ' for (uint32_t i=0; ipBufferInfo[i];\n' + ' }\n' + ' }\n' + ' break;\n' + ' case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n' + ' case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n' + ' if (descriptorCount && in_struct->pTexelBufferView) {\n' + ' pTexelBufferView = new VkBufferView[descriptorCount];\n' + ' for (uint32_t i=0; ipTexelBufferView[i];\n' + ' }\n' + ' }\n' + ' break;\n' + ' default:\n' + ' break;\n' + ' }\n', + 'VkShaderModuleCreateInfo' : + ' if (in_struct->pCode) {\n' + ' pCode = reinterpret_cast(new uint8_t[codeSize]);\n' + ' memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n' + ' }\n', + # VkGraphicsPipelineCreateInfo is special case because its pointers may be non-null but ignored + 'VkGraphicsPipelineCreateInfo' : + ' if (stageCount && in_struct->pStages) {\n' + ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' + ' for (uint32_t i=0; ipStages[i]);\n' + ' }\n' + ' }\n' + ' if (in_struct->pVertexInputState)\n' + ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(in_struct->pVertexInputState);\n' + ' else\n' + ' pVertexInputState = NULL;\n' + ' if (in_struct->pInputAssemblyState)\n' + ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(in_struct->pInputAssemblyState);\n' + ' else\n' + ' pInputAssemblyState = NULL;\n' + ' bool has_tessellation_stage = false;\n' + ' if (stageCount && pStages)\n' + ' for (uint32_t i=0; ipTessellationState && has_tessellation_stage)\n' + ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(in_struct->pTessellationState);\n' + ' else\n' + ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' + ' bool has_rasterization = in_struct->pRasterizationState ? !in_struct->pRasterizationState->rasterizerDiscardEnable : false;\n' + ' if (in_struct->pViewportState && has_rasterization) {\n' + ' bool is_dynamic_viewports = false;\n' + ' bool is_dynamic_scissors = false;\n' + ' if (in_struct->pDynamicState && in_struct->pDynamicState->pDynamicStates) {\n' + ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_viewports; ++i)\n' + ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_VIEWPORT)\n' + ' is_dynamic_viewports = true;\n' + ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_scissors; ++i)\n' + ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_SCISSOR)\n' + ' is_dynamic_scissors = true;\n' + ' }\n' + ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(in_struct->pViewportState, is_dynamic_viewports, is_dynamic_scissors);\n' + ' } else\n' + ' pViewportState = NULL; // original pViewportState pointer ignored\n' + ' if (in_struct->pRasterizationState)\n' + ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(in_struct->pRasterizationState);\n' + ' else\n' + ' pRasterizationState = NULL;\n' + ' if (in_struct->pMultisampleState && has_rasterization)\n' + ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(in_struct->pMultisampleState);\n' + ' else\n' + ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' + ' // needs a tracked subpass state uses_depthstencil_attachment\n' + ' if (in_struct->pDepthStencilState && has_rasterization && uses_depthstencil_attachment)\n' + ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(in_struct->pDepthStencilState);\n' + ' else\n' + ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' + ' // needs a tracked subpass state usesColorAttachment\n' + ' if (in_struct->pColorBlendState && has_rasterization && uses_color_attachment)\n' + ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(in_struct->pColorBlendState);\n' + ' else\n' + ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' + ' if (in_struct->pDynamicState)\n' + ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(in_struct->pDynamicState);\n' + ' else\n' + ' pDynamicState = NULL;\n', + # VkPipelineViewportStateCreateInfo is special case because its pointers may be non-null but ignored + 'VkPipelineViewportStateCreateInfo' : + ' if (in_struct->pViewports && !is_dynamic_viewports) {\n' + ' pViewports = new VkViewport[in_struct->viewportCount];\n' + ' memcpy ((void *)pViewports, (void *)in_struct->pViewports, sizeof(VkViewport)*in_struct->viewportCount);\n' + ' }\n' + ' else\n' + ' pViewports = NULL;\n' + ' if (in_struct->pScissors && !is_dynamic_scissors) {\n' + ' pScissors = new VkRect2D[in_struct->scissorCount];\n' + ' memcpy ((void *)pScissors, (void *)in_struct->pScissors, sizeof(VkRect2D)*in_struct->scissorCount);\n' + ' }\n' + ' else\n' + ' pScissors = NULL;\n', + # VkDescriptorSetLayoutBinding is special case because its pImmutableSamplers pointer may be non-null but ignored + 'VkDescriptorSetLayoutBinding' : + ' const bool sampler_type = in_struct->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || in_struct->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n' + ' if (descriptorCount && in_struct->pImmutableSamplers && sampler_type) {\n' + ' pImmutableSamplers = new VkSampler[descriptorCount];\n' + ' for (uint32_t i=0; ipImmutableSamplers[i];\n' + ' }\n' + ' }\n', + } + + custom_copy_txt = { + # VkGraphicsPipelineCreateInfo is special case because it has custom construct parameters + 'VkGraphicsPipelineCreateInfo' : + ' if (stageCount && src.pStages) {\n' + ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' + ' for (uint32_t i=0; irasterizerDiscardEnable : false;\n' + ' if (src.pViewportState && has_rasterization) {\n' + ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(*src.pViewportState);\n' + ' } else\n' + ' pViewportState = NULL; // original pViewportState pointer ignored\n' + ' if (src.pRasterizationState)\n' + ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(*src.pRasterizationState);\n' + ' else\n' + ' pRasterizationState = NULL;\n' + ' if (src.pMultisampleState && has_rasterization)\n' + ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(*src.pMultisampleState);\n' + ' else\n' + ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' + ' if (src.pDepthStencilState && has_rasterization)\n' + ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(*src.pDepthStencilState);\n' + ' else\n' + ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' + ' if (src.pColorBlendState && has_rasterization)\n' + ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(*src.pColorBlendState);\n' + ' else\n' + ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' + ' if (src.pDynamicState)\n' + ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(*src.pDynamicState);\n' + ' else\n' + ' pDynamicState = NULL;\n', + # VkPipelineViewportStateCreateInfo is special case because it has custom construct parameters + 'VkPipelineViewportStateCreateInfo' : + ' if (src.pViewports) {\n' + ' pViewports = new VkViewport[src.viewportCount];\n' + ' memcpy ((void *)pViewports, (void *)src.pViewports, sizeof(VkViewport)*src.viewportCount);\n' + ' }\n' + ' else\n' + ' pViewports = NULL;\n' + ' if (src.pScissors) {\n' + ' pScissors = new VkRect2D[src.scissorCount];\n' + ' memcpy ((void *)pScissors, (void *)src.pScissors, sizeof(VkRect2D)*src.scissorCount);\n' + ' }\n' + ' else\n' + ' pScissors = NULL;\n', + } + + custom_destruct_txt = {'VkShaderModuleCreateInfo' : + ' if (pCode)\n' + ' delete[] reinterpret_cast(pCode);\n' } + + for member in item.members: + m_type = member.type + if member.type in self.structNames: + member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) + if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: + m_type = 'safe_%s' % member.type + if member.ispointer and 'safe_' not in m_type and self.TypeContainsObjectHandle(member.type, False) == False: + # Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in + if m_type in ['void', 'char']: + # For these exceptions just copy initial value over for now + init_list += '\n %s(in_struct->%s),' % (member.name, member.name) + init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) + else: + default_init_list += '\n %s(nullptr),' % (member.name) + init_list += '\n %s(nullptr),' % (member.name) + init_func_txt += ' %s = nullptr;\n' % (member.name) + if 'pNext' != member.name and 'void' not in m_type: + if not member.isstaticarray and (member.len is None or '/' in member.len): + construct_txt += ' if (in_struct->%s) {\n' % member.name + construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name) + construct_txt += ' }\n' + destruct_txt += ' if (%s)\n' % member.name + destruct_txt += ' delete %s;\n' % member.name + else: + construct_txt += ' if (in_struct->%s) {\n' % member.name + construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len) + construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len) + construct_txt += ' }\n' + destruct_txt += ' if (%s)\n' % member.name + destruct_txt += ' delete[] %s;\n' % member.name + elif member.isstaticarray or member.len is not None: + if member.len is None: + # Extract length of static array by grabbing val between [] + static_array_size = re.match(r"[^[]*\[([^]]*)\]", member.cdecl) + construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % static_array_size.group(1) + construct_txt += ' %s[i] = in_struct->%s[i];\n' % (member.name, member.name) + construct_txt += ' }\n' + else: + # Init array ptr to NULL + default_init_list += '\n %s(nullptr),' % member.name + init_list += '\n %s(nullptr),' % member.name + init_func_txt += ' %s = nullptr;\n' % member.name + array_element = 'in_struct->%s[i]' % member.name + if member.type in self.structNames: + member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) + if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: + array_element = '%s(&in_struct->safe_%s[i])' % (member.type, member.name) + construct_txt += ' if (%s && in_struct->%s) {\n' % (member.len, member.name) + construct_txt += ' %s = new %s[%s];\n' % (member.name, m_type, member.len) + destruct_txt += ' if (%s)\n' % member.name + destruct_txt += ' delete[] %s;\n' % member.name + construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % (member.len) + if 'safe_' in m_type: + construct_txt += ' %s[i].initialize(&in_struct->%s[i]);\n' % (member.name, member.name) + else: + construct_txt += ' %s[i] = %s;\n' % (member.name, array_element) + construct_txt += ' }\n' + construct_txt += ' }\n' + elif member.ispointer == True: + construct_txt += ' if (in_struct->%s)\n' % member.name + construct_txt += ' %s = new %s(in_struct->%s);\n' % (member.name, m_type, member.name) + construct_txt += ' else\n' + construct_txt += ' %s = NULL;\n' % member.name + destruct_txt += ' if (%s)\n' % member.name + destruct_txt += ' delete %s;\n' % member.name + elif 'safe_' in m_type: + init_list += '\n %s(&in_struct->%s),' % (member.name, member.name) + init_func_txt += ' %s.initialize(&in_struct->%s);\n' % (member.name, member.name) + else: + init_list += '\n %s(in_struct->%s),' % (member.name, member.name) + init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) + if '' != init_list: + init_list = init_list[:-1] # hack off final comma + if item.name in custom_construct_txt: + construct_txt = custom_construct_txt[item.name] + if item.name in custom_destruct_txt: + destruct_txt = custom_destruct_txt[item.name] + safe_struct_body.append("\n%s::%s(const %s* in_struct%s) :%s\n{\n%s}" % (ss_name, ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_list, construct_txt)) + if '' != default_init_list: + default_init_list = " :%s" % (default_init_list[:-1]) + safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list)) + # Create slight variation of init and construct txt for copy constructor that takes a src object reference vs. struct ptr + copy_construct_init = init_func_txt.replace('in_struct->', 'src.') + copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line + copy_construct_txt = copy_construct_txt.replace('(in_struct->', '(*src.') # Pass object to copy constructors + copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object + if item.name in custom_copy_txt: + copy_construct_txt = custom_copy_txt[item.name] + copy_assign_txt = ' if (&src == this) return *this;\n\n' + destruct_txt + '\n' + copy_construct_init + copy_construct_txt + '\n return *this;' + safe_struct_body.append("\n%s::%s(const %s& src)\n{\n%s%s}" % (ss_name, ss_name, ss_name, copy_construct_init, copy_construct_txt)) # Copy constructor + safe_struct_body.append("\n%s& %s::operator=(const %s& src)\n{\n%s\n}" % (ss_name, ss_name, ss_name, copy_assign_txt)) # Copy assignment operator + safe_struct_body.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt)) + safe_struct_body.append("\nvoid %s::initialize(const %s* in_struct%s)\n{\n%s%s}" % (ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_func_txt, construct_txt)) + # Copy initializer uses same txt as copy constructor but has a ptr and not a reference + init_copy = copy_construct_init.replace('src.', 'src->') + init_construct = copy_construct_txt.replace('src.', 'src->') + safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct)) + if item.ifdef_protect != None: + safe_struct_body.append("#endif // %s\n" % item.ifdef_protect) + return "\n".join(safe_struct_body) + # + # Generate the type map + def GenerateTypeMapHelperHeader(self): + prefix = 'Lvl' + fprefix = 'lvl_' + typemap = prefix + 'TypeMap' + idmap = prefix + 'STypeMap' + type_member = 'Type' + id_member = 'kSType' + id_decl = 'static const VkStructureType ' + generic_header = prefix + 'GenericHeader' + generic_mod_header = prefix + 'GenericModHeader' + typename_func = fprefix + 'typename' + idname_func = fprefix + 'stype_name' + find_func = fprefix + 'find_in_chain' + find_mod_func = fprefix + 'find_mod_in_chain' + init_func = fprefix + 'init_struct' + + explanatory_comment = '\n'.join(( + '// These empty generic templates are specialized for each type with sType', + '// members and for each sType -- providing a two way map between structure', + '// types and sTypes')) + + empty_typemap = 'template struct ' + typemap + ' {};' + typemap_format = 'template <> struct {template}<{typename}> {{\n' + typemap_format += ' {id_decl}{id_member} = {id_value};\n' + typemap_format += '}};\n' + + empty_idmap = 'template struct ' + idmap + ' {};' + idmap_format = ''.join(( + 'template <> struct {template}<{id_value}> {{\n', + ' typedef {typename} {typedef};\n', + '}};\n')) + + # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file + utilities_format = '\n'.join(( + '// Header "base class" for pNext chain traversal', + 'struct {header} {{', + ' VkStructureType sType;', + ' const {header} *pNext;', + '}};', + 'struct {mod_header} {{', + ' VkStructureType sType;', + ' {mod_header} *pNext;', + '}};', + '', + '// Find an entry of the given type in the pNext chain', + 'template const T *{find_func}(const void *next) {{', + ' const {header} *current = reinterpret_cast(next);', + ' const T *found = nullptr;', + ' while (current) {{', + ' if ({type_map}::{id_member} == current->sType) {{', + ' found = reinterpret_cast(current);', + ' current = nullptr;', + ' }} else {{', + ' current = current->pNext;', + ' }}', + ' }}', + ' return found;', + '}}', + '// Find an entry of the given type in the pNext chain', + 'template T *{find_mod_func}(void *next) {{', + ' {mod_header} *current = reinterpret_cast<{mod_header} *>(next);', + ' T *found = nullptr;', + ' while (current) {{', + ' if ({type_map}::{id_member} == current->sType) {{', + ' found = reinterpret_cast(current);', + ' current = nullptr;', + ' }} else {{', + ' current = current->pNext;', + ' }}', + ' }}', + ' return found;', + '}}', + '', + '// Init the header of an sType struct with pNext', + 'template T {init_func}(void *p_next) {{', + ' T out = {{}};', + ' out.sType = {type_map}::kSType;', + ' out.pNext = p_next;', + ' return out;', + '}}', + '', + '// Init the header of an sType struct', + 'template T {init_func}() {{', + ' T out = {{}};', + ' out.sType = {type_map}::kSType;', + ' return out;', + '}}', + + '')) + + code = [] + + # Generate header + code.append('\n'.join(( + '#pragma once', + '#include \n', + explanatory_comment, '', + empty_idmap, + empty_typemap, ''))) + + # Generate the specializations for each type and stype + for item in self.structMembers: + typename = item.name + info = self.structTypes.get(typename) + if not info: + continue + + if item.ifdef_protect != None: + code.append('#ifdef %s' % item.ifdef_protect) + + code.append('// Map type {} to id {}'.format(typename, info.value)) + code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value, + id_decl=id_decl, id_member=id_member)) + code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, typedef=type_member)) + + if item.ifdef_protect != None: + code.append('#endif // %s' % item.ifdef_protect) + + # Generate utilities for all types + code.append('\n'.join(( + utilities_format.format(id_member=id_member, id_map=idmap, type_map=typemap, + type_member=type_member, header=generic_header, mod_header=generic_mod_header, + typename_func=typename_func, idname_func=idname_func, find_func=find_func, + find_mod_func=find_mod_func, init_func=init_func), '' + ))) + + return "\n".join(code) + + # + # Create a helper file and return it as a string + def OutputDestFile(self): + if self.helper_file_type == 'enum_string_header': + return self.GenerateEnumStringHelperHeader() + elif self.helper_file_type == 'safe_struct_header': + return self.GenerateSafeStructHelperHeader() + elif self.helper_file_type == 'safe_struct_source': + return self.GenerateSafeStructHelperSource() + elif self.helper_file_type == 'object_types_header': + return self.GenerateObjectTypesHelperHeader() + elif self.helper_file_type == 'extension_helper_header': + return self.GenerateExtensionHelperHeader() + elif self.helper_file_type == 'typemap_helper_header': + return self.GenerateTypeMapHelperHeader() + else: + return 'Bad Helper File Generator Option %s' % self.helper_file_type diff --git a/scripts/generators/vulkaninfo_generator.py b/scripts/generators/vulkaninfo_generator.py new file mode 100644 index 00000000..20e408e4 --- /dev/null +++ b/scripts/generators/vulkaninfo_generator.py @@ -0,0 +1,1729 @@ +#!/usr/bin/python3 +# +# Copyright (c) 2019-2022 Valve Corporation +# Copyright (c) 2019-2022 LunarG, Inc. +# Copyright (c) 2019-2022 Google Inc. +# Copyright (c) 2023-2024 RasterGrid Kft. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: Charles Giessen + +import re +import os +import sys +import copy +import operator +from collections import OrderedDict +import generator as gen +from common_codegen import GetFeatureProtect +from generator import GeneratorOptions, OutputGenerator +import xml.etree.ElementTree as etree + +LICENSE_HEADER = ''' +/* + * Copyright (c) 2019-2022 The Khronos Group Inc. + * Copyright (c) 2019-2022 Valve Corporation + * Copyright (c) 2019-2022 LunarG, Inc. + * Copyright (c) 2023-2024 RasterGrid Kft. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Author: Charles Giessen + * + */ + +/* + * This file is generated from the Khronos Vulkan XML API Registry. + */ +''' + +CUSTOM_FORMATTERS = r''' +template +std::string to_hex_str(const T i) { + std::stringstream stream; + stream << "0x" << std::setfill('0') << std::setw(sizeof(T)) << std::hex << i; + return stream.str(); +} + +template +std::string to_hex_str(Printer &p, const T i) { + if (p.Type() == OutputType::json) + return std::to_string(i); + else if (p.Type() == OutputType::vkconfig_output) + return std::string("\"") + to_hex_str(i) + std::string("\""); + else + return to_hex_str(i); +} + +''' + + +# used in the .cpp code +STRUCTURES_TO_GEN = ['VkExtent3D', 'VkExtent2D', 'VkPhysicalDeviceLimits', 'VkPhysicalDeviceFeatures', 'VkPhysicalDeviceSparseProperties', + 'VkSurfaceCapabilitiesKHR', 'VkSurfaceFormatKHR', 'VkLayerProperties', 'VkPhysicalDeviceToolProperties', 'VkFormatProperties', + 'VkSurfacePresentScalingCapabilitiesKHR', 'VkSurfacePresentModeCompatibilityKHR', 'VkPhysicalDeviceHostImageCopyProperties', + 'VkVideoProfileInfoKHR', 'VkVideoCapabilitiesKHR', 'VkVideoFormatPropertiesKHR'] +ENUMS_TO_GEN = ['VkResult', 'VkFormat', 'VkPresentModeKHR', + 'VkPhysicalDeviceType', 'VkImageTiling'] +FLAGS_TO_GEN = ['VkSurfaceTransformFlagsKHR', 'VkCompositeAlphaFlagsKHR', 'VkSurfaceCounterFlagsEXT', 'VkQueueFlags', + 'VkDeviceGroupPresentModeFlagsKHR', 'VkFormatFeatureFlags', 'VkFormatFeatureFlags2', 'VkMemoryPropertyFlags', 'VkMemoryHeapFlags'] +FLAG_STRINGS_TO_GEN = ['VkQueueFlags'] + +STRUCT_SHORT_VERSIONS_TO_GEN = ['VkExtent3D'] + +STRUCT_COMPARISONS_TO_GEN = ['VkSurfaceFormatKHR', 'VkSurfaceFormat2KHR', 'VkSurfaceCapabilitiesKHR', + 'VkSurfaceCapabilities2KHR', 'VkSurfaceCapabilities2EXT'] +# don't generate these structures +STRUCT_BLACKLIST = ['VkVideoProfileListInfoKHR', 'VkDrmFormatModifierPropertiesListEXT', 'VkDrmFormatModifierPropertiesEXT', 'VkDrmFormatModifierPropertiesList2EXT'] +# These structures are only used in version 1.1, otherwise they are included in the promoted structs +STRUCT_1_1_LIST = ['VkPhysicalDeviceProtectedMemoryFeatures', 'VkPhysicalDeviceShaderDrawParametersFeatures', 'VkPhysicalDeviceSubgroupProperties', 'VkPhysicalDeviceProtectedMemoryProperties'] + +# generate these structures such that they only print when not in json mode (as json wants them separate) +PORTABILITY_STRUCTS = ['VkPhysicalDevicePortabilitySubsetFeaturesKHR', 'VkPhysicalDevicePortabilitySubsetPropertiesKHR'] + +# iostream or custom outputter handles these types +PREDEFINED_TYPES = ['char', 'VkBool32', 'uint32_t', 'uint8_t', 'int32_t', + 'float', 'uint64_t', 'size_t', 'VkDeviceSize', 'int64_t'] + +NAMES_TO_IGNORE = ['sType', 'pNext'] + +EXTENSION_TYPE_INSTANCE = 'instance' +EXTENSION_TYPE_DEVICE = 'device' +EXTENSION_TYPE_BOTH = 'both' + +# Types that need pNext Chains built. 'extends' is the xml tag used in the structextends member. 'type' can be device, instance, or both +EXTENSION_CATEGORIES = OrderedDict(( + ('phys_device_props2', + {'extends': 'VkPhysicalDeviceProperties2', + 'type': EXTENSION_TYPE_BOTH, + 'holder_type': 'VkPhysicalDeviceProperties2', + 'print_iterator': True, + 'can_show_promoted_structs': True, + 'ignore_vendor_exclusion': False}), + ('phys_device_mem_props2', + {'extends': 'VkPhysicalDeviceMemoryProperties2', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type':'VkPhysicalDeviceMemoryProperties2', + 'print_iterator': False, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': False}), + ('phys_device_features2', + {'extends': 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type': 'VkPhysicalDeviceFeatures2', + 'print_iterator': True, + 'can_show_promoted_structs': True, + 'ignore_vendor_exclusion': False}), + ('surface_capabilities2', + {'extends': 'VkSurfaceCapabilities2KHR', + 'type': EXTENSION_TYPE_BOTH, + 'holder_type': 'VkSurfaceCapabilities2KHR', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': False, + 'exclude': ['VkSurfacePresentScalingCapabilitiesKHR', 'VkSurfacePresentModeCompatibilityKHR']}), + ('format_properties2', + {'extends': 'VkFormatProperties2', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type':'VkFormatProperties2', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': False}), + ('queue_properties2', + {'extends': 'VkQueueFamilyProperties2', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type': 'VkQueueFamilyProperties2', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': False}), + ('video_profile_info', + {'extends': 'VkVideoProfileInfoKHR', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type': 'VkVideoProfileInfoKHR', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': True}), + ('video_capabilities', + {'extends': 'VkVideoCapabilitiesKHR', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type': 'VkVideoCapabilitiesKHR', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': True,}), + ('video_format_properties', + {'extends': 'VkVideoFormatPropertiesKHR', + 'type': EXTENSION_TYPE_DEVICE, + 'holder_type': 'VkVideoFormatPropertiesKHR', + 'print_iterator': True, + 'can_show_promoted_structs': False, + 'ignore_vendor_exclusion': True}) + )) +class VulkanInfoGeneratorOptions(GeneratorOptions): + def __init__(self, + conventions=None, + input=None, + filename=None, + directory='.', + genpath = None, + apiname=None, + profile=None, + versions='.*', + emitversions='.*', + defaultExtensions=None, + addExtensions=None, + removeExtensions=None, + emitExtensions=None, + sortProcedure=None, + prefixText='', + genFuncPointers=True, + protectFile=True, + protectFeature=True, + protectProto=None, + protectProtoStr=None, + apicall='', + apientry='', + apientryp='', + indentFuncProto=True, + indentFuncPointer=False, + alignFuncParam=0, + expandEnumerants=True, + registryFile='vk.xml' + ): + GeneratorOptions.__init__(self, + conventions = conventions, + filename = filename, + directory = directory, + genpath = genpath, + apiname = apiname, + profile = profile, + versions = versions, + emitversions = emitversions, + defaultExtensions = defaultExtensions, + addExtensions = addExtensions, + removeExtensions = removeExtensions, + emitExtensions = emitExtensions, + sortProcedure = sortProcedure) + self.input = input + self.prefixText = prefixText + self.genFuncPointers = genFuncPointers + self.protectFile = protectFile + self.protectFeature = protectFeature + self.protectProto = protectProto + self.protectProtoStr = protectProtoStr + self.apicall = apicall + self.apientry = apientry + self.apientryp = apientryp + self.indentFuncProto = indentFuncProto + self.indentFuncPointer = indentFuncPointer + self.alignFuncParam = alignFuncParam + self.registryFile = registryFile + +# VulkanInfoGenerator - subclass of OutputGenerator. +# Generates a vulkan info output helper function + + +class VulkanInfoGenerator(OutputGenerator): + + def __init__(self, + errFile=sys.stderr, + warnFile=sys.stderr, + diagFile=sys.stdout): + OutputGenerator.__init__(self, errFile, warnFile, diagFile) + + self.constants = OrderedDict() + + self.types_to_gen = set() + + self.extension_sets = OrderedDict() + for ext_cat in EXTENSION_CATEGORIES.keys(): + self.extension_sets[ext_cat] = set() + + self.enums = [] + self.flags = [] + self.bitmasks = [] + self.format_ranges = [] + self.all_structures = [] + self.aliases = OrderedDict() + + self.extFuncs = OrderedDict() + self.extTypes = OrderedDict() + + self.vendor_abbreviations = [] + self.vulkan_versions = [] + + def beginFile(self, genOpts): + gen.OutputGenerator.beginFile(self, genOpts) + + for node in self.registry.reg.findall('enums'): + if node.get('name') == 'API Constants': + for item in node.findall('enum'): + self.constants[item.get('name')] = item.get('value') + + for node in self.registry.reg.find('extensions').findall('extension'): + ext = VulkanExtension(node) + for item in ext.vktypes: + if item not in self.extTypes: + self.extTypes[item] = [] + self.extTypes[item].append(ext) + for item in ext.vkfuncs: + self.extFuncs[item] = ext + + # need list of venders to blacklist vendor extensions + for tag in self.registry.reg.find('tags'): + if tag.get('name') not in ['KHR', 'EXT']: + self.vendor_abbreviations.append('_' + tag.get('name')) + + for ver in self.registry.reg.findall('feature'): + self.vulkan_versions.append(VulkanVersion(ver)) + + def endFile(self): + self.findFormatRanges() + + # gather the types that are needed to generate + types_to_gen = set() + for s in ENUMS_TO_GEN: + types_to_gen.add(s) + + for f in FLAGS_TO_GEN: + types_to_gen.add(f) + + types_to_gen.update( + GatherTypesToGen(self.all_structures, STRUCTURES_TO_GEN)) + for key, info in EXTENSION_CATEGORIES.items(): + types_to_gen.update( + GatherTypesToGen(self.all_structures, self.extension_sets[key], info.get('exclude'))) + types_to_gen = sorted(types_to_gen) + + names_of_structures_to_gen = set() + for s in self.all_structures: + if s.name in types_to_gen: + names_of_structures_to_gen.add(s.name) + names_of_structures_to_gen = sorted(names_of_structures_to_gen) + + structs_to_comp = set() + for s in STRUCT_COMPARISONS_TO_GEN: + structs_to_comp.add(s) + structs_to_comp.update( + GatherTypesToGen(self.all_structures, STRUCT_COMPARISONS_TO_GEN)) + + for key, value in self.extension_sets.items(): + self.extension_sets[key] = sorted(value) + + self.enums = sorted(self.enums, key=operator.attrgetter('name')) + self.flags = sorted(self.flags, key=operator.attrgetter('name')) + self.bitmasks = sorted(self.bitmasks, key=operator.attrgetter('name')) + self.all_structures = sorted(self.all_structures, key=operator.attrgetter('name')) + + # print the types gathered + out = '' + out += LICENSE_HEADER + '\n' + out += '#include "vulkaninfo.h"\n' + out += '#include "outputprinter.h"\n' + out += CUSTOM_FORMATTERS + + out += self.genVideoEnums() + + for enum in (e for e in self.enums if e.name in types_to_gen): + out += PrintEnumToString(enum, self) + out += PrintEnum(enum, self) + + for flag in self.flags: + if flag.name in types_to_gen or flag.enum in types_to_gen: + for bitmask in (b for b in self.bitmasks if b.name == flag.enum): + out += PrintBitMask(bitmask, flag.name, self) + + if flag.name in FLAG_STRINGS_TO_GEN: + for bitmask in (b for b in self.bitmasks if b.name == flag.enum): + out += PrintBitMaskToString(bitmask, flag.name, self) + + for s in (x for x in self.all_structures if x.name in types_to_gen and x.name not in STRUCT_BLACKLIST): + out += PrintStructure(s) + + for key, value in EXTENSION_CATEGORIES.items(): + out += PrintChainStruct(key, self.extension_sets[key], self.all_structures, value, self.extTypes, self.aliases, self.vulkan_versions) + + for s in (x for x in self.all_structures if x.name in structs_to_comp): + out += PrintStructComparisonForwardDecl(s) + for s in (x for x in self.all_structures if x.name in structs_to_comp): + out += PrintStructComparison(s) + for s in (x for x in self.all_structures if x.name in STRUCT_SHORT_VERSIONS_TO_GEN): + out += PrintStructShort(s) + + out += 'auto format_ranges = std::array{\n' + for f in self.format_ranges: + out += f' FormatRange{{{f.minimum_instance_version}, {f.extension_name if f.extension_name is not None else "nullptr"}, ' + out += f'static_cast({f.first_format}), static_cast({f.last_format})}},\n' + out += '};\n' + + out += self.genVideoProfileUtils() + + gen.write(out, file=self.outFile) + + gen.OutputGenerator.endFile(self) + + def genVideoEnums(self): + # We need to add dumping utilities for enums declared in the video std headers and directly + # present in the Vulkan API structures. In order to do that we really have no choice but + # to parse the video.xml and generate the utilities based on the enum types defined there + videoRegistryFile = self.genOpts.registryFile.replace('vk.xml', 'video.xml') + if os.path.isfile(videoRegistryFile): + videoxml = etree.parse(videoRegistryFile) + else: + assert False, "Could not find video.xml to generate utilities for video enum types" + out = '' + for enum in videoxml.findall("./enums[@name]"): + enumname = enum.get('name') + out += f'std::string {enumname}String({enumname} value) {{\n' + out += ' switch (value) {\n' + for option in enum.findall("./enum[@name]"): + name = option.get('name') + # Ignore aliases + if option.get('value') is not None: + out += f' case {name}: return "{name}";\n' + out += f' default: return std::string("UNKNOWN_{enumname}_value") + std::to_string(value);\n' + out += ' }\n}\n' + out += f'void Dump{enumname}(Printer &p, std::string name, {enumname} value) {{\n' + out += f' p.PrintKeyString(name, {enumname}String(value));\n}}\n' + return out + + def genVideoProfileUtils(self): + out = '' + + # Parse video codec information from the XML + videoCodecs = OrderedDict() + xmlVideoCodecs = self.registry.reg.find("./videocodecs") + for xmlVideoCodec in xmlVideoCodecs.findall("./videocodec"): + name = xmlVideoCodec.get('name') + extend = xmlVideoCodec.get('extend') + value = xmlVideoCodec.get('value') + if value is None: + # Video codec category + videoCodecs[name] = VulkanVideoCodec(name) + else: + # Specific video codec + videoCodecs[name] = VulkanVideoCodec(name, videoCodecs[extend], value) + videoCodec = videoCodecs[name] + + for xmlVideoProfiles in xmlVideoCodec.findall("./videoprofiles"): + videoProfileStructName = xmlVideoProfiles.get('struct') + videoCodec.profileStructs[videoProfileStructName] = VulkanVideoProfileStruct(videoProfileStructName) + videoProfileStruct = videoCodec.profileStructs[videoProfileStructName] + + for xmlVideoProfileMember in xmlVideoProfiles.findall("./videoprofilemember"): + memberName = xmlVideoProfileMember.get('name') + videoProfileStruct.members[memberName] = VulkanVideoProfileStructMember(memberName) + videoProfileStructMember = videoProfileStruct.members[memberName] + + for xmlVideoProfile in xmlVideoProfileMember.findall("./videoprofile"): + videoProfileStructMember.values[xmlVideoProfile.get('value')] = xmlVideoProfile.get('name') + + for xmlVideoCapabilities in xmlVideoCodec.findall("./videocapabilities"): + capabilityStructName = xmlVideoCapabilities.get('struct') + videoCodec.capabilities[capabilityStructName] = capabilityStructName + + for xmlVideoFormat in xmlVideoCodec.findall("./videoformat"): + videoFormatName = xmlVideoFormat.get('name') + videoFormatExtend = xmlVideoFormat.get('extend') + if videoFormatName is not None: + # This is a new video format category + videoFormatUsage = xmlVideoFormat.get('usage') + videoCodec.formats[videoFormatName] = VulkanVideoFormat(videoFormatName, videoFormatUsage) + videoFormat = videoCodec.formats[videoFormatName] + elif videoFormatExtend is not None: + # This is an extension to an already defined video format category + if videoFormatExtend in videoCodec.formats: + videoFormat = videoCodec.formats[videoFormatExtend] + else: + assert False, f"Video format category '{videoFormatExtend}' not found but it is attempted to be extended" + else: + assert False, "'name' or 'extend' is attribute is required for 'videoformat' element" + + for xmlVideoFormatProperties in xmlVideoFormat.findall("./videoformatproperties"): + propertiesStructName = xmlVideoFormatProperties.get('struct') + videoFormat.properties[propertiesStructName] = propertiesStructName + + for xmlVideoFormatRequiredCap in xmlVideoFormat.findall("./videorequirecapabilities"): + requiredCapStruct = xmlVideoFormatRequiredCap.get('struct') + requiredCapMember = xmlVideoFormatRequiredCap.get('member') + requiredCapValue = xmlVideoFormatRequiredCap.get('value') + videoFormat.requiredCaps.append(VulkanVideoRequiredCapabilities(requiredCapStruct, requiredCapMember, requiredCapValue)) + + # Collect flag types in a set because we will need to look this up + flagTypes = set() + for flagType in self.flags: + flagTypes.add(flagType.name) + + # Utility to get structure definition from structure name + def GetStructDef(name): + for s in self.all_structures: + if s.name == name: + return s + assert False, f"Definition for structure '{name}' is missing" + + # Utility to get the extension / version precondition of a list of type names + def GetTypesPrecondition(typelist, indent): + indent = ' ' * indent + out = '' + extEnables = {} + for typename in typelist: + for k, elem in self.extTypes.items(): + if k == typename or (typename in self.aliases.keys() and k in self.aliases[typename]): + for e in elem: + extEnables[e.extNameStr] = e.type + + version = None + for typename in typelist: + for v in self.vulkan_versions: + if typename in v.names: + if version is not None and (v.major > version.major or (v.major == version.major and v.minor > version.minor)): + version = v + + has_version = version is not None + has_extNameStr = len(extEnables) > 0 or typename in self.aliases.keys() + if has_version or has_extNameStr: + out += f'{indent}if (' + has_printed_condition = False + if has_extNameStr: + for key, value in extEnables.items(): + if has_printed_condition: + out += f'\n{indent} || ' + else: + has_printed_condition = True + if has_version: + out += '(' + if value == EXTENSION_TYPE_DEVICE: + out += f'gpu.CheckPhysicalDeviceExtensionIncluded({key})' + else: + assert False, 'Should never get here' + if has_version: + if has_printed_condition: + out += f'\n{indent} || (gpu.api_version >= {version.constant})' + else: + out += f'gpu.api_version >= {version.constant}' + out += ') {\n' + else: + out = f'{indent}{{\n' + return out + + # Utility to construct a capability prerequisite condition evaluation expression + def GetRequiredCapsCondition(structName, memberName, memberRef, value): + condition = '' + requiredCapStructDef = GetStructDef(structName) + for member in requiredCapStructDef.members: + if member.name == memberName: + if member.typeID in flagTypes: + # Check that the flags contain all the required values + def genExpressionFromValue(value): + return value if value == "" else f"({memberRef} & {value}) != 0" + + for char in condition: + if char in ['(', ')', '+', ',']: + condition += genExpressionFromValue(value) + value = "" + if char == '+': + # '+' means AND + condition += ' && ' + elif char == ',': + # ',' means OR + condition += ' || ' + else: + condition += char + else: + value += char + condition += genExpressionFromValue(value) + else: + condition = f'{memberRef} == {value}' + if condition == '': + return 'true' + else: + return f'({condition})' + + # Generate video format properties comparator + out += ''' +bool is_video_format_same(const VkVideoFormatPropertiesKHR &format_a, const VkVideoFormatPropertiesKHR &format_b) { + auto a = reinterpret_cast(&format_a); + auto b = reinterpret_cast(&format_b); + bool same = true; + while (same && a != nullptr && b != nullptr) { + if (a->sType != b->sType) { + // Structure type mismatch (extension structures are expected to be chained in the same order) + same = false; + } else { + switch (a->sType) {''' + + if 'VkVideoFormatPropertiesKHR' in self.registry.validextensionstructs: + for extstruct in ['VkVideoFormatPropertiesKHR'] + self.registry.validextensionstructs['VkVideoFormatPropertiesKHR']: + extstructDef = GetStructDef(extstruct) + out += f''' + case {extstructDef.sTypeName}: + same = same && memcmp(reinterpret_cast(a) + sizeof(VkBaseInStructure), + reinterpret_cast(b) + sizeof(VkBaseInStructure), + sizeof({extstruct}) - sizeof(VkBaseInStructure)) == 0; + break;''' + + out += ''' + default: + // Unexpected structure type + same = false; + break; + } + } + a = a->pNext; + b = b->pNext; + } + return same; +} +''' + + # Generate video profile info capture utilities + out += ''' +std::vector> enumerate_supported_video_profiles(AppGpu &gpu) { + std::vector> result{}; + + struct ChromaSubsamplingInfo { + VkVideoChromaSubsamplingFlagsKHR value; + const char* name; + }; + const std::vector chroma_subsampling_list = { + {VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR, "4:2:0"}, + {VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR, "4:2:2"}, + {VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR, "4:4:4"}, + {VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR, "monochrome"} + }; + + struct BitDepthInfo { + VkVideoComponentBitDepthFlagsKHR value; + const char* name; + }; + const std::vector bit_depth_list = { + {VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR, "8"}, + {VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR, "10"}, + {VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR, "12"} + }; + + auto find_caps_struct = [](const VkVideoCapabilitiesKHR &capabilities, VkStructureType stype) -> const VkBaseInStructure* { + auto p = reinterpret_cast(&capabilities); + while (p != nullptr) { + if (p->sType == stype) { + return p; + } + p = p->pNext; + } + return nullptr; + }; + + auto base_format = [] + (const ChromaSubsamplingInfo &chroma_subsampling, const BitDepthInfo &luma_bit_depth, const BitDepthInfo &chroma_bit_depth) { + std::string result{}; + result += " ("; + result += chroma_subsampling.name; + result += " "; + result += luma_bit_depth.name; + if (luma_bit_depth.value != chroma_bit_depth.value) { + result += ":"; + result += chroma_bit_depth.name; + } + result += "-bit)"; + return result; + }; + + auto add_profile = [&]( + const std::string &name, + const VkVideoProfileInfoKHR &profile_info, + AppVideoProfile::CreateProfileInfoChainCb create_profile_info_chain, + AppVideoProfile::CreateCapabilitiesChainCb create_capabilities_chain, + const AppVideoProfile::CreateFormatPropertiesChainCbList &create_format_properties_chain_list, + AppVideoProfile::InitProfileCb init_profile) { + auto profile = std::make_unique(gpu, gpu.phys_device, + name, profile_info, + create_profile_info_chain, + create_capabilities_chain, + create_format_properties_chain_list, + init_profile); + if (profile->supported) { + result.push_back(std::move(profile)); + } + }; +''' + + # Generate individual video profiles from the video codec metadata + for videoCodec in videoCodecs.values(): + # Ignore video codec categories + if videoCodec.value is None: + continue + + out += '\n' + out += GetTypesPrecondition(videoCodec.profileStructs, 4) + out += f'{" " * 8}const std::string codec_name = "{videoCodec.name}";\n' + + out += ''' + for (auto chroma_subsampling : chroma_subsampling_list) { + for (auto luma_bit_depth : bit_depth_list) { + for (auto chroma_bit_depth : bit_depth_list) { + if (chroma_subsampling.value == VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR && luma_bit_depth.value != chroma_bit_depth.value) { + // Ignore the chroma bit depth dimension for monochrome + continue; + } + + std::string profile_base_name = codec_name + base_format(chroma_subsampling, luma_bit_depth, chroma_bit_depth); +''' + + # Setup video profile info + out += f'{" " * 20}VkVideoProfileInfoKHR profile_info{{\n' + out += f'{" " * 20} VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,\n' + out += f'{" " * 20} nullptr,\n' + out += f'{" " * 20} {videoCodec.value},\n' + out += f'{" " * 20} chroma_subsampling.value,\n' + out += f'{" " * 20} luma_bit_depth.value,\n' + out += f'{" " * 20} chroma_bit_depth.value\n' + out += f'{" " * 20}}};\n\n' + + # Setup video profile info chain creation callback + out += f'{" " * 20}auto create_profile_info_chain = [&](const void **ppnext) -> std::unique_ptr {{\n' + out += f'{" " * 20} auto profile_info_chain = std::make_unique();\n' + for profileStruct in videoCodec.profileStructs: + structDef = GetStructDef(profileStruct) + out += AddGuardHeader(structDef) + out += f'{" " * 24}if (profile_info_chain != nullptr) {{\n' + out += f'{" " * 28}profile_info_chain->{profileStruct[2:]}.sType = {structDef.sTypeName};\n' + out += f'{" " * 28}profile_info_chain->{profileStruct[2:]}.pNext = nullptr;\n' + out += f'{" " * 28}*ppnext = &profile_info_chain->{profileStruct[2:]};\n' + out += f'{" " * 28}ppnext = &profile_info_chain->{profileStruct[2:]}.pNext;\n' + out += f'{" " * 24}}}\n' + if structDef.guard: + out += f'#else\n{" " * 20}profile_info_chain = nullptr;\n' + out += AddGuardFooter(structDef) + out += f'{" " * 20} return profile_info_chain;\n' + out += f'{" " * 20}}};\n\n' + + # Setup video capabilities chain creation callback + out += f'{" " * 20}auto create_capabilities_chain = [&](void **ppnext) -> std::unique_ptr {{\n' + out += f'{" " * 20} auto capabilities_chain = std::make_unique();\n' + for capabilities in videoCodec.capabilities: + structDef = GetStructDef(capabilities) + out += AddGuardHeader(structDef) + out += f'{" " * 24}if (capabilities_chain != nullptr) {{\n' + out += GetTypesPrecondition([capabilities], 28) + out += f'{" " * 32}capabilities_chain->{capabilities[2:]}.sType = {structDef.sTypeName};\n' + out += f'{" " * 32}capabilities_chain->{capabilities[2:]}.pNext = nullptr;\n' + out += f'{" " * 32}*ppnext = &capabilities_chain->{capabilities[2:]};\n' + out += f'{" " * 32}ppnext = &capabilities_chain->{capabilities[2:]}.pNext;\n' + out += f'{" " * 28}}}\n' + out += f'{" " * 24}}}\n' + out += AddGuardFooter(structDef) + out += f'{" " * 20} return capabilities_chain;\n' + out += f'{" " * 20}}};\n\n' + + # Setup video format properties chain creation callbacks + out += f'{" " * 20}const AppVideoProfile::CreateFormatPropertiesChainCbList create_format_properties_chain_list = {{\n' + for format in videoCodec.formats.values(): + out += f'{" " * 24}AppVideoProfile::CreateFormatPropertiesChainCb {{\n' + out += f'{" " * 28}"{format.name}",\n' + out += f'{" " * 28}{format.usage.replace("+", " | ")},\n' + + # Callback to check required capabilities + out += f'{" " * 28}[&](const VkVideoCapabilitiesKHR &capabilities) -> bool {{\n' + out += f'{" " * 28} bool supported = true;\n' + for requiredCap in format.requiredCaps: + structDef = GetStructDef(requiredCap.struct) + out += AddGuardHeader(structDef) + out += GetTypesPrecondition([requiredCap.struct], 32) + out += f'{" " * 32} auto caps = reinterpret_cast(find_caps_struct(capabilities, {structDef.sTypeName}));\n' + out += f'{" " * 32} if (caps != nullptr) {{\n' + out += f'{" " * 32} supported = supported && {GetRequiredCapsCondition(requiredCap.struct, requiredCap.member, f"caps->{requiredCap.member}", requiredCap.value)};\n' + out += f'{" " * 32} }} else {{\n' + out += f'{" " * 32} supported = false;\n' + out += f'{" " * 32} }}\n' + out += f'{" " * 32}}} else {{\n' + out += f'{" " * 32} supported = false;\n' + out += f'{" " * 32}}}\n' + if structDef.guard: + out += f'#else\n{" " * 32}supported = false;\n' + out += AddGuardFooter(structDef) + out += f'{" " * 28} return supported;\n' + out += f'{" " * 28}}},\n' + + # Callback to create video format properties chain + out += f'{" " * 28}[&](void **ppnext) -> std::unique_ptr {{\n' + out += f'{" " * 28} auto format_properties_chain = std::make_unique();\n' + for formatProps in format.properties: + structDef = GetStructDef(formatProps) + out += AddGuardHeader(structDef) + out += f'{" " * 32}if (format_properties_chain != nullptr) {{\n' + out += GetTypesPrecondition([formatProps], 36) + out += f'{" " * 40}format_properties_chain->{formatProps[2:]}.sType = {structDef.sTypeName};\n' + out += f'{" " * 40}format_properties_chain->{formatProps[2:]}.pNext = nullptr;\n' + out += f'{" " * 40}*ppnext = &format_properties_chain->{formatProps[2:]};\n' + out += f'{" " * 40}ppnext = &format_properties_chain->{formatProps[2:]}.pNext;\n' + out += f'{" " * 36}}}\n' + out += f'{" " * 32}}}\n' + out += AddGuardFooter(structDef) + out += f'{" " * 28} return format_properties_chain;\n' + out += f'{" " * 28}}},\n' + + out += f'{" " * 24}}},\n' + out += f'{" " * 20}}};\n\n' + + # Permute profiles for each profile struct member value + profiles = {'': []} + for profileStruct in videoCodec.profileStructs.values(): + for profileStructMember in profileStruct.members.values(): + newProfiles = {} + for profileStructMemberValue, profileStructMemberName in profileStructMember.values.items(): + for profileName, profile in profiles.items(): + # Only add video profile name suffix to the full descriptive name if not empty to avoid excess whitespace + newProfileName = profileName if profileStructMemberName == '' else f'{profileName} {profileStructMemberName}' + newProfiles[newProfileName] = profile + [{ + "struct": profileStruct.struct, + "member": profileStructMember.name, + "value": profileStructMemberValue + }] + profiles = newProfiles + + for profileName, profile in profiles.items(): + out += f'{" " * 20}add_profile(profile_base_name + "{profileName}", profile_info,\n' + out += f'{" " * 20} create_profile_info_chain, create_capabilities_chain,\n' + out += f'{" " * 20} create_format_properties_chain_list,\n' + out += f'{" " * 20} [](AppVideoProfile& profile) {{\n' + for profileStruct in videoCodec.profileStructs: + structDef = GetStructDef(profileStruct) + out += AddGuardHeader(structDef) + for elem in profile: + if elem['struct'] == profileStruct: + out += f'{" " * 24}profile.profile_info_chain->{elem["struct"][2:]}.{elem["member"]} = {elem["value"]};\n' + out += AddGuardFooter(structDef) + out += f'{" " * 20}}});\n' + + out += f'{" " * 16}}}\n' + out += f'{" " * 12}}}\n' + out += f'{" " * 8}}}\n' + out += f'{" " * 4}}}\n' + + out += ' return result;\n' + out += '}\n\n' + + return out + + def genCmd(self, cmd, name, alias): + gen.OutputGenerator.genCmd(self, cmd, name, alias) + + # These are actually constants + def genEnum(self, enuminfo, name, alias): + gen.OutputGenerator.genEnum(self, enuminfo, name, alias) + + # These are actually enums + def genGroup(self, groupinfo, groupName, alias): + gen.OutputGenerator.genGroup(self, groupinfo, groupName, alias) + + if alias is not None: + if alias in self.aliases.keys(): + self.aliases[alias].append(groupName) + else: + self.aliases[alias] = [groupName, ] + return + + if groupinfo.elem.get('type') == 'bitmask': + self.bitmasks.append(VulkanBitmask(groupinfo.elem)) + elif groupinfo.elem.get('type') == 'enum': + self.enums.append(VulkanEnum(groupinfo.elem)) + + def genType(self, typeinfo, name, alias): + gen.OutputGenerator.genType(self, typeinfo, name, alias) + + if alias is not None: + if alias in self.aliases.keys(): + self.aliases[alias].append(name) + else: + self.aliases[alias] = [name, ] + return + + if typeinfo.elem.get('category') == 'bitmask': + self.flags.append(VulkanFlags(typeinfo.elem)) + + if typeinfo.elem.get('category') == 'struct': + self.all_structures.append(VulkanStructure( + name, typeinfo.elem, self.constants, self.extTypes)) + + is_vendor_type = False + for vendor in self.vendor_abbreviations: + for node in typeinfo.elem.findall('member'): + if node.get('values') is not None: + if node.get('values').find(vendor) != -1: + is_vendor_type = True + break + if is_vendor_type: + break + + for key, value in EXTENSION_CATEGORIES.items(): + if str(typeinfo.elem.get('structextends')).find(value.get('extends')) != -1: + if value.get('exclude') is None or name not in value.get('exclude'): + if not is_vendor_type or value.get('ignore_vendor_exclusion'): + self.extension_sets[key].add(name) + + # finds all the ranges of formats from core (1.0), core versions (1.1+), and extensions + def findFormatRanges(self): + for enums in self.registry.reg.findall('enums'): + if enums.get('name') == 'VkFormat': + min_val = 2**32 + max_val = 0 + for enum in enums.findall('enum'): + if enum.get('value') is None: + continue + value = int(enum.get('value')) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(0, None, min_val, max_val)) + + for feature in self.registry.reg.findall('feature'): + for require in feature.findall('require'): + comment = require.get('comment') + original_ext = None + if comment is not None and comment.find('Promoted from') >= 0: + # may need tweaking in the future - some ext names aren't just the upper case version + original_ext = comment.split(' ')[2].upper() + '_EXTENSION_NAME' + # insert an underscore before numbers in the name define + original_ext = re.sub(r'([A-Z])(\d+)', r'\1_\2', original_ext) + min_val = 2**32 + max_val = 0 + for enum in require.findall('enum'): + if enum.get('extends') == 'VkFormat': + value = CalcEnumValue(int(enum.get('extnumber')), int(enum.get('offset'))) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(feature.get('name').replace('_VERSION_', '_API_VERSION_'), None, min_val, max_val)) + # If the formats came from an extension, add a format range for that extension so it'll be printed if the ext is supported but not the core version + if original_ext is not None: + self.format_ranges.append(VulkanFormatRange(0, original_ext, min_val, max_val)) + + for extension in self.registry.reg.find('extensions').findall('extension'): + if not self.genOpts.apiname in extension.get('supported').split(','): + continue + + min_val = 2**32 + max_val = 0 + enum_name_string = '' + for require in extension.findall('require'): + for enum in require.findall('enum'): + if enum.get('value') is not None and enum.get('value').find(extension.get('name')): + enum_name_string = enum.get('name') + if enum.get('extends') == 'VkFormat': + if enum.get('offset') is None: + continue + value = CalcEnumValue(int(extension.get('number')), int(enum.get('offset'))) + min_val = min(min_val, value) + max_val = max(max_val, value) + if min_val < 2**32 and max_val > 0: + self.format_ranges.append(VulkanFormatRange(0, enum_name_string, min_val, max_val)) + + + +def GatherTypesToGen(structure_list, structures, exclude = None): + if exclude is None: + exclude = [] + types = set() + for s in structures: + types.add(s) + added_stuff = True # repeat until no new types are added + while added_stuff is True: + added_stuff = False + for s in structure_list: + if s.name in types: + for m in s.members: + if m.typeID not in PREDEFINED_TYPES and m.name not in NAMES_TO_IGNORE: + if m.typeID not in types: + if s.name not in exclude: + types.add(m.typeID) + added_stuff = True + return types + + +def GetExtension(name, generator): + if name in generator.extFuncs: + return generator.extFuncs[name] + elif name in generator.extTypes: + return generator.extTypes[name][0] + else: + return None + + +def AddGuardHeader(obj): + if obj is not None and obj.guard is not None: + return f'#ifdef {obj.guard}\n' + else: + return '' + + +def AddGuardFooter(obj): + if obj is not None and obj.guard is not None: + return f'#endif // {obj.guard}\n' + else: + return '' + +def CalcEnumValue(num, offset): + base = 1000000000 + block_size = 1000 + return base + (num - 1) * block_size + offset + +def PrintEnumToString(enum, generator): + out = '' + out += AddGuardHeader(GetExtension(enum.name, generator)) + out += f'std::string {enum.name}String({enum.name} value) {{\n' + out += ' switch (value) {\n' + for v in enum.options: + out += f' case ({v.name}): return "{v.name[3:]}";\n' + out += f' default: return std::string("UNKNOWN_{enum.name}_value") + std::to_string(value);\n' + out += ' }\n}\n' + out += AddGuardFooter(GetExtension(enum.name, generator)) + return out + + +def PrintEnum(enum, generator): + out = '' + out += AddGuardHeader(GetExtension(enum.name, generator)) + out += f'''void Dump{enum.name}(Printer &p, std::string name, {enum.name} value) {{ + if (p.Type() == OutputType::json) + p.PrintKeyString(name, std::string("VK_") + {enum.name}String(value)); + else + p.PrintKeyString(name, {enum.name}String(value)); +}} +''' + out += AddGuardFooter(GetExtension(enum.name, generator)) + return out + + +def PrintGetFlagStrings(name, bitmask): + out = '' + out += f'std::vector {name}GetStrings({name} value) {{\n' + out += ' std::vector strings;\n' + # If a bitmask contains a field whose value is zero, we want to support printing the correct bitflag + # Otherwise, use "None" for when there are not bits set in the bitmask + if bitmask.options[0].value != 0: + out += ' if (value == 0) { strings.push_back("None"); return strings; }\n' + else: + out += f' if (value == 0) {{ strings.push_back("{bitmask.options[0].name[3:]}"); return strings; }}\n' + for v in bitmask.options: + # only check single-bit flags + if v.value != 0 and (v.value & (v.value - 1)) == 0: + out += f' if ({v.name} & value) strings.push_back("{v.name[3:]}");\n' + out += ' return strings;\n}\n' + return out + + +def PrintFlags(bitmask, name): + out = f'void Dump{name}(Printer &p, std::string name, {name} value) {{\n' + out += f''' if (static_cast<{bitmask.name}>(value) == 0) {{ + ArrayWrapper arr(p, name, 0); + if (p.Type() != OutputType::json && p.Type() != OutputType::vkconfig_output) + p.SetAsType().PrintString("None"); + return; + }} + auto strings = {bitmask.name}GetStrings(static_cast<{bitmask.name}>(value)); + ArrayWrapper arr(p, name, strings.size()); + for(auto& str : strings){{ + if (p.Type() == OutputType::json) + p.SetAsType().PrintString(std::string("VK_") + str); + else + p.SetAsType().PrintString(str); + }} +}} +''' + return out + + +def PrintFlagBits(bitmask): + return f'''void Dump{bitmask.name}(Printer &p, std::string name, {bitmask.name} value) {{ + auto strings = {bitmask.name}GetStrings(value); + if (strings.size() > 0) {{ + if (p.Type() == OutputType::json) + p.PrintKeyString(name, std::string("VK_") + strings.at(0)); + else + p.PrintKeyString(name, strings.at(0)); + }} +}} +''' + + + +def PrintBitMask(bitmask, name, generator): + out = PrintGetFlagStrings(bitmask.name, bitmask) + out += AddGuardHeader(GetExtension(bitmask.name, generator)) + out += PrintFlags(bitmask, name) + out += PrintFlagBits(bitmask) + out += AddGuardFooter(GetExtension(bitmask.name, generator)) + out += '\n' + return out + + +def PrintBitMaskToString(bitmask, name, generator): + out = AddGuardHeader(GetExtension(bitmask.name, generator)) + out += f'std::string {name}String({name} value) {{\n' + out += ' std::string out;\n' + out += ' bool is_first = true;\n' + for v in bitmask.options: + out += f' if ({v.name} & value) {{\n' + out += ' if (is_first) { is_first = false; } else { out += " | "; }\n' + out += f' out += "{str(v.name)[3:]}";\n' + out += ' }\n' + out += ' return out;\n' + out += '}\n' + out += AddGuardFooter(GetExtension(bitmask.name, generator)) + return out + + +def PrintStructure(struct): + if len(struct.members) == 0: + return '' + out = '' + out += AddGuardHeader(struct) + max_key_len = 0 + for v in struct.members: + if v.arrayLength is not None: + if len(v.name) + len(v.arrayLength) + 2 > max_key_len: + max_key_len = len(v.name) + len(v.arrayLength) + 2 + elif v.typeID in PREDEFINED_TYPES or v.typeID in STRUCT_BLACKLIST: + if len(v.name) > max_key_len: + max_key_len = len(v.name) + + out += f'void Dump{struct.name}(Printer &p, std::string name, const {struct.name} &obj) {{\n' + if struct.name == 'VkPhysicalDeviceLimits': + out += ' if (p.Type() == OutputType::json)\n' + out += ' p.ObjectStart("limits");\n' + out += ' else\n' + out += ' p.SetSubHeader().ObjectStart(name);\n' + elif struct.name == 'VkPhysicalDeviceSparseProperties': + out += ' if (p.Type() == OutputType::json)\n' + out += ' p.ObjectStart("sparseProperties");\n' + out += ' else\n' + out += ' p.SetSubHeader().ObjectStart(name);\n' + else: + out += ' ObjectWrapper object{p, name};\n' + if max_key_len > 0: + out += f' p.SetMinKeyWidth({max_key_len});\n' + for v in struct.members: + # arrays + if v.arrayLength is not None: + # strings + if v.typeID == 'char': + out += f' p.PrintKeyString("{v.name}", obj.{v.name});\n' + # uuid's + elif v.typeID == 'uint8_t' and (v.arrayLength == '8' or v.arrayLength == '16'): # VK_UUID_SIZE + if v.arrayLength == '8': + out += ' if (obj.deviceLUIDValid) { // special case\n' + out += f' p.PrintKeyValue("{v.name}", obj.{v.name});\n' + if v.arrayLength == '8': + out += ' }\n' + elif struct.name == 'VkQueueFamilyGlobalPriorityProperties' and v.name == 'priorities': + out += f' ArrayWrapper arr(p,"{v.name}", obj.priorityCount);\n' + out += ' for (uint32_t i = 0; i < obj.priorityCount; i++) {\n' + out += ' if (p.Type() == OutputType::json)\n' + out += ' p.PrintString(std::string("VK_") + VkQueueGlobalPriorityString(obj.priorities[i]));\n' + out += ' else\n' + out += ' p.PrintString(VkQueueGlobalPriorityString(obj.priorities[i]));\n' + out += ' }\n' + elif v.arrayLength.isdigit(): + out += f' {{\n ArrayWrapper arr(p,"{v.name}", ' + v.arrayLength + ');\n' + out += f' for (uint32_t i = 0; i < {v.arrayLength}; i++) {{ p.PrintElement(obj.{v.name}[i]); }}\n' + out += ' }\n' + else: # dynamic array length based on other member + out += f' if (obj.{v.arrayLength} == 0 || obj.{v.name} == nullptr) {{\n' + out += f' p.PrintKeyString("{v.name}", "NULL");\n' + out += ' } else {\n' + out += f' ArrayWrapper arr(p,"{v.name}", obj.{v.arrayLength});\n' + out += f' for (uint32_t i = 0; i < obj.{v.arrayLength}; i++) {{\n' + out += f' Dump{v.typeID}(p, std::to_string(i), obj.{v.name}[i]);\n' + out += ' }\n' + out += ' }\n' + elif v.typeID == 'VkBool32': + out += f' p.PrintKeyBool("{v.name}", static_cast(obj.{v.name}));\n' + elif v.typeID == 'uint8_t': + out += f' p.PrintKeyValue("{v.name}", static_cast(obj.{v.name}));\n' + elif v.typeID == 'VkDeviceSize' or (v.typeID == 'uint32_t' and v.name in ['vendorID', 'deviceID']): + out += f' p.PrintKeyValue("{v.name}", to_hex_str(p, obj.{v.name}));\n' + elif v.typeID in PREDEFINED_TYPES: + out += f' p.PrintKeyValue("{v.name}", obj.{v.name});\n' + elif v.name not in NAMES_TO_IGNORE: + # if it is an enum/flag/bitmask + if v.typeID in ['VkFormatFeatureFlags', 'VkFormatFeatureFlags2']: + out += ' p.SetOpenDetails();\n' # special case so that feature flags are open in html output + out += f' Dump{v.typeID}(p, "{v.name}", obj.{v.name});\n' + + if struct.name in ['VkPhysicalDeviceLimits', 'VkPhysicalDeviceSparseProperties']: + out += ' p.ObjectEnd();\n' + out += '}\n' + + out += AddGuardFooter(struct) + return out + + +def PrintStructShort(struct): + out = '' + out += AddGuardHeader(struct) + out += f'std::ostream &operator<<(std::ostream &o, {struct.name} &obj) {{\n' + out += ' return o << "(" << ' + + first = True + for v in struct.members: + if first: + first = False + out += f'obj.{v.name} << ' + else: + out += f'\',\' << obj.{v.name} << ' + out += '")";\n' + out += '}\n' + out += AddGuardFooter(struct) + return out + +def PrintChainStruct(listName, structures, all_structures, chain_details, extTypes, aliases, vulkan_versions): + sorted_structures = sorted( + all_structures, key=operator.attrgetter('name')) + + version_desc = '' + if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: + version_desc = 'gpu.api_version' + else: + version_desc = 'inst.instance_version' + + out = '' + structs_to_print = [] + for s in sorted_structures: + if s.name in structures: + structs_to_print.append(s) + # use default constructor and delete copy & move operators + out += f'''struct {listName}_chain {{ + {listName}_chain() = default; + {listName}_chain(const {listName}_chain &) = delete; + {listName}_chain& operator=(const {listName}_chain &) = delete; + {listName}_chain({listName}_chain &&) = delete; + {listName}_chain& operator=({listName}_chain &&) = delete; +''' + + out += ' void* start_of_chain = nullptr;\n' + for s in structs_to_print: + if s.name in STRUCT_BLACKLIST: + continue + out += AddGuardHeader(s) + if s.sTypeName is not None: + out += f' {s.name} {s.name[2:]}{{}};\n' + # Specific versions of drivers have an incorrect definition of the size of these structs. + # We need to artificially pad the structure it just so the driver doesn't write out of bounds and + # into other structures that are adjacent. This bug comes from the in-development version of + # the extension having a larger size than the final version, so older drivers try to write to + # members which don't exist. + if s.name in ['VkPhysicalDeviceShaderIntegerDotProductFeatures', 'VkPhysicalDeviceHostImageCopyFeaturesEXT']: + out += f' char {s.name}_padding[64];\n' + if s.hasLengthmember: + for member in s.members: + if member.lengthMember: + out += f' std::vector<{member.typeID}> {s.name}_{member.name};\n' + out += AddGuardFooter(s) + out += ' void initialize_chain(' + if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: + out += 'AppInstance &inst, ' + if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: + out += 'AppGpu &gpu ' + if chain_details.get('can_show_promoted_structs'): + out += ', bool show_promoted_structs' + out += ') noexcept {\n' + for s in structs_to_print: + if s.name in STRUCT_BLACKLIST: + continue + out += AddGuardHeader(s) + out += f' {s.name[2:]}.sType = {s.sTypeName};\n' + out += AddGuardFooter(s) + + + out += ' std::vector chain_members{};\n' + for s in structs_to_print: + if s.name in STRUCT_BLACKLIST: + continue + out += AddGuardHeader(s) + extEnables = {} + for k, elem in extTypes.items(): + if k == s.name or (s.name in aliases.keys() and k in aliases[s.name]): + for e in elem: + extEnables[e.extNameStr] = e.type + + version = None + oldVersionName = None + for v in vulkan_versions: + if s.name in v.names: + version = v + if s.name in aliases.keys(): + for alias in aliases[s.name]: + oldVersionName = alias + + has_version = version is not None + has_extNameStr = len(extEnables) > 0 or s.name in aliases.keys() + if has_version or has_extNameStr: + out += ' if (' + has_printed_condition = False + if has_extNameStr: + for key, value in extEnables.items(): + if has_printed_condition: + out += '\n || ' + else: + has_printed_condition = True + if has_version: + out += '(' + if value == EXTENSION_TYPE_DEVICE: + out += f'gpu.CheckPhysicalDeviceExtensionIncluded({key})' + elif value == EXTENSION_TYPE_INSTANCE: + out += f'inst.CheckExtensionEnabled({key})' + else: + assert False, 'Should never get here' + if has_version: + str_show_promoted_structs = '|| show_promoted_structs' if chain_details.get('can_show_promoted_structs') else '' + if s.name in STRUCT_1_1_LIST: + out += f'{version_desc} == {version.constant} {str_show_promoted_structs}' + elif has_printed_condition: + out += f')\n && ({version_desc} < {version.constant} {str_show_promoted_structs})' + else: + out += f'({version_desc} >= {version.constant})' + out += ')\n ' + else: + out += ' ' + out += f'chain_members.push_back(reinterpret_cast(&{s.name[2:]}));\n' + out += AddGuardFooter(s) + chain_param_list = [] + chain_arg_list = [] + if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: + chain_param_list.append('AppInstance &inst') + chain_arg_list.append('inst') + if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: + chain_param_list.append('AppGpu &gpu') + chain_arg_list.append('gpu') + if chain_details.get('can_show_promoted_structs'): + chain_param_list.append('bool show_promoted_structs') + chain_arg_list.append('show_promoted_structs') + + out += f''' + if (!chain_members.empty()) {{ + for(size_t i = 0; i < chain_members.size() - 1; i++){{ + chain_members[i]->pNext = chain_members[i + 1]; + }} + start_of_chain = chain_members[0]; + }} + }} +}}; +void setup_{listName}_chain({chain_details['holder_type']}& start, std::unique_ptr<{listName}_chain>& chain, {','.join(chain_param_list)}){{ + chain = std::unique_ptr<{listName}_chain>(new {listName}_chain()); + chain->initialize_chain({','.join(chain_arg_list)}); + start.pNext = chain->start_of_chain; +}}; +''' + if chain_details.get('print_iterator'): + out += '\n' + out += f'void chain_iterator_{listName}(Printer &p, ' + if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: + out += 'AppInstance &inst, ' + if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: + out += 'AppGpu &gpu, ' + if chain_details.get('can_show_promoted_structs'): + out += 'bool show_promoted_structs, ' + out += 'const void * place) {\n' + out += ' while (place) {\n' + out += ' const VkBaseOutStructure *structure = (const VkBaseOutStructure *)place;\n' + out += ' p.SetSubHeader();\n' + + for s in sorted_structures: + if s.sTypeName is None or s.name in STRUCT_BLACKLIST: + continue + + extEnables = {} + for k, elem in extTypes.items(): + if k == s.name or (s.name in aliases.keys() and k in aliases[s.name]): + for e in elem: + extEnables[e.extNameStr] = e.type + + version = None + oldVersionName = None + for v in vulkan_versions: + if s.name in v.names: + version = v + if s.name in aliases.keys(): + for alias in aliases[s.name]: + oldVersionName = alias + + if s.name in structures: + out += AddGuardHeader(s) + out += f' if (structure->sType == {s.sTypeName}' + if s.name in PORTABILITY_STRUCTS: + out += ' && p.Type() != OutputType::json' + has_version = version is not None + has_extNameStr = len(extEnables) > 0 or s.name in aliases.keys() + out += ') {\n' + out += f' const {s.name}* props = (const {s.name}*)structure;\n' + out += f' Dump{s.name}(p, ' + if s.name in aliases.keys() and version is not None: + out += f'{version_desc} >= {version.constant} ?"{s.name}":"{oldVersionName}"' + else: + out += f'"{s.name}"' + out += ', *props);\n' + out += ' p.AddNewline();\n' + out += ' }\n' + out += AddGuardFooter(s) + out += ' place = structure->pNext;\n' + out += ' }\n' + out += '}\n' + + out += '\n' + out += f'bool prepare_{listName}_twocall_chain_vectors(std::unique_ptr<{listName}_chain>& chain) {{\n' + out += ' (void)chain;\n' + is_twocall = False + for s in structs_to_print: + if not s.hasLengthmember: + continue + if s.name in STRUCT_BLACKLIST: + continue + out += AddGuardHeader(s) + for member in s.members: + if member.lengthMember: + out += f' chain->{s.name}_{member.name}.resize(chain->{s.name[2:]}.{member.arrayLength});\n' + out += f' chain->{s.name[2:]}.{member.name} = chain->{s.name}_{member.name}.data();\n' + out += AddGuardFooter(s) + is_twocall = True + out += f' return {"true" if is_twocall else "false"};\n' + out += '}\n' + + return out + + +def PrintStructComparisonForwardDecl(structure): + out = '' + out += f'bool operator==(const {structure.name} & a, const {structure.name} b);\n' + return out + + +def PrintStructComparison(structure): + out = '' + out += f'bool operator==(const {structure.name} & a, const {structure.name} b) {{\n' + out += ' return ' + is_first = True + for m in structure.members: + if m.name not in NAMES_TO_IGNORE: + if not is_first: + out += '\n && ' + else: + is_first = False + out += f'a.{m.name} == b.{m.name}' + out += ';\n' + out += '}\n' + return out + + +class VulkanEnum: + class Option: + + def __init__(self, name, value, bitpos, comment): + self.name = name + self.comment = comment + + if bitpos is not None: + value = 1 << int(bitpos) + elif isinstance(value, str): + if value.lower().startswith('0x'): + value = int(value, 16) + else: + value = int(value) + + self.value = value + + def values(self): + return { + 'optName': self.name, + 'optValue': self.value, + 'optComment': self.comment, + } + + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + self.options = [] + + for child in rootNode: + childName = child.get('name') + childValue = child.get('value') + childBitpos = child.get('bitpos') + childComment = child.get('comment') + childExtends = child.get('extends') + childOffset = child.get('offset') + childExtNum = child.get('extnumber') + support = child.get('supported') + if support == 'disabled': + continue + + if childName is None: + continue + if childValue is None and childBitpos is None and childOffset is None: + continue + + if childExtends is not None and childExtNum is not None and childOffset is not None: + childValue = CalcEnumValue(int(childExtNum), int(childOffset)) + if 'dir' in child.keys(): + childValue = -childValue + duplicate = False + for o in self.options: + if o.values()['optName'] == childName: + duplicate = True + if duplicate: + continue + + self.options.append(VulkanEnum.Option( + childName, childValue, childBitpos, childComment)) + + +class VulkanBitmask: + + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + + # Read each value that the enum contains + self.options = [] + for child in rootNode: + childName = child.get('name') + childValue = child.get('value') + childBitpos = child.get('bitpos') + childComment = child.get('comment') + support = child.get('supported') + if childName is None or (childValue is None and childBitpos is None): + continue + if support == 'disabled': + continue + + duplicate = False + for option in self.options: + if option.name == childName: + duplicate = True + if duplicate: + continue + + self.options.append(VulkanEnum.Option( + childName, childValue, childBitpos, childComment)) + + +class VulkanFlags: + + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.type = rootNode.get('type') + self.enum = rootNode.get('requires') + # 64 bit flags use bitvalues, not requires + if self.enum is None: + self.enum = rootNode.get('bitvalues') + + +class VulkanVariable: + def __init__(self, rootNode, constants): + self.name = rootNode.find('name').text + # Typename, dereferenced and converted to a useable C++ token + self.typeID = rootNode.find('type').text + self.baseType = self.typeID + self.childType = None + self.arrayLength = None + self.text = '' + for node in rootNode.itertext(): + comment = rootNode.find('comment') + if comment is not None and comment.text == node: + continue + self.text += node + + typeMatch = re.search('.+?(?=' + self.name + ')', self.text) + self.type = typeMatch.string[typeMatch.start():typeMatch.end()] + self.type = ' '.join(self.type.split()) + bracketMatch = re.search('(?<=\\[)[a-zA-Z0-9_]+(?=\\])', self.text) + if bracketMatch is not None: + matchText = bracketMatch.string[bracketMatch.start( + ):bracketMatch.end()] + self.childType = self.type + self.type += '[' + matchText + ']' + if matchText in constants: + self.arrayLength = constants[matchText] + else: + self.arrayLength = matchText + + self.lengthMember = False + lengthString = rootNode.get('len') + lengths = [] + if lengthString is not None: + lengths = re.split(',', lengthString) + lengths = list(filter(('null-terminated').__ne__, lengths)) + if self.arrayLength is None and len(lengths) > 0: + self.childType = '*'.join(self.type.split('*')[0:-1]) + self.arrayLength = lengths[0] + self.lengthMember = True + if self.arrayLength is not None and self.arrayLength.startswith('latexmath'): + code = self.arrayLength[10:len(self.arrayLength)] + code = re.sub('\\[', '', code) + code = re.sub('\\]', '', code) + code = re.sub('\\\\(lceil|rceil)', '', code) + code = re.sub('{|}', '', code) + code = re.sub('\\\\mathit', '', code) + code = re.sub('\\\\over', '/', code) + code = re.sub('\\\\textrm', '', code) + self.arrayLength = code + + # Dereference if necessary and handle members of variables + if self.arrayLength is not None: + self.arrayLength = re.sub('::', '->', self.arrayLength) + sections = self.arrayLength.split('->') + if sections[-1][0] == 'p' and sections[0][1].isupper(): + self.arrayLength = '*' + self.arrayLength + + +class VulkanStructure: + def __init__(self, name, rootNode, constants, extTypes): + self.name = name + self.members = [] + self.guard = None + self.sTypeName = None + self.extendsStruct = rootNode.get('structextends') + self.hasLengthmember = False + + for node in rootNode.findall('member'): + if node.get('values') is not None: + self.sTypeName = node.get('values') + self.members.append(VulkanVariable(node, constants)) + + for member in self.members: + if member.lengthMember: + self.hasLengthmember = True + break + + for k, elem in extTypes.items(): + if k == self.name: + for e in elem: + if e.guard is not None: + self.guard = e.guard + + +class VulkanExtension: + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.number = int(rootNode.get('number')) + self.type = rootNode.get('type') + self.dependency = rootNode.get('requires') + self.guard = GetFeatureProtect(rootNode) + self.supported = rootNode.get('supported') + self.extNameStr = None + self.vktypes = [] + self.vkfuncs = [] + self.constants = OrderedDict() + self.enumValues = OrderedDict() + self.node = rootNode + + for req in rootNode.findall('require'): + for ty in req.findall('type'): + self.vktypes.append(ty.get('name')) + + for func in req.findall('command'): + self.vkfuncs.append(func.get('name')) + + for enum in req.findall('enum'): + base = enum.get('extends') + name = enum.get('name') + value = enum.get('value') + bitpos = enum.get('bitpos') + offset = enum.get('offset') + # gets the VK_XXX_EXTENSION_NAME string + if value == f'"{self.name}"': + self.extNameStr = name + + if value is None and bitpos is not None: + value = 1 << int(bitpos) + + if offset is not None: + offset = int(offset) + if base is not None and offset is not None: + enumValue = 1000000000 + 1000*(self.number - 1) + offset + if enum.get('dir') == '-': + enumValue = -enumValue + self.enumValues[base] = (name, enumValue) + else: + self.constants[name] = value + + +class VulkanVersion: + def __init__(self, rootNode): + self.name = rootNode.get('name') + self.constant = self.name.replace('_VERSION_', '_API_VERSION_') + self.names = set() + + match = re.search(r"^[A-Z]+_VERSION_([1-9][0-9]*)_([0-9]+)$", self.name) + self.major = int(match.group(1)) + self.minor = int(match.group(2)) + + for req in rootNode.findall('require'): + for ty in req.findall('type'): + self.names.add(ty.get('name')) + for func in req.findall('command'): + self.names.add(func.get('name')) + for enum in req.findall('enum'): + self.names.add(enum.get('name')) + self.names = sorted(self.names) + +class VulkanFormatRange: + def __init__(self, min_inst_version, ext_name, first, last): + self.minimum_instance_version = min_inst_version + self.extension_name = ext_name + self.first_format = first + self.last_format = last + +class VulkanVideoRequiredCapabilities(): + def __init__(self, struct, member, value): + self.struct = struct + self.member = member + self.value = value + +class VulkanVideoFormat(): + def __init__(self, name, usage): + self.name = name + self.usage = usage + self.properties = OrderedDict() + self.requiredCaps = list() + super().__init__() + +class VulkanVideoProfileStructMember(): + def __init__(self, name): + self.name = name + self.values = OrderedDict() + +class VulkanVideoProfileStruct(): + def __init__(self, struct): + self.struct = struct + self.members = OrderedDict() + +class VulkanVideoCodec(): + def __init__(self, name, extend = None, value = None): + self.name = name + self.value = value + self.profileStructs = OrderedDict() + self.capabilities = OrderedDict() + self.formats = OrderedDict() + if extend is not None: + self.profileStructs = copy.deepcopy(extend.profileStructs) + self.capabilities = copy.deepcopy(extend.capabilities) + self.formats = copy.deepcopy(extend.formats) diff --git a/scripts/kvt_genvk.py b/scripts/kvt_genvk.py index 8b9de7b7..868cc3fb 100644 --- a/scripts/kvt_genvk.py +++ b/scripts/kvt_genvk.py @@ -359,9 +359,9 @@ if __name__ == '__main__': from cgenerator import CGeneratorOptions, COutputGenerator # Generator Modifications - from mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator - from vulkan_tools_helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions - from vulkaninfo_generator import VulkanInfoGenerator, VulkanInfoGeneratorOptions + from generators.mock_icd_generator import MockICDGeneratorOptions, MockICDOutputGenerator + from generators.vulkan_tools_helper_file_generator import HelperFileOutputGenerator, HelperFileOutputGeneratorOptions + from generators.vulkaninfo_generator import VulkanInfoGenerator, VulkanInfoGeneratorOptions # Temporary workaround for vkconventions python2 compatibility import abc abc.ABC = abc.ABCMeta('ABC', (object,), {}) diff --git a/scripts/mock_icd_generator.py b/scripts/mock_icd_generator.py deleted file mode 100644 index f64f4af0..00000000 --- a/scripts/mock_icd_generator.py +++ /dev/null @@ -1,1635 +0,0 @@ -#!/usr/bin/python3 -i -# -# Copyright (c) 2015-2025 The Khronos Group Inc. -# Copyright (c) 2015-2025 Valve Corporation -# Copyright (c) 2015-2025 LunarG, Inc. -# Copyright (c) 2015-2025 Google Inc. -# Copyright (c) 2023-2025 RasterGrid Kft. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Tobin Ehlis -# -# This script generates a Mock ICD that intercepts almost all Vulkan -# functions. That layer is not intended to be useful or even compilable -# in its initial state. Rather it's intended to be a starting point that -# can be copied and customized to assist in creation of a new layer. - -import os,re,sys -from generator import * -from common_codegen import * - -CUSTOM_C_INTERCEPTS = { -'vkCreateInstance': ''' - // TODO: If loader ver <=4 ICD must fail with VK_ERROR_INCOMPATIBLE_DRIVER for all vkCreateInstance calls with - // apiVersion set to > Vulkan 1.0 because the loader is still at interface version <= 4. Otherwise, the - // ICD should behave as normal. - if (loader_interface_version <= 4) { - return VK_ERROR_INCOMPATIBLE_DRIVER; - } - *pInstance = (VkInstance)CreateDispObjHandle(); - for (auto& physical_device : physical_device_map[*pInstance]) - physical_device = (VkPhysicalDevice)CreateDispObjHandle(); - // TODO: If emulating specific device caps, will need to add intelligence here - return VK_SUCCESS; -''', -'vkDestroyInstance': ''' - if (instance) { - for (const auto physical_device : physical_device_map.at(instance)) { - display_map.erase(physical_device); - DestroyDispObjHandle((void*)physical_device); - } - physical_device_map.erase(instance); - DestroyDispObjHandle((void*)instance); - } -''', -'vkAllocateCommandBuffers': ''' - unique_lock_t lock(global_lock); - for (uint32_t i = 0; i < pAllocateInfo->commandBufferCount; ++i) { - pCommandBuffers[i] = (VkCommandBuffer)CreateDispObjHandle(); - command_pool_buffer_map[pAllocateInfo->commandPool].push_back(pCommandBuffers[i]); - } - return VK_SUCCESS; -''', -'vkFreeCommandBuffers': ''' - unique_lock_t lock(global_lock); - for (auto i = 0u; i < commandBufferCount; ++i) { - if (!pCommandBuffers[i]) { - continue; - } - - for (auto& pair : command_pool_buffer_map) { - auto& cbs = pair.second; - auto it = std::find(cbs.begin(), cbs.end(), pCommandBuffers[i]); - if (it != cbs.end()) { - cbs.erase(it); - } - } - - DestroyDispObjHandle((void*) pCommandBuffers[i]); - } -''', -'vkCreateCommandPool': ''' - unique_lock_t lock(global_lock); - *pCommandPool = (VkCommandPool)global_unique_handle++; - command_pool_map[device].insert(*pCommandPool); - return VK_SUCCESS; -''', -'vkDestroyCommandPool': ''' - // destroy command buffers for this pool - unique_lock_t lock(global_lock); - auto it = command_pool_buffer_map.find(commandPool); - if (it != command_pool_buffer_map.end()) { - for (auto& cb : it->second) { - DestroyDispObjHandle((void*) cb); - } - command_pool_buffer_map.erase(it); - } - command_pool_map[device].erase(commandPool); -''', -'vkEnumeratePhysicalDevices': ''' - VkResult result_code = VK_SUCCESS; - if (pPhysicalDevices) { - const auto return_count = (std::min)(*pPhysicalDeviceCount, icd_physical_device_count); - for (uint32_t i = 0; i < return_count; ++i) pPhysicalDevices[i] = physical_device_map.at(instance)[i]; - if (return_count < icd_physical_device_count) result_code = VK_INCOMPLETE; - *pPhysicalDeviceCount = return_count; - } else { - *pPhysicalDeviceCount = icd_physical_device_count; - } - return result_code; -''', -'vkCreateDevice': ''' - *pDevice = (VkDevice)CreateDispObjHandle(); - // TODO: If emulating specific device caps, will need to add intelligence here - return VK_SUCCESS; -''', -'vkDestroyDevice': ''' - unique_lock_t lock(global_lock); - // First destroy sub-device objects - // Destroy Queues - for (auto queue_family_map_pair : queue_map[device]) { - for (auto index_queue_pair : queue_map[device][queue_family_map_pair.first]) { - DestroyDispObjHandle((void*)index_queue_pair.second); - } - } - - for (auto& cp : command_pool_map[device]) { - for (auto& cb : command_pool_buffer_map[cp]) { - DestroyDispObjHandle((void*) cb); - } - command_pool_buffer_map.erase(cp); - } - command_pool_map[device].clear(); - - queue_map.erase(device); - buffer_map.erase(device); - image_memory_size_map.erase(device); - // Now destroy device - DestroyDispObjHandle((void*)device); - // TODO: If emulating specific device caps, will need to add intelligence here -''', -'vkGetDeviceQueue': ''' - unique_lock_t lock(global_lock); - auto queue = queue_map[device][queueFamilyIndex][queueIndex]; - if (queue) { - *pQueue = queue; - } else { - *pQueue = queue_map[device][queueFamilyIndex][queueIndex] = (VkQueue)CreateDispObjHandle(); - } - // TODO: If emulating specific device caps, will need to add intelligence here - return; -''', -'vkGetDeviceQueue2': ''' - GetDeviceQueue(device, pQueueInfo->queueFamilyIndex, pQueueInfo->queueIndex, pQueue); - // TODO: Add further support for GetDeviceQueue2 features -''', -'vkEnumerateInstanceLayerProperties': ''' - return VK_SUCCESS; -''', -'vkEnumerateInstanceVersion': ''' - *pApiVersion = VK_HEADER_VERSION_COMPLETE; - return VK_SUCCESS; -''', -'vkEnumerateDeviceLayerProperties': ''' - return VK_SUCCESS; -''', -'vkEnumerateInstanceExtensionProperties': ''' - // If requesting number of extensions, return that - if (!pLayerName) { - if (!pProperties) { - *pPropertyCount = (uint32_t)instance_extension_map.size(); - } else { - uint32_t i = 0; - for (const auto &name_ver_pair : instance_extension_map) { - if (i == *pPropertyCount) { - break; - } - std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName)); - pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0; - pProperties[i].specVersion = name_ver_pair.second; - ++i; - } - if (i != instance_extension_map.size()) { - return VK_INCOMPLETE; - } - } - } - // If requesting extension properties, fill in data struct for number of extensions - return VK_SUCCESS; -''', -'vkEnumerateDeviceExtensionProperties': ''' - // If requesting number of extensions, return that - if (!pLayerName) { - if (!pProperties) { - *pPropertyCount = (uint32_t)device_extension_map.size(); - } else { - uint32_t i = 0; - for (const auto &name_ver_pair : device_extension_map) { - if (i == *pPropertyCount) { - break; - } - std::strncpy(pProperties[i].extensionName, name_ver_pair.first.c_str(), sizeof(pProperties[i].extensionName)); - pProperties[i].extensionName[sizeof(pProperties[i].extensionName) - 1] = 0; - pProperties[i].specVersion = name_ver_pair.second; - ++i; - } - *pPropertyCount = i; - if (i != device_extension_map.size()) { - return VK_INCOMPLETE; - } - } - } - // If requesting extension properties, fill in data struct for number of extensions - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfacePresentModesKHR': ''' - // Currently always say that all present modes are supported - if (!pPresentModes) { - *pPresentModeCount = 6; - } else { - if (*pPresentModeCount >= 6) pPresentModes[5] = VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR; - if (*pPresentModeCount >= 5) pPresentModes[4] = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR; - if (*pPresentModeCount >= 4) pPresentModes[3] = VK_PRESENT_MODE_FIFO_RELAXED_KHR; - if (*pPresentModeCount >= 3) pPresentModes[2] = VK_PRESENT_MODE_FIFO_KHR; - if (*pPresentModeCount >= 2) pPresentModes[1] = VK_PRESENT_MODE_MAILBOX_KHR; - if (*pPresentModeCount >= 1) pPresentModes[0] = VK_PRESENT_MODE_IMMEDIATE_KHR; - *pPresentModeCount = *pPresentModeCount < 6 ? *pPresentModeCount : 6; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfaceFormatsKHR': ''' - // Currently always say that RGBA8 & BGRA8 are supported - if (!pSurfaceFormats) { - *pSurfaceFormatCount = 2; - } else { - if (*pSurfaceFormatCount >= 2) { - pSurfaceFormats[1].format = VK_FORMAT_R8G8B8A8_UNORM; - pSurfaceFormats[1].colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - if (*pSurfaceFormatCount >= 1) { - pSurfaceFormats[0].format = VK_FORMAT_B8G8R8A8_UNORM; - pSurfaceFormats[0].colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfaceFormats2KHR': ''' - // Currently always say that RGBA8 & BGRA8 are supported - if (!pSurfaceFormats) { - *pSurfaceFormatCount = 2; - } else { - if (*pSurfaceFormatCount >= 2) { - pSurfaceFormats[1].pNext = nullptr; - pSurfaceFormats[1].surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM; - pSurfaceFormats[1].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - if (*pSurfaceFormatCount >= 1) { - pSurfaceFormats[1].pNext = nullptr; - pSurfaceFormats[0].surfaceFormat.format = VK_FORMAT_B8G8R8A8_UNORM; - pSurfaceFormats[0].surfaceFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfaceSupportKHR': ''' - // Currently say that all surface/queue combos are supported - *pSupported = VK_TRUE; - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfaceCapabilitiesKHR': ''' - // In general just say max supported is available for requested surface - pSurfaceCapabilities->minImageCount = 1; - pSurfaceCapabilities->maxImageCount = 0; - pSurfaceCapabilities->currentExtent.width = 0xFFFFFFFF; - pSurfaceCapabilities->currentExtent.height = 0xFFFFFFFF; - pSurfaceCapabilities->minImageExtent.width = 1; - pSurfaceCapabilities->minImageExtent.height = 1; - pSurfaceCapabilities->maxImageExtent.width = 0xFFFF; - pSurfaceCapabilities->maxImageExtent.height = 0xFFFF; - pSurfaceCapabilities->maxImageArrayLayers = 128; - pSurfaceCapabilities->supportedTransforms = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR | - VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | - VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR | - VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR | - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR | - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR | - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR | - VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR | - VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR; - pSurfaceCapabilities->currentTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; - pSurfaceCapabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | - VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR | - VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR | - VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR; - pSurfaceCapabilities->supportedUsageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | - VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_SAMPLED_BIT | - VK_IMAGE_USAGE_STORAGE_BIT | - VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | - VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | - VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT; - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSurfaceCapabilities2KHR': ''' - GetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, pSurfaceInfo->surface, &pSurfaceCapabilities->surfaceCapabilities); - - auto *present_mode_compatibility = lvl_find_mod_in_chain(pSurfaceCapabilities->pNext); - if (present_mode_compatibility) { - if (!present_mode_compatibility->pPresentModes) { - present_mode_compatibility->presentModeCount = 3; - } else { - // arbitrary - present_mode_compatibility->pPresentModes[0] = VK_PRESENT_MODE_IMMEDIATE_KHR; - present_mode_compatibility->pPresentModes[1] = VK_PRESENT_MODE_FIFO_KHR; - present_mode_compatibility->pPresentModes[2] = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR; - } - } - return VK_SUCCESS; -''', -'vkGetInstanceProcAddr': ''' - if (!negotiate_loader_icd_interface_called) { - loader_interface_version = 0; - } - const auto &item = name_to_funcptr_map.find(pName); - if (item != name_to_funcptr_map.end()) { - return reinterpret_cast(item->second); - } - // Mock should intercept all functions so if we get here just return null - return nullptr; -''', -'vkGetDeviceProcAddr': ''' - return GetInstanceProcAddr(nullptr, pName); -''', -'vkGetPhysicalDeviceMemoryProperties': ''' - pMemoryProperties->memoryTypeCount = 6; - // Host visible Coherent - pMemoryProperties->memoryTypes[0].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - pMemoryProperties->memoryTypes[0].heapIndex = 0; - // Host visible Cached - pMemoryProperties->memoryTypes[1].propertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT; - pMemoryProperties->memoryTypes[1].heapIndex = 0; - // Device local and Host visible - pMemoryProperties->memoryTypes[2].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_CACHED_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - pMemoryProperties->memoryTypes[2].heapIndex = 1; - // Device local lazily - pMemoryProperties->memoryTypes[3].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT; - pMemoryProperties->memoryTypes[3].heapIndex = 1; - // Device local protected - pMemoryProperties->memoryTypes[4].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_PROTECTED_BIT; - pMemoryProperties->memoryTypes[4].heapIndex = 1; - // Device local only - pMemoryProperties->memoryTypes[5].propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - pMemoryProperties->memoryTypes[5].heapIndex = 1; - pMemoryProperties->memoryHeapCount = 2; - pMemoryProperties->memoryHeaps[0].flags = VK_MEMORY_HEAP_MULTI_INSTANCE_BIT; - pMemoryProperties->memoryHeaps[0].size = 8000000000; - pMemoryProperties->memoryHeaps[1].flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT; - pMemoryProperties->memoryHeaps[1].size = 8000000000; -''', -'vkGetPhysicalDeviceMemoryProperties2KHR': ''' - GetPhysicalDeviceMemoryProperties(physicalDevice, &pMemoryProperties->memoryProperties); -''', -'vkGetPhysicalDeviceQueueFamilyProperties': ''' - if (pQueueFamilyProperties) { - std::vector props2(*pQueueFamilyPropertyCount, { - VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR}); - GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount, props2.data()); - for (uint32_t i = 0; i < *pQueueFamilyPropertyCount; ++i) { - pQueueFamilyProperties[i] = props2[i].queueFamilyProperties; - } - } else { - GetPhysicalDeviceQueueFamilyProperties2KHR(physicalDevice, pQueueFamilyPropertyCount, nullptr); - } -''', -'vkGetPhysicalDeviceQueueFamilyProperties2KHR': ''' - if (pQueueFamilyProperties) { - if (*pQueueFamilyPropertyCount >= 1) { - auto props = &pQueueFamilyProperties[0].queueFamilyProperties; - props->queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT - | VK_QUEUE_SPARSE_BINDING_BIT | VK_QUEUE_PROTECTED_BIT; - props->queueCount = 1; - props->timestampValidBits = 16; - props->minImageTransferGranularity = {1,1,1}; - } - if (*pQueueFamilyPropertyCount >= 2) { - auto props = &pQueueFamilyProperties[1].queueFamilyProperties; - props->queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT | VK_QUEUE_VIDEO_DECODE_BIT_KHR; - props->queueCount = 1; - props->timestampValidBits = 16; - props->minImageTransferGranularity = {1,1,1}; - - auto status_query_props = lvl_find_mod_in_chain(pQueueFamilyProperties[1].pNext); - if (status_query_props) { - status_query_props->queryResultStatusSupport = VK_TRUE; - } - auto video_props = lvl_find_mod_in_chain(pQueueFamilyProperties[1].pNext); - if (video_props) { - video_props->videoCodecOperations = VK_VIDEO_CODEC_OPERATION_DECODE_H264_BIT_KHR - | VK_VIDEO_CODEC_OPERATION_DECODE_H265_BIT_KHR - | VK_VIDEO_CODEC_OPERATION_DECODE_AV1_BIT_KHR; - } - } - if (*pQueueFamilyPropertyCount >= 3) { - auto props = &pQueueFamilyProperties[2].queueFamilyProperties; - props->queueFlags = VK_QUEUE_TRANSFER_BIT | VK_QUEUE_PROTECTED_BIT | VK_QUEUE_VIDEO_ENCODE_BIT_KHR; - props->queueCount = 1; - props->timestampValidBits = 16; - props->minImageTransferGranularity = {1,1,1}; - - auto status_query_props = lvl_find_mod_in_chain(pQueueFamilyProperties[2].pNext); - if (status_query_props) { - status_query_props->queryResultStatusSupport = VK_TRUE; - } - auto video_props = lvl_find_mod_in_chain(pQueueFamilyProperties[2].pNext); - if (video_props) { - video_props->videoCodecOperations = VK_VIDEO_CODEC_OPERATION_ENCODE_H264_BIT_KHR - | VK_VIDEO_CODEC_OPERATION_ENCODE_H265_BIT_KHR - | VK_VIDEO_CODEC_OPERATION_ENCODE_AV1_BIT_KHR; - } - } - if (*pQueueFamilyPropertyCount > 3) { - *pQueueFamilyPropertyCount = 3; - } - } else { - *pQueueFamilyPropertyCount = 3; - } -''', -'vkGetPhysicalDeviceFeatures': ''' - uint32_t num_bools = sizeof(VkPhysicalDeviceFeatures) / sizeof(VkBool32); - VkBool32 *bool_array = &pFeatures->robustBufferAccess; - SetBoolArrayTrue(bool_array, num_bools); -''', -'vkGetPhysicalDeviceFeatures2KHR': ''' - GetPhysicalDeviceFeatures(physicalDevice, &pFeatures->features); - uint32_t num_bools = 0; // Count number of VkBool32s in extension structs - VkBool32* feat_bools = nullptr; - auto vk_1_1_features = lvl_find_mod_in_chain(pFeatures->pNext); - if (vk_1_1_features) { - vk_1_1_features->protectedMemory = VK_TRUE; - } - auto vk_1_3_features = lvl_find_mod_in_chain(pFeatures->pNext); - if (vk_1_3_features) { - vk_1_3_features->synchronization2 = VK_TRUE; - } - auto prot_features = lvl_find_mod_in_chain(pFeatures->pNext); - if (prot_features) { - prot_features->protectedMemory = VK_TRUE; - } - auto sync2_features = lvl_find_mod_in_chain(pFeatures->pNext); - if (sync2_features) { - sync2_features->synchronization2 = VK_TRUE; - } - auto video_maintenance1_features = lvl_find_mod_in_chain(pFeatures->pNext); - if (video_maintenance1_features) { - video_maintenance1_features->videoMaintenance1 = VK_TRUE; - } - const auto *desc_idx_features = lvl_find_in_chain(pFeatures->pNext); - if (desc_idx_features) { - const auto bool_size = sizeof(VkPhysicalDeviceDescriptorIndexingFeaturesEXT) - offsetof(VkPhysicalDeviceDescriptorIndexingFeaturesEXT, shaderInputAttachmentArrayDynamicIndexing); - num_bools = bool_size/sizeof(VkBool32); - feat_bools = (VkBool32*)&desc_idx_features->shaderInputAttachmentArrayDynamicIndexing; - SetBoolArrayTrue(feat_bools, num_bools); - } - const auto *blendop_features = lvl_find_in_chain(pFeatures->pNext); - if (blendop_features) { - const auto bool_size = sizeof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT) - offsetof(VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT, advancedBlendCoherentOperations); - num_bools = bool_size/sizeof(VkBool32); - feat_bools = (VkBool32*)&blendop_features->advancedBlendCoherentOperations; - SetBoolArrayTrue(feat_bools, num_bools); - } - const auto *host_image_copy_features = lvl_find_in_chain(pFeatures->pNext); - if (host_image_copy_features) { - feat_bools = (VkBool32*)&host_image_copy_features->hostImageCopy; - SetBoolArrayTrue(feat_bools, 1); - } -''', -'vkGetPhysicalDeviceFormatProperties': ''' - if (VK_FORMAT_UNDEFINED == format) { - *pFormatProperties = { 0x0, 0x0, 0x0 }; - } else { - // Default to a color format, skip DS bit - *pFormatProperties = { 0x00FFFDFF, 0x00FFFDFF, 0x00FFFDFF }; - switch (format) { - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_X8_D24_UNORM_PACK32: - case VK_FORMAT_D32_SFLOAT: - case VK_FORMAT_S8_UINT: - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - // Don't set color bits for DS formats - *pFormatProperties = { 0x00FFFE7F, 0x00FFFE7F, 0x00FFFE7F }; - break; - case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: - case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: - case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM: - case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16: - case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM: - // Set decode/encode bits for these formats - *pFormatProperties = { 0x1EFFFDFF, 0x1EFFFDFF, 0x00FFFDFF }; - break; - default: - break; - } - } -''', -'vkGetPhysicalDeviceFormatProperties2KHR': ''' - GetPhysicalDeviceFormatProperties(physicalDevice, format, &pFormatProperties->formatProperties); - VkFormatProperties3KHR *props_3 = lvl_find_mod_in_chain(pFormatProperties->pNext); - if (props_3) { - props_3->linearTilingFeatures = pFormatProperties->formatProperties.linearTilingFeatures; - props_3->optimalTilingFeatures = pFormatProperties->formatProperties.optimalTilingFeatures; - props_3->bufferFeatures = pFormatProperties->formatProperties.bufferFeatures; - props_3->optimalTilingFeatures |= VK_FORMAT_FEATURE_2_HOST_IMAGE_TRANSFER_BIT_EXT; - } -''', -'vkGetPhysicalDeviceImageFormatProperties': ''' - // A hardcoded unsupported format - if (format == VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) { - return VK_ERROR_FORMAT_NOT_SUPPORTED; - } - - // TODO: Just hard-coding some values for now - // TODO: If tiling is linear, limit the mips, levels, & sample count - if (VK_IMAGE_TILING_LINEAR == tiling) { - *pImageFormatProperties = { { 4096, 4096, 256 }, 1, 1, VK_SAMPLE_COUNT_1_BIT, 4294967296 }; - } else { - // We hard-code support for all sample counts except 64 bits. - *pImageFormatProperties = { { 4096, 4096, 256 }, 12, 256, 0x7F & ~VK_SAMPLE_COUNT_64_BIT, 4294967296 }; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceImageFormatProperties2KHR': ''' - auto *external_image_prop = lvl_find_mod_in_chain(pImageFormatProperties->pNext); - auto *external_image_format = lvl_find_in_chain(pImageFormatInfo->pNext); - if (external_image_prop && external_image_format) { - external_image_prop->externalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; - external_image_prop->externalMemoryProperties.compatibleHandleTypes = external_image_format->handleType; - } - - GetPhysicalDeviceImageFormatProperties(physicalDevice, pImageFormatInfo->format, pImageFormatInfo->type, pImageFormatInfo->tiling, pImageFormatInfo->usage, pImageFormatInfo->flags, &pImageFormatProperties->imageFormatProperties); - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceSparseImageFormatProperties': ''' - if (!pProperties) { - *pPropertyCount = 1; - } else { - // arbitrary - pProperties->imageGranularity = {4, 4, 4}; - pProperties->flags = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT; - switch (format) { - case VK_FORMAT_D16_UNORM: - case VK_FORMAT_D32_SFLOAT: - pProperties->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - break; - case VK_FORMAT_S8_UINT: - pProperties->aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - break; - case VK_FORMAT_X8_D24_UNORM_PACK32: - case VK_FORMAT_D16_UNORM_S8_UINT: - case VK_FORMAT_D24_UNORM_S8_UINT: - case VK_FORMAT_D32_SFLOAT_S8_UINT: - pProperties->aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - break; - default: - pProperties->aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - break; - } - } -''', -'vkGetPhysicalDeviceSparseImageFormatProperties2KHR': ''' - if (pPropertyCount && pProperties) { - GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling, pPropertyCount, &pProperties->properties); - } else { - GetPhysicalDeviceSparseImageFormatProperties(physicalDevice, pFormatInfo->format, pFormatInfo->type, pFormatInfo->samples, pFormatInfo->usage, pFormatInfo->tiling, pPropertyCount, nullptr); - } -''', -'vkGetPhysicalDeviceProperties': ''' - pProperties->apiVersion = VK_HEADER_VERSION_COMPLETE; - pProperties->driverVersion = 1; - pProperties->vendorID = 0xba5eba11; - pProperties->deviceID = 0xf005ba11; - pProperties->deviceType = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU; - //std::string devName = "Vulkan Mock Device"; - strcpy(pProperties->deviceName, "Vulkan Mock Device"); - pProperties->pipelineCacheUUID[0] = 18; - pProperties->limits = SetLimits(&pProperties->limits); - pProperties->sparseProperties = { VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE, VK_TRUE }; -''', -'vkGetPhysicalDeviceProperties2KHR': ''' - // The only value that need to be set are those the Profile layer can't set - // see https://github.com/KhronosGroup/Vulkan-Profiles/issues/352 - // All values set are arbitrary - GetPhysicalDeviceProperties(physicalDevice, &pProperties->properties); - - auto *props_11 = lvl_find_mod_in_chain(pProperties->pNext); - if (props_11) { - props_11->protectedNoFault = VK_FALSE; - } - - auto *props_12 = lvl_find_mod_in_chain(pProperties->pNext); - if (props_12) { - props_12->denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; - props_12->roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; - } - - auto *props_13 = lvl_find_mod_in_chain(pProperties->pNext); - if (props_13) { - props_13->storageTexelBufferOffsetSingleTexelAlignment = VK_TRUE; - props_13->uniformTexelBufferOffsetSingleTexelAlignment = VK_TRUE; - props_13->storageTexelBufferOffsetAlignmentBytes = 16; - props_13->uniformTexelBufferOffsetAlignmentBytes = 16; - } - - auto *protected_memory_props = lvl_find_mod_in_chain(pProperties->pNext); - if (protected_memory_props) { - protected_memory_props->protectedNoFault = VK_FALSE; - } - - auto *float_controls_props = lvl_find_mod_in_chain(pProperties->pNext); - if (float_controls_props) { - float_controls_props->denormBehaviorIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; - float_controls_props->roundingModeIndependence = VK_SHADER_FLOAT_CONTROLS_INDEPENDENCE_ALL; - } - - auto *conservative_raster_props = lvl_find_mod_in_chain(pProperties->pNext); - if (conservative_raster_props) { - conservative_raster_props->primitiveOverestimationSize = 0.00195313f; - conservative_raster_props->conservativePointAndLineRasterization = VK_TRUE; - conservative_raster_props->degenerateTrianglesRasterized = VK_TRUE; - conservative_raster_props->degenerateLinesRasterized = VK_TRUE; - } - - auto *rt_pipeline_props = lvl_find_mod_in_chain(pProperties->pNext); - if (rt_pipeline_props) { - rt_pipeline_props->shaderGroupHandleSize = 32; - rt_pipeline_props->shaderGroupBaseAlignment = 64; - rt_pipeline_props->shaderGroupHandleCaptureReplaySize = 32; - } - - auto *rt_pipeline_nv_props = lvl_find_mod_in_chain(pProperties->pNext); - if (rt_pipeline_nv_props) { - rt_pipeline_nv_props->shaderGroupHandleSize = 32; - rt_pipeline_nv_props->shaderGroupBaseAlignment = 64; - } - - auto *texel_buffer_props = lvl_find_mod_in_chain(pProperties->pNext); - if (texel_buffer_props) { - texel_buffer_props->storageTexelBufferOffsetSingleTexelAlignment = VK_TRUE; - texel_buffer_props->uniformTexelBufferOffsetSingleTexelAlignment = VK_TRUE; - texel_buffer_props->storageTexelBufferOffsetAlignmentBytes = 16; - texel_buffer_props->uniformTexelBufferOffsetAlignmentBytes = 16; - } - - auto *descriptor_buffer_props = lvl_find_mod_in_chain(pProperties->pNext); - if (descriptor_buffer_props) { - descriptor_buffer_props->combinedImageSamplerDescriptorSingleArray = VK_TRUE; - descriptor_buffer_props->bufferlessPushDescriptors = VK_TRUE; - descriptor_buffer_props->allowSamplerImageViewPostSubmitCreation = VK_TRUE; - descriptor_buffer_props->descriptorBufferOffsetAlignment = 4; - } - - auto *mesh_shader_props = lvl_find_mod_in_chain(pProperties->pNext); - if (mesh_shader_props) { - mesh_shader_props->meshOutputPerVertexGranularity = 32; - mesh_shader_props->meshOutputPerPrimitiveGranularity = 32; - mesh_shader_props->prefersLocalInvocationVertexOutput = VK_TRUE; - mesh_shader_props->prefersLocalInvocationPrimitiveOutput = VK_TRUE; - mesh_shader_props->prefersCompactVertexOutput = VK_TRUE; - mesh_shader_props->prefersCompactPrimitiveOutput = VK_TRUE; - } - - auto *fragment_density_map2_props = lvl_find_mod_in_chain(pProperties->pNext); - if (fragment_density_map2_props) { - fragment_density_map2_props->subsampledLoads = VK_FALSE; - fragment_density_map2_props->subsampledCoarseReconstructionEarlyAccess = VK_FALSE; - fragment_density_map2_props->maxSubsampledArrayLayers = 2; - fragment_density_map2_props->maxDescriptorSetSubsampledSamplers = 1; - } - - auto *maintenance3_props = lvl_find_mod_in_chain(pProperties->pNext); - if (maintenance3_props) { - maintenance3_props->maxMemoryAllocationSize = 1073741824; - maintenance3_props->maxPerSetDescriptors = 1024; - } - - const uint32_t num_copy_layouts = 5; - const VkImageLayout HostCopyLayouts[]{ - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL, - VK_IMAGE_LAYOUT_STENCIL_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL, - }; - - auto *host_image_copy_props = lvl_find_mod_in_chain(pProperties->pNext); - if (host_image_copy_props){ - if (host_image_copy_props->pCopyDstLayouts == nullptr) host_image_copy_props->copyDstLayoutCount = num_copy_layouts; - else { - uint32_t num_layouts = (std::min)(host_image_copy_props->copyDstLayoutCount, num_copy_layouts); - for (uint32_t i = 0; i < num_layouts; i++) { - host_image_copy_props->pCopyDstLayouts[i] = HostCopyLayouts[i]; - } - } - if (host_image_copy_props->pCopySrcLayouts == nullptr) host_image_copy_props->copySrcLayoutCount = num_copy_layouts; - else { - uint32_t num_layouts = (std::min)(host_image_copy_props->copySrcLayoutCount, num_copy_layouts); - for (uint32_t i = 0; i < num_layouts; i++) { - host_image_copy_props->pCopySrcLayouts[i] = HostCopyLayouts[i]; - } - } - } - - auto *driver_properties = lvl_find_mod_in_chain(pProperties->pNext); - if (driver_properties) { - std::strncpy(driver_properties->driverName, "Vulkan Mock Device", VK_MAX_DRIVER_NAME_SIZE); -#if defined(GIT_BRANCH_NAME) && defined(GIT_TAG_INFO) - std::strncpy(driver_properties->driverInfo, "Branch: " GIT_BRANCH_NAME " Tag Info: " GIT_TAG_INFO, VK_MAX_DRIVER_INFO_SIZE); -#else - std::strncpy(driver_properties->driverInfo, "Branch: --unknown-- Tag Info: --unknown--", VK_MAX_DRIVER_INFO_SIZE); -#endif - } - - auto *layered_properties = lvl_find_mod_in_chain(pProperties->pNext); - if (layered_properties) { - layered_properties->layeredApiCount = 1; - if (layered_properties->pLayeredApis) { - layered_properties->pLayeredApis[0] = VkPhysicalDeviceLayeredApiPropertiesKHR{ - VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_LAYERED_API_PROPERTIES_KHR, - nullptr, - 0xba5eba11, - 0xf005ba11, - VK_PHYSICAL_DEVICE_LAYERED_API_VULKAN_KHR - }; - std::strncpy(layered_properties->pLayeredApis[0].deviceName, "Fake Driver", VK_MAX_PHYSICAL_DEVICE_NAME_SIZE); - } - } -''', -'vkGetPhysicalDeviceExternalSemaphoreProperties':''' - // Hard code support for all handle types and features - pExternalSemaphoreProperties->exportFromImportedHandleTypes = 0x1F; - pExternalSemaphoreProperties->compatibleHandleTypes = 0x1F; - pExternalSemaphoreProperties->externalSemaphoreFeatures = 0x3; -''', -'vkGetPhysicalDeviceExternalSemaphorePropertiesKHR':''' - GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties); -''', -'vkGetPhysicalDeviceExternalFenceProperties':''' - // Hard-code support for all handle types and features - pExternalFenceProperties->exportFromImportedHandleTypes = 0xF; - pExternalFenceProperties->compatibleHandleTypes = 0xF; - pExternalFenceProperties->externalFenceFeatures = 0x3; -''', -'vkGetPhysicalDeviceExternalFencePropertiesKHR':''' - GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties); -''', -'vkGetPhysicalDeviceExternalBufferProperties':''' - constexpr VkExternalMemoryHandleTypeFlags supported_flags = 0x1FF; - if (pExternalBufferInfo->handleType & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) { - // Can't have dedicated memory with AHB - pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT | VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT; - pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = pExternalBufferInfo->handleType; - pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = pExternalBufferInfo->handleType; - } else if (pExternalBufferInfo->handleType & supported_flags) { - pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0x7; - pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = supported_flags; - pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = supported_flags; - } else { - pExternalBufferProperties->externalMemoryProperties.externalMemoryFeatures = 0; - pExternalBufferProperties->externalMemoryProperties.exportFromImportedHandleTypes = 0; - // According to spec, handle type is always compatible with itself. Even if export/import - // not supported, it's important to properly implement self-compatibility property since - // application's control flow can rely on this. - pExternalBufferProperties->externalMemoryProperties.compatibleHandleTypes = pExternalBufferInfo->handleType; - } -''', -'vkGetPhysicalDeviceExternalBufferPropertiesKHR':''' - GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties); -''', -'vkGetBufferMemoryRequirements': ''' - // TODO: Just hard-coding reqs for now - pMemoryRequirements->size = 4096; - pMemoryRequirements->alignment = 1; - pMemoryRequirements->memoryTypeBits = 0xFFFF; - // Return a better size based on the buffer size from the create info. - unique_lock_t lock(global_lock); - auto d_iter = buffer_map.find(device); - if (d_iter != buffer_map.end()) { - auto iter = d_iter->second.find(buffer); - if (iter != d_iter->second.end()) { - pMemoryRequirements->size = ((iter->second.size + 4095) / 4096) * 4096; - } - } -''', -'vkGetBufferMemoryRequirements2KHR': ''' - GetBufferMemoryRequirements(device, pInfo->buffer, &pMemoryRequirements->memoryRequirements); -''', -'vkGetDeviceBufferMemoryRequirements': ''' - // TODO: Just hard-coding reqs for now - pMemoryRequirements->memoryRequirements.alignment = 1; - pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF; - - // Return a size based on the buffer size from the create info. - pMemoryRequirements->memoryRequirements.size = ((pInfo->pCreateInfo->size + 4095) / 4096) * 4096; -''', -'vkGetDeviceBufferMemoryRequirementsKHR': ''' - GetDeviceBufferMemoryRequirements(device, pInfo, pMemoryRequirements); -''', -'vkGetImageMemoryRequirements': ''' - pMemoryRequirements->size = 0; - pMemoryRequirements->alignment = 1; - - unique_lock_t lock(global_lock); - auto d_iter = image_memory_size_map.find(device); - if(d_iter != image_memory_size_map.end()){ - auto iter = d_iter->second.find(image); - if (iter != d_iter->second.end()) { - pMemoryRequirements->size = iter->second; - } - } - // Here we hard-code that the memory type at index 3 doesn't support this image. - pMemoryRequirements->memoryTypeBits = 0xFFFF & ~(0x1 << 3); -''', -'vkGetImageMemoryRequirements2KHR': ''' - GetImageMemoryRequirements(device, pInfo->image, &pMemoryRequirements->memoryRequirements); -''', -'vkGetDeviceImageMemoryRequirements': ''' - pMemoryRequirements->memoryRequirements.size = GetImageSizeFromCreateInfo(pInfo->pCreateInfo); - pMemoryRequirements->memoryRequirements.alignment = 1; - // Here we hard-code that the memory type at index 3 doesn't support this image. - pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF & ~(0x1 << 3); -''', -'vkGetDeviceImageMemoryRequirementsKHR': ''' - GetDeviceImageMemoryRequirements(device, pInfo, pMemoryRequirements); -''', -'vkMapMemory': ''' - unique_lock_t lock(global_lock); - if (VK_WHOLE_SIZE == size) { - if (allocated_memory_size_map.count(memory) != 0) - size = allocated_memory_size_map[memory] - offset; - else - size = 0x10000; - } - void* map_addr = malloc((size_t)size); - mapped_memory_map[memory].push_back(map_addr); - *ppData = map_addr; - return VK_SUCCESS; -''', -'vkMapMemory2KHR': ''' - return MapMemory(device, pMemoryMapInfo->memory, pMemoryMapInfo->offset, pMemoryMapInfo->size, pMemoryMapInfo->flags, ppData); -''', -'vkUnmapMemory': ''' - unique_lock_t lock(global_lock); - for (auto map_addr : mapped_memory_map[memory]) { - free(map_addr); - } - mapped_memory_map.erase(memory); -''', -'vkUnmapMemory2KHR': ''' - UnmapMemory(device, pMemoryUnmapInfo->memory); - return VK_SUCCESS; -''', -'vkGetImageSubresourceLayout': ''' - // Need safe values. Callers are computing memory offsets from pLayout, with no return code to flag failure. - *pLayout = VkSubresourceLayout(); // Default constructor zero values. -''', -'vkCreateSwapchainKHR': ''' - unique_lock_t lock(global_lock); - *pSwapchain = (VkSwapchainKHR)global_unique_handle++; - for(uint32_t i = 0; i < icd_swapchain_image_count; ++i){ - swapchain_image_map[*pSwapchain][i] = (VkImage)global_unique_handle++; - } - return VK_SUCCESS; -''', -'vkDestroySwapchainKHR': ''' - unique_lock_t lock(global_lock); - swapchain_image_map.clear(); -''', -'vkGetSwapchainImagesKHR': ''' - if (!pSwapchainImages) { - *pSwapchainImageCount = icd_swapchain_image_count; - } else { - unique_lock_t lock(global_lock); - for (uint32_t img_i = 0; img_i < (std::min)(*pSwapchainImageCount, icd_swapchain_image_count); ++img_i){ - pSwapchainImages[img_i] = swapchain_image_map.at(swapchain)[img_i]; - } - - if (*pSwapchainImageCount < icd_swapchain_image_count) return VK_INCOMPLETE; - else if (*pSwapchainImageCount > icd_swapchain_image_count) *pSwapchainImageCount = icd_swapchain_image_count; - } - return VK_SUCCESS; -''', -'vkAcquireNextImageKHR': ''' - *pImageIndex = 0; - return VK_SUCCESS; -''', -'vkAcquireNextImage2KHR': ''' - *pImageIndex = 0; - return VK_SUCCESS; -''', -'vkCreateBuffer': ''' - unique_lock_t lock(global_lock); - *pBuffer = (VkBuffer)global_unique_handle++; - buffer_map[device][*pBuffer] = { - pCreateInfo->size, - current_available_address - }; - current_available_address += pCreateInfo->size; - // Always align to next 64-bit pointer - const uint64_t alignment = current_available_address % 64; - if (alignment != 0) { - current_available_address += (64 - alignment); - } - return VK_SUCCESS; -''', -'vkDestroyBuffer': ''' - unique_lock_t lock(global_lock); - buffer_map[device].erase(buffer); -''', -'vkCreateImage': ''' - unique_lock_t lock(global_lock); - *pImage = (VkImage)global_unique_handle++; - image_memory_size_map[device][*pImage] = GetImageSizeFromCreateInfo(pCreateInfo); - return VK_SUCCESS; -''', -'vkDestroyImage': ''' - unique_lock_t lock(global_lock); - image_memory_size_map[device].erase(image); -''', -'vkEnumeratePhysicalDeviceGroupsKHR': ''' - if (!pPhysicalDeviceGroupProperties) { - *pPhysicalDeviceGroupCount = 1; - } else { - // arbitrary - pPhysicalDeviceGroupProperties->physicalDeviceCount = 1; - pPhysicalDeviceGroupProperties->physicalDevices[0] = physical_device_map.at(instance)[0]; - pPhysicalDeviceGroupProperties->subsetAllocation = VK_FALSE; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceMultisamplePropertiesEXT': ''' - if (pMultisampleProperties) { - // arbitrary - pMultisampleProperties->maxSampleLocationGridSize = {32, 32}; - } -''', -'vkGetPhysicalDeviceFragmentShadingRatesKHR': ''' - if (!pFragmentShadingRates) { - *pFragmentShadingRateCount = 1; - } else { - // arbitrary - pFragmentShadingRates->sampleCounts = VK_SAMPLE_COUNT_1_BIT | VK_SAMPLE_COUNT_4_BIT; - pFragmentShadingRates->fragmentSize = {8, 8}; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceCalibrateableTimeDomainsEXT': ''' - if (!pTimeDomains) { - *pTimeDomainCount = 1; - } else { - // arbitrary - *pTimeDomains = VK_TIME_DOMAIN_DEVICE_EXT; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceCalibrateableTimeDomainsKHR': ''' - if (!pTimeDomains) { - *pTimeDomainCount = 1; - } else { - // arbitrary - *pTimeDomains = VK_TIME_DOMAIN_DEVICE_KHR; - } - return VK_SUCCESS; -''', -'vkGetFenceWin32HandleKHR': ''' - *pHandle = (HANDLE)0x12345678; - return VK_SUCCESS; -''', -'vkGetFenceFdKHR': ''' - *pFd = 0x42; - return VK_SUCCESS; -''', -'vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR': ''' - if (!pCounters) { - *pCounterCount = 3; - } else { - if (*pCounterCount == 0){ - return VK_INCOMPLETE; - } - // arbitrary - pCounters[0].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; - pCounters[0].scope = VK_QUERY_SCOPE_COMMAND_BUFFER_KHR; - pCounters[0].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; - pCounters[0].uuid[0] = 0x01; - if (*pCounterCount == 1){ - return VK_INCOMPLETE; - } - pCounters[1].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; - pCounters[1].scope = VK_QUERY_SCOPE_RENDER_PASS_KHR; - pCounters[1].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; - pCounters[1].uuid[0] = 0x02; - if (*pCounterCount == 2){ - return VK_INCOMPLETE; - } - pCounters[2].unit = VK_PERFORMANCE_COUNTER_UNIT_GENERIC_KHR; - pCounters[2].scope = VK_QUERY_SCOPE_COMMAND_KHR; - pCounters[2].storage = VK_PERFORMANCE_COUNTER_STORAGE_INT32_KHR; - pCounters[2].uuid[0] = 0x03; - *pCounterCount = 3; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR': ''' - if (pNumPasses) { - // arbitrary - *pNumPasses = 1; - } -''', -'vkGetShaderModuleIdentifierEXT': ''' - if (pIdentifier) { - // arbitrary - pIdentifier->identifierSize = 1; - pIdentifier->identifier[0] = 0x01; - } -''', -'vkGetImageSparseMemoryRequirements': ''' - if (!pSparseMemoryRequirements) { - *pSparseMemoryRequirementCount = 1; - } else { - // arbitrary - pSparseMemoryRequirements->imageMipTailFirstLod = 0; - pSparseMemoryRequirements->imageMipTailSize = 8; - pSparseMemoryRequirements->imageMipTailOffset = 0; - pSparseMemoryRequirements->imageMipTailStride = 4; - pSparseMemoryRequirements->formatProperties.imageGranularity = {4, 4, 4}; - pSparseMemoryRequirements->formatProperties.flags = VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT; - // Would need to track the VkImage to know format for better value here - pSparseMemoryRequirements->formatProperties.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | VK_IMAGE_ASPECT_METADATA_BIT; - } - -''', -'vkGetImageSparseMemoryRequirements2KHR': ''' - if (pSparseMemoryRequirementCount && pSparseMemoryRequirements) { - GetImageSparseMemoryRequirements(device, pInfo->image, pSparseMemoryRequirementCount, &pSparseMemoryRequirements->memoryRequirements); - } else { - GetImageSparseMemoryRequirements(device, pInfo->image, pSparseMemoryRequirementCount, nullptr); - } -''', -'vkGetBufferDeviceAddress': ''' - VkDeviceAddress address = 0; - auto d_iter = buffer_map.find(device); - if (d_iter != buffer_map.end()) { - auto iter = d_iter->second.find(pInfo->buffer); - if (iter != d_iter->second.end()) { - address = iter->second.address; - } - } - return address; -''', -'vkGetBufferDeviceAddressKHR': ''' - return GetBufferDeviceAddress(device, pInfo); -''', -'vkGetBufferDeviceAddressEXT': ''' - return GetBufferDeviceAddress(device, pInfo); -''', -'vkGetDescriptorSetLayoutSizeEXT': ''' - // Need to give something non-zero - *pLayoutSizeInBytes = 4; -''', -'vkGetAccelerationStructureBuildSizesKHR': ''' - // arbitrary - pSizeInfo->accelerationStructureSize = 4; - pSizeInfo->updateScratchSize = 4; - pSizeInfo->buildScratchSize = 4; -''', -'vkGetAccelerationStructureMemoryRequirementsNV': ''' - // arbitrary - pMemoryRequirements->memoryRequirements.size = 4096; - pMemoryRequirements->memoryRequirements.alignment = 1; - pMemoryRequirements->memoryRequirements.memoryTypeBits = 0xFFFF; -''', -'vkGetAccelerationStructureDeviceAddressKHR': ''' - // arbitrary - need to be aligned to 256 bytes - return 0x262144; -''', -'vkGetVideoSessionMemoryRequirementsKHR': ''' - if (!pMemoryRequirements) { - *pMemoryRequirementsCount = 1; - } else { - // arbitrary - pMemoryRequirements[0].memoryBindIndex = 0; - pMemoryRequirements[0].memoryRequirements.size = 4096; - pMemoryRequirements[0].memoryRequirements.alignment = 1; - pMemoryRequirements[0].memoryRequirements.memoryTypeBits = 0xFFFF; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR': ''' - if (!pProperties) { - *pPropertyCount = 2; - } else { - // arbitrary - pProperties[0].MSize = 16; - pProperties[0].NSize = 16; - pProperties[0].KSize = 16; - pProperties[0].AType = VK_COMPONENT_TYPE_UINT32_KHR; - pProperties[0].BType = VK_COMPONENT_TYPE_UINT32_KHR; - pProperties[0].CType = VK_COMPONENT_TYPE_UINT32_KHR; - pProperties[0].ResultType = VK_COMPONENT_TYPE_UINT32_KHR; - pProperties[0].saturatingAccumulation = VK_FALSE; - pProperties[0].scope = VK_SCOPE_SUBGROUP_KHR; - - pProperties[1] = pProperties[0]; - pProperties[1].scope = VK_SCOPE_DEVICE_KHR; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceVideoCapabilitiesKHR': ''' - return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR; -''', -'vkGetPhysicalDeviceVideoFormatPropertiesKHR': ''' - return VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR; -''', -'vkGetDescriptorSetLayoutSupport':''' - if (pSupport) { - pSupport->supported = VK_TRUE; - } -''', -'vkGetDescriptorSetLayoutSupportKHR':''' - GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport); -''', -'vkGetRenderAreaGranularity': ''' - pGranularity->width = 1; - pGranularity->height = 1; -''', -'vkGetMemoryFdKHR': ''' - *pFd = 1; - return VK_SUCCESS; -''', -'vkGetMemoryHostPointerPropertiesEXT': ''' - pMemoryHostPointerProperties->memoryTypeBits = 1 << 5; // DEVICE_LOCAL only type - return VK_SUCCESS; -''', -'vkGetAndroidHardwareBufferPropertiesANDROID': ''' - pProperties->allocationSize = 65536; - pProperties->memoryTypeBits = 1 << 5; // DEVICE_LOCAL only type - - auto *format_prop = lvl_find_mod_in_chain(pProperties->pNext); - if (format_prop) { - // Likley using this format - format_prop->format = VK_FORMAT_R8G8B8A8_UNORM; - format_prop->externalFormat = 37; - } - - auto *format_resolve_prop = lvl_find_mod_in_chain(pProperties->pNext); - if (format_resolve_prop) { - format_resolve_prop->colorAttachmentFormat = VK_FORMAT_R8G8B8A8_UNORM; - } - return VK_SUCCESS; -''', -'vkGetPhysicalDeviceDisplayPropertiesKHR': ''' - if (!pProperties) { - *pPropertyCount = 1; - } else { - unique_lock_t lock(global_lock); - pProperties[0].display = (VkDisplayKHR)global_unique_handle++; - display_map[physicalDevice].insert(pProperties[0].display); - } - return VK_SUCCESS; -''', -'vkRegisterDisplayEventEXT': ''' - unique_lock_t lock(global_lock); - *pFence = (VkFence)global_unique_handle++; - return VK_SUCCESS; -''', -'vkQueueSubmit': ''' - // Special way to cause DEVICE_LOST - // Picked VkExportFenceCreateInfo because needed some struct that wouldn't get cleared by validation Safe Struct - // ... TODO - It would be MUCH nicer to have a layer or other setting control when this occured - // For now this is used to allow Validation Layers test reacting to device losts - if (submitCount > 0 && pSubmits) { - auto pNext = reinterpret_cast(pSubmits[0].pNext); - if (pNext && pNext->sType == VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO && pNext->pNext == nullptr) { - return VK_ERROR_DEVICE_LOST; - } - } - return VK_SUCCESS; -''', -'vkGetMemoryWin32HandlePropertiesKHR': ''' - pMemoryWin32HandleProperties->memoryTypeBits = 0xFFFF; - return VK_SUCCESS; -''', -'vkCreatePipelineBinariesKHR': ''' - unique_lock_t lock(global_lock); - for (uint32_t i = 0; i < pBinaries->pipelineBinaryCount; ++i) { - pBinaries->pPipelineBinaries[i] = (VkPipelineBinaryKHR)global_unique_handle++; - } - return VK_SUCCESS; -''' -} - -# MockICDGeneratorOptions - subclass of GeneratorOptions. -# -# Adds options used by MockICDOutputGenerator objects during Mock -# ICD generation. -# -# Additional members -# prefixText - list of strings to prefix generated header with -# (usually a copyright statement + calling convention macros). -# protectFile - True if multiple inclusion protection should be -# generated (based on the filename) around the entire header. -# protectFeature - True if #ifndef..#endif protection should be -# generated around a feature interface in the header file. -# genFuncPointers - True if function pointer typedefs should be -# generated -# protectProto - If conditional protection should be generated -# around prototype declarations, set to either '#ifdef' -# to require opt-in (#ifdef protectProtoStr) or '#ifndef' -# to require opt-out (#ifndef protectProtoStr). Otherwise -# set to None. -# protectProtoStr - #ifdef/#ifndef symbol to use around prototype -# declarations, if protectProto is set -# apicall - string to use for the function declaration prefix, -# such as APICALL on Windows. -# apientry - string to use for the calling convention macro, -# in typedefs, such as APIENTRY. -# apientryp - string to use for the calling convention macro -# in function pointer typedefs, such as APIENTRYP. -# indentFuncProto - True if prototype declarations should put each -# parameter on a separate line -# indentFuncPointer - True if typedefed function pointers should put each -# parameter on a separate line -# alignFuncParam - if nonzero and parameters are being put on a -# separate line, align parameter names at the specified column -class MockICDGeneratorOptions(GeneratorOptions): - def __init__(self, - conventions = None, - filename = None, - directory = '.', - genpath = None, - apiname = None, - profile = None, - versions = '.*', - emitversions = '.*', - defaultExtensions = None, - addExtensions = None, - removeExtensions = None, - emitExtensions = None, - sortProcedure = regSortFeatures, - prefixText = "", - genFuncPointers = True, - protectFile = True, - protectFeature = True, - protectProto = None, - protectProtoStr = None, - apicall = '', - apientry = '', - apientryp = '', - indentFuncProto = True, - indentFuncPointer = False, - alignFuncParam = 0, - expandEnumerants = True, - helper_file_type = ''): - GeneratorOptions.__init__(self, - conventions = conventions, - filename = filename, - directory = directory, - genpath = genpath, - apiname = apiname, - profile = profile, - versions = versions, - emitversions = emitversions, - defaultExtensions = defaultExtensions, - addExtensions = addExtensions, - removeExtensions = removeExtensions, - emitExtensions = emitExtensions, - sortProcedure = sortProcedure) - self.prefixText = prefixText - self.genFuncPointers = genFuncPointers - self.protectFile = protectFile - self.protectFeature = protectFeature - self.protectProto = protectProto - self.protectProtoStr = protectProtoStr - self.apicall = apicall - self.apientry = apientry - self.apientryp = apientryp - self.indentFuncProto = indentFuncProto - self.indentFuncPointer = indentFuncPointer - self.alignFuncParam = alignFuncParam - -# MockICDOutputGenerator - subclass of OutputGenerator. -# Generates a mock vulkan ICD. -# This is intended to be a minimal replacement for a vulkan device in order -# to enable Vulkan Validation testing. -# -# ---- methods ---- -# MockOutputGenerator(errFile, warnFile, diagFile) - args as for -# OutputGenerator. Defines additional internal state. -# ---- methods overriding base class ---- -# beginFile(genOpts) -# endFile() -# beginFeature(interface, emit) -# endFeature() -# genType(typeinfo,name) -# genStruct(typeinfo,name) -# genGroup(groupinfo,name) -# genEnum(enuminfo, name) -# genCmd(cmdinfo) -class MockICDOutputGenerator(OutputGenerator): - """Generate specified API interfaces in a specific style, such as a C header""" - # This is an ordered list of sections in the header file. - TYPE_SECTIONS = ['include', 'define', 'basetype', 'handle', 'enum', - 'group', 'bitmask', 'funcpointer', 'struct'] - ALL_SECTIONS = TYPE_SECTIONS + ['command'] - def __init__(self, - errFile = sys.stderr, - warnFile = sys.stderr, - diagFile = sys.stdout): - OutputGenerator.__init__(self, errFile, warnFile, diagFile) - # Internal state - accumulators for different inner block text - self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) - self.intercepts = [] - self.function_declarations = False - - # Check if the parameter passed in is a pointer to an array - def paramIsArray(self, param): - return param.attrib.get('len') is not None - - # Check if the parameter passed in is a pointer - def paramIsPointer(self, param): - ispointer = False - for elem in param: - if ((elem.tag != 'type') and (elem.tail is not None)) and '*' in elem.tail: - ispointer = True - return ispointer - - # Check if an object is a non-dispatchable handle - def isHandleTypeNonDispatchable(self, handletype): - handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") - if handle is not None and handle.find('type').text == 'VK_DEFINE_NON_DISPATCHABLE_HANDLE': - return True - else: - return False - - # Check if an object is a dispatchable handle - def isHandleTypeDispatchable(self, handletype): - handle = self.registry.tree.find("types/type/[name='" + handletype + "'][@category='handle']") - if handle is not None and handle.find('type').text == 'VK_DEFINE_HANDLE': - return True - else: - return False - - # Check that the target API is in the supported list for the extension - def checkExtensionAPISupport(self, supported): - return self.genOpts.apiname in supported.split(',') - - def beginFile(self, genOpts): - OutputGenerator.beginFile(self, genOpts) - # C-specific - # - # Multiple inclusion protection & C++ namespace. - if (genOpts.protectFile and self.genOpts.filename == "function_declarations.h"): - self.function_declarations = True - - # User-supplied prefix text, if any (list of strings) - if (genOpts.prefixText): - for s in genOpts.prefixText: - write(s, file=self.outFile) - - if self.function_declarations: - self.newline() - # Include all of the extensions in ICD except specific ignored ones - device_exts = [] - instance_exts = [] - # Ignore extensions that ICDs should not implement or are not safe to report - ignore_exts = ['VK_EXT_validation_cache', 'VK_KHR_portability_subset'] - for ext in self.registry.tree.findall("extensions/extension"): - if self.checkExtensionAPISupport(ext.attrib['supported']): # Only include API-relevant extensions - if (ext.attrib['name'] not in ignore_exts): - # Search for extension version enum - for enum in ext.findall('require/enum'): - if enum.get('name', '').endswith('_SPEC_VERSION'): - ext_version = enum.get('value') - if (ext.attrib.get('type') == 'instance'): - instance_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext_version)) - else: - device_exts.append(' {"%s", %s},' % (ext.attrib['name'], ext_version)) - break - write('#pragma once\n',file=self.outFile) - write('#include ',file=self.outFile) - write('#include ',file=self.outFile) - write('#include ',file=self.outFile) - write('#include ',file=self.outFile) - write('#include ',file=self.outFile) - self.newline() - write('namespace vkmock {\n', file=self.outFile) - write('// Map of instance extension name to version', file=self.outFile) - write('static const std::unordered_map instance_extension_map = {', file=self.outFile) - write('\n'.join(instance_exts), file=self.outFile) - write('};', file=self.outFile) - write('// Map of device extension name to version', file=self.outFile) - write('static const std::unordered_map device_extension_map = {', file=self.outFile) - write('\n'.join(device_exts), file=self.outFile) - write('};', file=self.outFile) - else: - write('#pragma once\n',file=self.outFile) - write('#include "mock_icd.h"',file=self.outFile) - write('#include "function_declarations.h"\n',file=self.outFile) - write('namespace vkmock {', file=self.outFile) - - - def endFile(self): - # C-specific - # Finish C++ namespace - self.newline() - if self.function_declarations: - # record intercepted procedures - write('// Map of all APIs to be intercepted by this layer', file=self.outFile) - write('static const std::unordered_map name_to_funcptr_map = {', file=self.outFile) - write('\n'.join(self.intercepts), file=self.outFile) - write('};\n', file=self.outFile) - write('} // namespace vkmock', file=self.outFile) - self.newline() - - # Finish processing in superclass - OutputGenerator.endFile(self) - def beginFeature(self, interface, emit): - #write('// starting beginFeature', file=self.outFile) - # Start processing in superclass - OutputGenerator.beginFeature(self, interface, emit) - self.featureExtraProtect = GetFeatureProtect(interface) - # C-specific - # Accumulate includes, defines, types, enums, function pointer typedefs, - # end function prototypes separately for this feature. They're only - # printed in endFeature(). - self.sections = dict([(section, []) for section in self.ALL_SECTIONS]) - #write('// ending beginFeature', file=self.outFile) - def endFeature(self): - # C-specific - # Actually write the interface to the output file. - #write('// starting endFeature', file=self.outFile) - if (self.emit): - self.newline() - if (self.genOpts.protectFeature): - write('#ifndef', self.featureName, file=self.outFile) - # If type declarations are needed by other features based on - # this one, it may be necessary to suppress the ExtraProtect, - # or move it below the 'for section...' loop. - #write('// endFeature looking at self.featureExtraProtect', file=self.outFile) - if (self.featureExtraProtect != None): - write('#ifdef', self.featureExtraProtect, file=self.outFile) - #write('#define', self.featureName, '1', file=self.outFile) - for section in self.TYPE_SECTIONS: - #write('// endFeature writing section'+section, file=self.outFile) - contents = self.sections[section] - if contents: - write('\n'.join(contents), file=self.outFile) - self.newline() - #write('// endFeature looking at self.sections[command]', file=self.outFile) - if (self.sections['command']): - write('\n'.join(self.sections['command']), end=u'', file=self.outFile) - self.newline() - if (self.featureExtraProtect != None): - write('#endif /*', self.featureExtraProtect, '*/', file=self.outFile) - if (self.genOpts.protectFeature): - write('#endif /*', self.featureName, '*/', file=self.outFile) - # Finish processing in superclass - OutputGenerator.endFeature(self) - #write('// ending endFeature', file=self.outFile) - # - # Append a definition to the specified section - def appendSection(self, section, text): - # self.sections[section].append('SECTION: ' + section + '\n') - self.sections[section].append(text) - # - # Type generation - def genType(self, typeinfo, name, alias): - pass - # - # Struct (e.g. C "struct" type) generation. - # This is a special case of the tag where the contents are - # interpreted as a set of tags instead of freeform C - # C type declarations. The tags are just like - # tags - they are a declaration of a struct or union member. - # Only simple member declarations are supported (no nested - # structs etc.) - def genStruct(self, typeinfo, typeName, alias): - OutputGenerator.genStruct(self, typeinfo, typeName, alias) - body = 'typedef ' + typeinfo.elem.get('category') + ' ' + typeName + ' {\n' - # paramdecl = self.makeCParamDecl(typeinfo.elem, self.genOpts.alignFuncParam) - for member in typeinfo.elem.findall('.//member'): - body += self.makeCParamDecl(member, self.genOpts.alignFuncParam) - body += ';\n' - body += '} ' + typeName + ';\n' - self.appendSection('struct', body) - # - # Group (e.g. C "enum" type) generation. - # These are concatenated together with other types. - def genGroup(self, groupinfo, groupName, alias): - pass - # Enumerant generation - # tags may specify their values in several ways, but are usually - # just integers. - def genEnum(self, enuminfo, name, alias): - pass - # - # Command generation - def genCmd(self, cmdinfo, name, alias): - decls = self.makeCDecls(cmdinfo.elem) - if self.function_declarations: # In the header declare all intercepts - self.appendSection('command', '') - self.appendSection('command', 'static %s' % (decls[0])) - if (self.featureExtraProtect != None): - self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] - self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] - if (self.featureExtraProtect != None): - self.intercepts += [ '#endif' ] - return - - manual_functions = [ - # Include functions here to be intercepted w/ manually implemented function bodies - 'vkGetDeviceProcAddr', - 'vkGetInstanceProcAddr', - 'vkCreateDevice', - 'vkDestroyDevice', - 'vkCreateInstance', - 'vkDestroyInstance', - 'vkFreeCommandBuffers', - 'vkAllocateCommandBuffers', - 'vkDestroyCommandPool', - #'vkCreateDebugReportCallbackEXT', - #'vkDestroyDebugReportCallbackEXT', - 'vkEnumerateInstanceLayerProperties', - 'vkEnumerateInstanceVersion', - 'vkEnumerateInstanceExtensionProperties', - 'vkEnumerateDeviceLayerProperties', - 'vkEnumerateDeviceExtensionProperties', - ] - if name in manual_functions: - self.appendSection('command', '') - if name not in CUSTOM_C_INTERCEPTS: - self.appendSection('command', '// declare only') - self.appendSection('command', 'static %s' % (decls[0])) - self.appendSection('command', '// TODO: Implement custom intercept body') - else: - self.appendSection('command', 'static %s' % (decls[0][:-1])) - self.appendSection('command', '{\n%s}' % (CUSTOM_C_INTERCEPTS[name])) - self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] - return - # record that the function will be intercepted - if (self.featureExtraProtect != None): - self.intercepts += [ '#ifdef %s' % self.featureExtraProtect ] - self.intercepts += [ ' {"%s", (void*)%s},' % (name,name[2:]) ] - if (self.featureExtraProtect != None): - self.intercepts += [ '#endif' ] - - OutputGenerator.genCmd(self, cmdinfo, name, alias) - # - self.appendSection('command', '') - self.appendSection('command', 'static %s' % (decls[0][:-1])) - if name in CUSTOM_C_INTERCEPTS: - self.appendSection('command', '{%s}' % (CUSTOM_C_INTERCEPTS[name])) - return - - # Declare result variable, if any. - resulttype = cmdinfo.elem.find('proto/type') - if (resulttype != None and resulttype.text == 'void'): - resulttype = None - # if the name w/ KHR postfix is in the CUSTOM_C_INTERCEPTS - # Call the KHR custom version instead of generating separate code - khr_name = name + "KHR" - if khr_name in CUSTOM_C_INTERCEPTS: - return_string = '' - if resulttype != None: - return_string = 'return ' - params = cmdinfo.elem.findall('param/name') - param_names = [] - for param in params: - param_names.append(param.text) - self.appendSection('command', '{\n %s%s(%s);\n}' % (return_string, khr_name[2:], ", ".join(param_names))) - return - self.appendSection('command', '{') - - api_function_name = cmdinfo.elem.attrib.get('name') - # GET THE TYPE OF FUNCTION - if any(api_function_name.startswith(ftxt) for ftxt in ('vkCreate', 'vkAllocate')): - # Get last param - last_param = cmdinfo.elem.findall('param')[-1] - lp_txt = last_param.find('name').text - lp_len = None - if ('len' in last_param.attrib): - lp_len = last_param.attrib['len'] - lp_len = lp_len.replace('::', '->') - lp_type = last_param.find('type').text - handle_type = 'dispatchable' - allocator_txt = 'CreateDispObjHandle()'; - if (self.isHandleTypeNonDispatchable(lp_type)): - handle_type = 'non-' + handle_type - allocator_txt = 'global_unique_handle++'; - # Need to lock in both cases - self.appendSection('command', ' unique_lock_t lock(global_lock);') - if (lp_len != None): - #print("%s last params (%s) has len %s" % (handle_type, lp_txt, lp_len)) - self.appendSection('command', ' for (uint32_t i = 0; i < %s; ++i) {' % (lp_len)) - self.appendSection('command', ' %s[i] = (%s)%s;' % (lp_txt, lp_type, allocator_txt)) - self.appendSection('command', ' }') - else: - #print("Single %s last param is '%s' w/ type '%s'" % (handle_type, lp_txt, lp_type)) - if 'AllocateMemory' in api_function_name: - # Store allocation size in case it's mapped - self.appendSection('command', ' allocated_memory_size_map[(VkDeviceMemory)global_unique_handle] = pAllocateInfo->allocationSize;') - self.appendSection('command', ' *%s = (%s)%s;' % (lp_txt, lp_type, allocator_txt)) - elif True in [ftxt in api_function_name for ftxt in ['Destroy', 'Free']]: - self.appendSection('command', '//Destroy object') - if 'FreeMemory' in api_function_name: - # If the memory is mapped, unmap it - self.appendSection('command', ' UnmapMemory(device, memory);') - # Remove from allocation map - self.appendSection('command', ' unique_lock_t lock(global_lock);') - self.appendSection('command', ' allocated_memory_size_map.erase(memory);') - else: - self.appendSection('command', '//Not a CREATE or DESTROY function') - - # Return result variable, if any. - if (resulttype != None): - if api_function_name == 'vkGetEventStatus': - self.appendSection('command', ' return VK_EVENT_SET;') - else: - self.appendSection('command', ' return VK_SUCCESS;') - self.appendSection('command', '}') - # - # override makeProtoName to drop the "vk" prefix - def makeProtoName(self, name, tail): - return self.genOpts.apientry + name[2:] + tail diff --git a/scripts/vulkan_tools_helper_file_generator.py b/scripts/vulkan_tools_helper_file_generator.py deleted file mode 100644 index b0e486ef..00000000 --- a/scripts/vulkan_tools_helper_file_generator.py +++ /dev/null @@ -1,1240 +0,0 @@ -#!/usr/bin/python3 -i -# -# Copyright (c) 2015-2021 The Khronos Group Inc. -# Copyright (c) 2015-2021 Valve Corporation -# Copyright (c) 2015-2021 LunarG, Inc. -# Copyright (c) 2015-2021 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Mark Lobodzinski -# Author: Tobin Ehlis -# Author: John Zulauf - -import os,re,sys -import xml.etree.ElementTree as etree -from generator import * -from collections import namedtuple -from common_codegen import * - -# -# HelperFileOutputGeneratorOptions - subclass of GeneratorOptions. -class HelperFileOutputGeneratorOptions(GeneratorOptions): - def __init__(self, - conventions = None, - filename = None, - directory = '.', - genpath = None, - apiname = None, - profile = None, - versions = '.*', - emitversions = '.*', - defaultExtensions = None, - addExtensions = None, - removeExtensions = None, - emitExtensions = None, - sortProcedure = regSortFeatures, - prefixText = "", - genFuncPointers = True, - protectFile = True, - protectFeature = True, - apicall = '', - apientry = '', - apientryp = '', - alignFuncParam = 0, - library_name = '', - expandEnumerants = True, - helper_file_type = ''): - GeneratorOptions.__init__(self, - conventions = conventions, - filename = filename, - directory = directory, - genpath = genpath, - apiname = apiname, - profile = profile, - versions = versions, - emitversions = emitversions, - defaultExtensions = defaultExtensions, - addExtensions = addExtensions, - removeExtensions = removeExtensions, - emitExtensions = emitExtensions, - sortProcedure = sortProcedure) - self.prefixText = prefixText - self.genFuncPointers = genFuncPointers - self.protectFile = protectFile - self.protectFeature = protectFeature - self.apicall = apicall - self.apientry = apientry - self.apientryp = apientryp - self.alignFuncParam = alignFuncParam - self.library_name = library_name - self.helper_file_type = helper_file_type -# -# HelperFileOutputGenerator - subclass of OutputGenerator. Outputs Vulkan helper files -class HelperFileOutputGenerator(OutputGenerator): - """Generate helper file based on XML element attributes""" - def __init__(self, - errFile = sys.stderr, - warnFile = sys.stderr, - diagFile = sys.stdout): - OutputGenerator.__init__(self, errFile, warnFile, diagFile) - # Internal state - accumulators for different inner block text - self.enum_output = '' # string built up of enum string routines - # Internal state - accumulators for different inner block text - self.structNames = [] # List of Vulkan struct typenames - self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType - self.structMembers = [] # List of StructMemberData records for all Vulkan structs - self.object_types = [] # List of all handle types - self.object_type_aliases = [] # Aliases to handles types (for handles that were extensions) - self.debug_report_object_types = [] # Handy copy of debug_report_object_type enum data - self.core_object_types = [] # Handy copy of core_object_type enum data - self.device_extension_info = dict() # Dict of device extension name defines and ifdef values - self.instance_extension_info = dict() # Dict of instance extension name defines and ifdef values - - # Named tuples to store struct and command data - self.StructType = namedtuple('StructType', ['name', 'value']) - self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isconst', 'iscount', 'len', 'extstructs', 'cdecl']) - self.StructMemberData = namedtuple('StructMemberData', ['name', 'members', 'ifdef_protect']) - - self.custom_construct_params = { - # safe_VkGraphicsPipelineCreateInfo needs to know if subpass has color and\or depth\stencil attachments to use its pointers - 'VkGraphicsPipelineCreateInfo' : - ', const bool uses_color_attachment, const bool uses_depthstencil_attachment', - # safe_VkPipelineViewportStateCreateInfo needs to know if viewport and scissor is dynamic to use its pointers - 'VkPipelineViewportStateCreateInfo' : - ', const bool is_dynamic_viewports, const bool is_dynamic_scissors', - } - # - # Called once at the beginning of each run - def beginFile(self, genOpts): - OutputGenerator.beginFile(self, genOpts) - # User-supplied prefix text, if any (list of strings) - self.helper_file_type = genOpts.helper_file_type - self.library_name = genOpts.library_name - # File Comment - file_comment = '// *** THIS FILE IS GENERATED - DO NOT EDIT ***\n' - file_comment += '// See vulkan_tools_helper_file_generator.py for modifications\n' - write(file_comment, file=self.outFile) - # Copyright Notice - copyright = '' - copyright += '\n' - copyright += '/***************************************************************************\n' - copyright += ' *\n' - copyright += ' * Copyright (c) 2015-2017 The Khronos Group Inc.\n' - copyright += ' * Copyright (c) 2015-2017 Valve Corporation\n' - copyright += ' * Copyright (c) 2015-2017 LunarG, Inc.\n' - copyright += ' * Copyright (c) 2015-2017 Google Inc.\n' - copyright += ' *\n' - copyright += ' * Licensed under the Apache License, Version 2.0 (the "License");\n' - copyright += ' * you may not use this file except in compliance with the License.\n' - copyright += ' * You may obtain a copy of the License at\n' - copyright += ' *\n' - copyright += ' * http://www.apache.org/licenses/LICENSE-2.0\n' - copyright += ' *\n' - copyright += ' * Unless required by applicable law or agreed to in writing, software\n' - copyright += ' * distributed under the License is distributed on an "AS IS" BASIS,\n' - copyright += ' * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' - copyright += ' * See the License for the specific language governing permissions and\n' - copyright += ' * limitations under the License.\n' - copyright += ' *\n' - copyright += ' * Author: Mark Lobodzinski \n' - copyright += ' * Author: Courtney Goeltzenleuchter \n' - copyright += ' * Author: Tobin Ehlis \n' - copyright += ' * Author: Chris Forbes \n' - copyright += ' * Author: John Zulauf\n' - copyright += ' *\n' - copyright += ' ****************************************************************************/\n' - write(copyright, file=self.outFile) - # - # Write generated file content to output file - def endFile(self): - dest_file = '' - dest_file += self.OutputDestFile() - # Remove blank lines at EOF - if dest_file.endswith('\n'): - dest_file = dest_file[:-1] - write(dest_file, file=self.outFile); - # Finish processing in superclass - OutputGenerator.endFile(self) - # - # Override parent class to be notified of the beginning of an extension - def beginFeature(self, interface, emit): - # Start processing in superclass - OutputGenerator.beginFeature(self, interface, emit) - self.featureExtraProtect = GetFeatureProtect(interface) - - if interface.tag != 'extension': - return - name = self.featureName - for enum in interface.findall('require/enum'): - if enum.get('name', '').endswith('EXTENSION_NAME'): - name_define = enum.get('name') - break - requires = interface.get('requires') - if requires is not None: - required_extensions = requires.split(',') - else: - required_extensions = list() - info = { 'define': name_define, 'ifdef':self.featureExtraProtect, 'reqs':required_extensions } - if interface.get('type') == 'instance': - self.instance_extension_info[name] = info - else: - self.device_extension_info[name] = info - - # - # Override parent class to be notified of the end of an extension - def endFeature(self): - # Finish processing in superclass - OutputGenerator.endFeature(self) - # - # Grab group (e.g. C "enum" type) info to output for enum-string conversion helper - def genGroup(self, groupinfo, groupName, alias): - OutputGenerator.genGroup(self, groupinfo, groupName, alias) - groupElem = groupinfo.elem - # For enum_string_header - if self.helper_file_type == 'enum_string_header': - value_set = set() - for elem in groupElem.findall('enum'): - if elem.get('supported') != 'disabled' and elem.get('alias') == None: - value_set.add(elem.get('name')) - self.enum_output += self.GenerateEnumStringConversion(groupName, value_set) - elif self.helper_file_type == 'object_types_header': - if groupName == 'VkDebugReportObjectTypeEXT': - for elem in groupElem.findall('enum'): - if elem.get('supported') != 'disabled': - item_name = elem.get('name') - self.debug_report_object_types.append(item_name) - elif groupName == 'VkObjectType': - for elem in groupElem.findall('enum'): - if elem.get('supported') != 'disabled': - item_name = elem.get('name') - self.core_object_types.append(item_name) - - # - # Called for each type -- if the type is a struct/union, grab the metadata - def genType(self, typeinfo, name, alias): - OutputGenerator.genType(self, typeinfo, name, alias) - typeElem = typeinfo.elem - # If the type is a struct type, traverse the imbedded tags generating a structure. - # Otherwise, emit the tag text. - category = typeElem.get('category') - if category == 'handle': - if alias: - self.object_type_aliases.append((name,alias)) - else: - self.object_types.append(name) - elif (category == 'struct' or category == 'union'): - self.structNames.append(name) - self.genStruct(typeinfo, name, alias) - # - # Check if the parameter passed in is a pointer - def paramIsPointer(self, param): - ispointer = False - for elem in param: - if ((elem.tag != 'type') and (elem.tail is not None)) and '*' in elem.tail: - ispointer = True - return ispointer - # - # Check if the parameter passed in is a static array - def paramIsStaticArray(self, param): - isstaticarray = 0 - paramname = param.find('name') - if (paramname.tail is not None) and ('[' in paramname.tail): - isstaticarray = paramname.tail.count('[') - return isstaticarray - # - # Retrieve the type and name for a parameter - def getTypeNameTuple(self, param): - type = '' - name = '' - for elem in param: - if elem.tag == 'type': - type = noneStr(elem.text) - elif elem.tag == 'name': - name = noneStr(elem.text) - return (type, name) - # - # Retrieve the value of the len tag - def getLen(self, param): - result = None - len = param.attrib.get('len') - if len and len != 'null-terminated': - # For string arrays, 'len' can look like 'count,null-terminated', indicating that we - # have a null terminated array of strings. We strip the null-terminated from the - # 'len' field and only return the parameter specifying the string count - if 'null-terminated' in len: - result = len.split(',')[0] - else: - result = len - if 'altlen' in param.attrib: - # Elements with latexmath 'len' also contain a C equivalent 'altlen' attribute - # Use indexing operator instead of get() so we fail if the attribute is missing - result = param.attrib['altlen'] - # Spec has now notation for len attributes, using :: instead of platform specific pointer symbol - result = str(result).replace('::', '->') - return result - # - # Check if a structure is or contains a dispatchable (dispatchable = True) or - # non-dispatchable (dispatchable = False) handle - def TypeContainsObjectHandle(self, handle_type, dispatchable): - if dispatchable: - type_key = 'VK_DEFINE_HANDLE' - else: - type_key = 'VK_DEFINE_NON_DISPATCHABLE_HANDLE' - handle = self.registry.tree.find("types/type/[name='" + handle_type + "'][@category='handle']") - if handle is not None and handle.find('type').text == type_key: - return True - # if handle_type is a struct, search its members - if handle_type in self.structNames: - member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == handle_type), None) - if member_index is not None: - for item in self.structMembers[member_index].members: - handle = self.registry.tree.find("types/type/[name='" + item.type + "'][@category='handle']") - if handle is not None and handle.find('type').text == type_key: - return True - return False - # - # Generate local ready-access data describing Vulkan structures and unions from the XML metadata - def genStruct(self, typeinfo, typeName, alias): - OutputGenerator.genStruct(self, typeinfo, typeName, alias) - members = typeinfo.elem.findall('.//member') - # Iterate over members once to get length parameters for arrays - lens = set() - for member in members: - len = self.getLen(member) - if len: - lens.add(len) - # Generate member info - membersInfo = [] - for member in members: - # Get the member's type and name - info = self.getTypeNameTuple(member) - type = info[0] - name = info[1] - cdecl = self.makeCParamDecl(member, 1) - # Process VkStructureType - if type == 'VkStructureType': - # Extract the required struct type value from the comments - # embedded in the original text defining the 'typeinfo' element - rawXml = etree.tostring(typeinfo.elem).decode('ascii') - result = re.search(r'VK_STRUCTURE_TYPE_\w+', rawXml) - if result: - value = result.group(0) - # Store the required type value - self.structTypes[typeName] = self.StructType(name=name, value=value) - # Store pointer/array/string info - isstaticarray = self.paramIsStaticArray(member) - membersInfo.append(self.CommandParam(type=type, - name=name, - ispointer=self.paramIsPointer(member), - isstaticarray=isstaticarray, - isconst=True if 'const' in cdecl else False, - iscount=True if name in lens else False, - len=self.getLen(member), - extstructs=self.registry.validextensionstructs[typeName] if name == 'pNext' else None, - cdecl=cdecl)) - self.structMembers.append(self.StructMemberData(name=typeName, members=membersInfo, ifdef_protect=self.featureExtraProtect)) - # - # Enum_string_header: Create a routine to convert an enumerated value into a string - def GenerateEnumStringConversion(self, groupName, value_list): - outstring = '\n' - outstring += 'static inline const char* string_%s(%s input_value)\n' % (groupName, groupName) - outstring += '{\n' - outstring += ' switch ((%s)input_value)\n' % groupName - outstring += ' {\n' - for item in value_list: - outstring += ' case %s:\n' % item - outstring += ' return "%s";\n' % item - outstring += ' default:\n' - outstring += ' return "Unhandled %s";\n' % groupName - outstring += ' }\n' - outstring += '}\n' - return outstring - # - # Tack on a helper which, given an index into a VkPhysicalDeviceFeatures structure, will print the corresponding feature name - def DeIndexPhysDevFeatures(self): - pdev_members = None - for name, members, ifdef in self.structMembers: - if name == 'VkPhysicalDeviceFeatures': - pdev_members = members - break - deindex = '\n' - deindex += 'static inline const char * GetPhysDevFeatureString(uint32_t index) {\n' - deindex += ' const char * IndexToPhysDevFeatureString[] = {\n' - for feature in pdev_members: - deindex += ' "%s",\n' % feature.name - deindex += ' };\n\n' - deindex += ' return IndexToPhysDevFeatureString[index];\n' - deindex += '}\n' - return deindex - # - # Combine enum string helper header file preamble with body text and return - def GenerateEnumStringHelperHeader(self): - enum_string_helper_header = '\n' - enum_string_helper_header += '#pragma once\n' - enum_string_helper_header += '#ifdef _WIN32\n' - enum_string_helper_header += '#pragma warning( disable : 4065 )\n' - enum_string_helper_header += '#endif\n' - enum_string_helper_header += '\n' - enum_string_helper_header += '#include \n' - enum_string_helper_header += '\n' - enum_string_helper_header += self.enum_output - enum_string_helper_header += self.DeIndexPhysDevFeatures() - return enum_string_helper_header - # - # Helper function for declaring a counter variable only once - def DeclareCounter(self, string_var, declare_flag): - if declare_flag == False: - string_var += ' uint32_t i = 0;\n' - declare_flag = True - return string_var, declare_flag - # - # Combine safe struct helper header file preamble with body text and return - def GenerateSafeStructHelperHeader(self): - safe_struct_helper_header = '\n' - safe_struct_helper_header += '#pragma once\n' - safe_struct_helper_header += '#include \n' - safe_struct_helper_header += '\n' - safe_struct_helper_header += self.GenerateSafeStructHeader() - return safe_struct_helper_header - # - # safe_struct header: build function prototypes for header file - def GenerateSafeStructHeader(self): - safe_struct_header = '' - for item in self.structMembers: - if self.NeedSafeStruct(item) == True: - safe_struct_header += '\n' - if item.ifdef_protect != None: - safe_struct_header += '#ifdef %s\n' % item.ifdef_protect - safe_struct_header += 'struct safe_%s {\n' % (item.name) - for member in item.members: - if member.type in self.structNames: - member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) - if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: - if member.ispointer: - safe_struct_header += ' safe_%s* %s;\n' % (member.type, member.name) - else: - safe_struct_header += ' safe_%s %s;\n' % (member.type, member.name) - continue - if member.len is not None and (self.TypeContainsObjectHandle(member.type, True) or self.TypeContainsObjectHandle(member.type, False)): - safe_struct_header += ' %s* %s;\n' % (member.type, member.name) - else: - safe_struct_header += '%s;\n' % member.cdecl - safe_struct_header += ' safe_%s(const %s* in_struct%s);\n' % (item.name, item.name, self.custom_construct_params.get(item.name, '')) - safe_struct_header += ' safe_%s(const safe_%s& src);\n' % (item.name, item.name) - safe_struct_header += ' safe_%s& operator=(const safe_%s& src);\n' % (item.name, item.name) - safe_struct_header += ' safe_%s();\n' % item.name - safe_struct_header += ' ~safe_%s();\n' % item.name - safe_struct_header += ' void initialize(const %s* in_struct%s);\n' % (item.name, self.custom_construct_params.get(item.name, '')) - safe_struct_header += ' void initialize(const safe_%s* src);\n' % (item.name) - safe_struct_header += ' %s *ptr() { return reinterpret_cast<%s *>(this); }\n' % (item.name, item.name) - safe_struct_header += ' %s const *ptr() const { return reinterpret_cast<%s const *>(this); }\n' % (item.name, item.name) - safe_struct_header += '};\n' - if item.ifdef_protect != None: - safe_struct_header += '#endif // %s\n' % item.ifdef_protect - return safe_struct_header - # - # Generate extension helper header file - def GenerateExtensionHelperHeader(self): - - V_1_0_instance_extensions_promoted_to_core = [ - 'vk_khr_device_group_creation', - 'vk_khr_external_fence_capabilities', - 'vk_khr_external_memory_capabilities', - 'vk_khr_external_semaphore_capabilities', - 'vk_khr_get_physical_device_properties_2', - ] - - V_1_0_device_extensions_promoted_to_core = [ - 'vk_khr_16bit_storage', - 'vk_khr_bind_memory_2', - 'vk_khr_dedicated_allocation', - 'vk_khr_descriptor_update_template', - 'vk_khr_device_group', - 'vk_khr_external_fence', - 'vk_khr_external_memory', - 'vk_khr_external_semaphore', - 'vk_khr_get_memory_requirements_2', - 'vk_khr_maintenance1', - 'vk_khr_maintenance2', - 'vk_khr_maintenance3', - 'vk_khr_multiview', - 'vk_khr_relaxed_block_layout', - 'vk_khr_sampler_ycbcr_conversion', - 'vk_khr_shader_draw_parameters', - 'vk_khr_storage_buffer_storage_class', - 'vk_khr_variable_pointers', - ] - - output = [ - '', - '#ifndef VK_EXTENSION_HELPER_H_', - '#define VK_EXTENSION_HELPER_H_', - '#include ', - '#include ', - '#include ', - '', - '#include ', - ''] - - def guarded(ifdef, value): - if ifdef is not None: - return '\n'.join([ '#ifdef %s' % ifdef, value, '#endif' ]) - else: - return value - - for type in ['Instance', 'Device']: - struct_type = '%sExtensions' % type - if type == 'Instance': - extension_dict = self.instance_extension_info - promoted_ext_list = V_1_0_instance_extensions_promoted_to_core - struct_decl = 'struct %s {' % struct_type - instance_struct_type = struct_type - else: - extension_dict = self.device_extension_info - promoted_ext_list = V_1_0_device_extensions_promoted_to_core - struct_decl = 'struct %s : public %s {' % (struct_type, instance_struct_type) - - extension_items = sorted(extension_dict.items()) - - field_name = { ext_name: re.sub('_extension_name', '', info['define'].lower()) for ext_name, info in extension_items } - if type == 'Instance': - instance_field_name = field_name - instance_extension_dict = extension_dict - else: - # Get complete field name and extension data for both Instance and Device extensions - field_name.update(instance_field_name) - extension_dict = extension_dict.copy() # Don't modify the self. we're pointing to - extension_dict.update(instance_extension_dict) - - # Output the data member list - struct = [struct_decl] - struct.extend([ ' bool %s{false};' % field_name[ext_name] for ext_name, info in extension_items]) - - # Construct the extension information map -- mapping name to data member (field), and required extensions - # The map is contained within a static function member for portability reasons. - info_type = '%sInfo' % type - info_map_type = '%sMap' % info_type - req_type = '%sReq' % type - req_vec_type = '%sVec' % req_type - struct.extend([ - '', - ' struct %s {' % req_type, - ' const bool %s::* enabled;' % struct_type, - ' const char *name;', - ' };', - ' typedef std::vector<%s> %s;' % (req_type, req_vec_type), - ' struct %s {' % info_type, - ' %s(bool %s::* state_, const %s requires_): state(state_), requires(requires_) {}' % ( info_type, struct_type, req_vec_type), - ' bool %s::* state;' % struct_type, - ' %s requires;' % req_vec_type, - ' };', - '', - ' typedef std::unordered_map %s;' % (info_type, info_map_type), - ' static const %s &get_info(const char *name) {' %info_type, - ' static const %s info_map = {' % info_map_type ]) - - field_format = '&' + struct_type + '::%s' - req_format = '{' + field_format+ ', %s}' - req_indent = '\n ' - req_join = ',' + req_indent - info_format = (' std::make_pair(%s, ' + info_type + '(' + field_format + ', {%s})),') - def format_info(ext_name, info): - reqs = req_join.join([req_format % (field_name[req], extension_dict[req]['define']) for req in info['reqs']]) - return info_format % (info['define'], field_name[ext_name], '{%s}' % (req_indent + reqs) if reqs else '') - - struct.extend([guarded(info['ifdef'], format_info(ext_name, info)) for ext_name, info in extension_items]) - struct.extend([ - ' };', - '', - ' static const %s empty_info {nullptr, %s()};' % (info_type, req_vec_type), - ' %s::const_iterator info = info_map.find(name);' % info_map_type, - ' if ( info != info_map.cend()) {', - ' return info->second;', - ' }', - ' return empty_info;', - ' }', - '']) - - if type == 'Instance': - struct.extend([ - ' uint32_t NormalizeApiVersion(uint32_t specified_version) {', - ' uint32_t api_version = (specified_version < VK_API_VERSION_1_1) ? VK_API_VERSION_1_0 : VK_API_VERSION_1_1;', - ' return api_version;', - ' }', - '', - ' uint32_t InitFromInstanceCreateInfo(uint32_t requested_api_version, const VkInstanceCreateInfo *pCreateInfo) {']) - else: - struct.extend([ - ' %s() = default;' % struct_type, - ' %s(const %s& instance_ext) : %s(instance_ext) {}' % (struct_type, instance_struct_type, instance_struct_type), - '', - ' uint32_t InitFromDeviceCreateInfo(const %s *instance_extensions, uint32_t requested_api_version,' % instance_struct_type, - ' const VkDeviceCreateInfo *pCreateInfo) {', - ' // Initialize: this to defaults, base class fields to input.', - ' assert(instance_extensions);', - ' *this = %s(*instance_extensions);' % struct_type]) - - struct.extend([ - '', - ' static const std::vector V_1_0_promoted_%s_extensions = {' % type.lower() ]) - struct.extend([' %s_EXTENSION_NAME,' % ext_name.upper() for ext_name in promoted_ext_list]) - struct.extend([ - ' };', - '', - ' // Initialize struct data, robust to invalid pCreateInfo', - ' if (pCreateInfo->ppEnabledExtensionNames) {', - ' for (uint32_t i = 0; i < pCreateInfo->enabledExtensionCount; i++) {', - ' if (!pCreateInfo->ppEnabledExtensionNames[i]) continue;', - ' auto info = get_info(pCreateInfo->ppEnabledExtensionNames[i]);', - ' if(info.state) this->*(info.state) = true;', - ' }', - ' }', - ' uint32_t api_version = NormalizeApiVersion(requested_api_version);', - ' if (api_version >= VK_API_VERSION_1_1) {', - ' for (auto promoted_ext : V_1_0_promoted_%s_extensions) {' % type.lower(), - ' auto info = get_info(promoted_ext);', - ' assert(info.state);', - ' if (info.state) this->*(info.state) = true;', - ' }', - ' }', - ' return api_version;', - ' }', - '};']) - - # Output reference lists of instance/device extension names - struct.extend(['', 'static const char * const k%sExtensionNames = ' % type]) - struct.extend([guarded(info['ifdef'], ' %s' % info['define']) for ext_name, info in extension_items]) - struct.extend([';', '']) - output.extend(struct) - - output.extend(['', '#endif // VK_EXTENSION_HELPER_H_']) - return '\n'.join(output) - # - # Combine object types helper header file preamble with body text and return - def GenerateObjectTypesHelperHeader(self): - object_types_helper_header = '\n' - object_types_helper_header += '#pragma once\n' - object_types_helper_header += '\n' - object_types_helper_header += '#include \n\n' - object_types_helper_header += self.GenerateObjectTypesHeader() - return object_types_helper_header - # - # Object types header: create object enum type header file - def GenerateObjectTypesHeader(self): - object_types_header = '' - object_types_header += '// Object Type enum for validation layer internal object handling\n' - object_types_header += 'typedef enum VulkanObjectType {\n' - object_types_header += ' kVulkanObjectTypeUnknown = 0,\n' - enum_num = 1 - type_list = []; - enum_entry_map = {} - - # Output enum definition as each handle is processed, saving the names to use for the conversion routine - for item in self.object_types: - fixup_name = item[2:] - enum_entry = 'kVulkanObjectType%s' % fixup_name - enum_entry_map[item] = enum_entry - object_types_header += ' ' + enum_entry - object_types_header += ' = %d,\n' % enum_num - enum_num += 1 - type_list.append(enum_entry) - object_types_header += ' kVulkanObjectTypeMax = %d,\n' % enum_num - object_types_header += ' // Aliases for backwards compatibilty of "promoted" types\n' - for (name, alias) in self.object_type_aliases: - fixup_name = name[2:] - object_types_header += ' kVulkanObjectType{} = {},\n'.format(fixup_name, enum_entry_map[alias]) - object_types_header += '} VulkanObjectType;\n\n' - - # Output name string helper - object_types_header += '// Array of object name strings for OBJECT_TYPE enum conversion\n' - object_types_header += 'static const char * const object_string[kVulkanObjectTypeMax] = {\n' - object_types_header += ' "Unknown",\n' - for item in self.object_types: - fixup_name = item[2:] - object_types_header += ' "%s",\n' % fixup_name - object_types_header += '};\n' - - # Key creation helper for map comprehensions that convert between k and VK symbols - def to_key(regex, raw_key): return re.search(regex, raw_key).group(1).lower().replace("_","") - - # Output a conversion routine from the layer object definitions to the debug report definitions - # As the VK_DEBUG_REPORT types are not being updated, specify UNKNOWN for unmatched types - object_types_header += '\n' - object_types_header += '// Helper array to get Vulkan VK_EXT_debug_report object type enum from the internal layers version\n' - object_types_header += 'const VkDebugReportObjectTypeEXT get_debug_report_enum[] = {\n' - object_types_header += ' VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, // kVulkanObjectTypeUnknown\n' - - dbg_re = '^VK_DEBUG_REPORT_OBJECT_TYPE_(.*)_EXT$' - dbg_map = {to_key(dbg_re, dbg) : dbg for dbg in self.debug_report_object_types} - dbg_default = 'VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT' - for object_type in type_list: - vk_object_type = dbg_map.get(object_type.replace("kVulkanObjectType", "").lower(), dbg_default) - object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) - object_types_header += '};\n' - - # Output a conversion routine from the layer object definitions to the core object type definitions - # This will intentionally *fail* for unmatched types as the VK_OBJECT_TYPE list should match the kVulkanObjectType list - object_types_header += '\n' - object_types_header += '// Helper array to get Official Vulkan VkObjectType enum from the internal layers version\n' - object_types_header += 'const VkObjectType get_object_type_enum[] = {\n' - object_types_header += ' VK_OBJECT_TYPE_UNKNOWN, // kVulkanObjectTypeUnknown\n' - - vko_re = '^VK_OBJECT_TYPE_(.*)' - vko_map = {to_key(vko_re, vko) : vko for vko in self.core_object_types} - for object_type in type_list: - vk_object_type = vko_map[object_type.replace("kVulkanObjectType", "").lower()] - object_types_header += ' %s, // %s\n' % (vk_object_type, object_type) - object_types_header += '};\n' - - # Create a function to convert from VkDebugReportObjectTypeEXT to VkObjectType - object_types_header += '\n' - object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n' - object_types_header += 'static inline VkObjectType convertDebugReportObjectToCoreObject(VkDebugReportObjectTypeEXT debug_report_obj){\n' - object_types_header += ' if (debug_report_obj == VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT) {\n' - object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n' - for core_object_type in self.core_object_types: - core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower() - core_target_type = core_target_type.replace("_", "") - for dr_object_type in self.debug_report_object_types: - dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower() - dr_target_type = dr_target_type[:-4] - dr_target_type = dr_target_type.replace("_", "") - if core_target_type == dr_target_type: - object_types_header += ' } else if (debug_report_obj == %s) {\n' % dr_object_type - object_types_header += ' return %s;\n' % core_object_type - break - object_types_header += ' }\n' - object_types_header += ' return VK_OBJECT_TYPE_UNKNOWN;\n' - object_types_header += '}\n' - - # Create a function to convert from VkObjectType to VkDebugReportObjectTypeEXT - object_types_header += '\n' - object_types_header += '// Helper function to convert from VkDebugReportObjectTypeEXT to VkObjectType\n' - object_types_header += 'static inline VkDebugReportObjectTypeEXT convertCoreObjectToDebugReportObject(VkObjectType core_report_obj){\n' - object_types_header += ' if (core_report_obj == VK_OBJECT_TYPE_UNKNOWN) {\n' - object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n' - for core_object_type in self.core_object_types: - core_target_type = core_object_type.replace("VK_OBJECT_TYPE_", "").lower() - core_target_type = core_target_type.replace("_", "") - for dr_object_type in self.debug_report_object_types: - dr_target_type = dr_object_type.replace("VK_DEBUG_REPORT_OBJECT_TYPE_", "").lower() - dr_target_type = dr_target_type[:-4] - dr_target_type = dr_target_type.replace("_", "") - if core_target_type == dr_target_type: - object_types_header += ' } else if (core_report_obj == %s) {\n' % core_object_type - object_types_header += ' return %s;\n' % dr_object_type - break - object_types_header += ' }\n' - object_types_header += ' return VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;\n' - object_types_header += '}\n' - return object_types_header - # - # Determine if a structure needs a safe_struct helper function - # That is, it has an sType or one of its members is a pointer - def NeedSafeStruct(self, structure): - if 'sType' == structure.name: - return True - for member in structure.members: - if member.ispointer == True: - return True - return False - # - # Combine safe struct helper source file preamble with body text and return - def GenerateSafeStructHelperSource(self): - safe_struct_helper_source = '\n' - safe_struct_helper_source += '#include "vk_safe_struct.h"\n' - safe_struct_helper_source += '#include \n' - safe_struct_helper_source += '#ifdef VK_USE_PLATFORM_ANDROID_KHR\n' - safe_struct_helper_source += '#if __ANDROID_API__ < __ANDROID_API_O__\n' - safe_struct_helper_source += 'struct AHardwareBuffer {};\n' - safe_struct_helper_source += '#endif\n' - safe_struct_helper_source += '#endif\n' - - safe_struct_helper_source += '\n' - safe_struct_helper_source += self.GenerateSafeStructSource() - return safe_struct_helper_source - # - # safe_struct source -- create bodies of safe struct helper functions - def GenerateSafeStructSource(self): - safe_struct_body = [] - wsi_structs = ['VkXlibSurfaceCreateInfoKHR', - 'VkXcbSurfaceCreateInfoKHR', - 'VkWaylandSurfaceCreateInfoKHR', - 'VkMirSurfaceCreateInfoKHR', - 'VkAndroidSurfaceCreateInfoKHR', - 'VkWin32SurfaceCreateInfoKHR' - ] - for item in self.structMembers: - if self.NeedSafeStruct(item) == False: - continue - if item.name in wsi_structs: - continue - if item.ifdef_protect != None: - safe_struct_body.append("#ifdef %s\n" % item.ifdef_protect) - ss_name = "safe_%s" % item.name - init_list = '' # list of members in struct constructor initializer - default_init_list = '' # Default constructor just inits ptrs to nullptr in initializer - init_func_txt = '' # Txt for initialize() function that takes struct ptr and inits members - construct_txt = '' # Body of constuctor as well as body of initialize() func following init_func_txt - destruct_txt = '' - - custom_construct_txt = { - # VkWriteDescriptorSet is special case because pointers may be non-null but ignored - 'VkWriteDescriptorSet' : - ' switch (descriptorType) {\n' - ' case VK_DESCRIPTOR_TYPE_SAMPLER:\n' - ' case VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:\n' - ' case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:\n' - ' case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:\n' - ' case VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT:\n' - ' if (descriptorCount && in_struct->pImageInfo) {\n' - ' pImageInfo = new VkDescriptorImageInfo[descriptorCount];\n' - ' for (uint32_t i=0; ipImageInfo[i];\n' - ' }\n' - ' }\n' - ' break;\n' - ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:\n' - ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER:\n' - ' case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:\n' - ' case VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC:\n' - ' if (descriptorCount && in_struct->pBufferInfo) {\n' - ' pBufferInfo = new VkDescriptorBufferInfo[descriptorCount];\n' - ' for (uint32_t i=0; ipBufferInfo[i];\n' - ' }\n' - ' }\n' - ' break;\n' - ' case VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER:\n' - ' case VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER:\n' - ' if (descriptorCount && in_struct->pTexelBufferView) {\n' - ' pTexelBufferView = new VkBufferView[descriptorCount];\n' - ' for (uint32_t i=0; ipTexelBufferView[i];\n' - ' }\n' - ' }\n' - ' break;\n' - ' default:\n' - ' break;\n' - ' }\n', - 'VkShaderModuleCreateInfo' : - ' if (in_struct->pCode) {\n' - ' pCode = reinterpret_cast(new uint8_t[codeSize]);\n' - ' memcpy((void *)pCode, (void *)in_struct->pCode, codeSize);\n' - ' }\n', - # VkGraphicsPipelineCreateInfo is special case because its pointers may be non-null but ignored - 'VkGraphicsPipelineCreateInfo' : - ' if (stageCount && in_struct->pStages) {\n' - ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' - ' for (uint32_t i=0; ipStages[i]);\n' - ' }\n' - ' }\n' - ' if (in_struct->pVertexInputState)\n' - ' pVertexInputState = new safe_VkPipelineVertexInputStateCreateInfo(in_struct->pVertexInputState);\n' - ' else\n' - ' pVertexInputState = NULL;\n' - ' if (in_struct->pInputAssemblyState)\n' - ' pInputAssemblyState = new safe_VkPipelineInputAssemblyStateCreateInfo(in_struct->pInputAssemblyState);\n' - ' else\n' - ' pInputAssemblyState = NULL;\n' - ' bool has_tessellation_stage = false;\n' - ' if (stageCount && pStages)\n' - ' for (uint32_t i=0; ipTessellationState && has_tessellation_stage)\n' - ' pTessellationState = new safe_VkPipelineTessellationStateCreateInfo(in_struct->pTessellationState);\n' - ' else\n' - ' pTessellationState = NULL; // original pTessellationState pointer ignored\n' - ' bool has_rasterization = in_struct->pRasterizationState ? !in_struct->pRasterizationState->rasterizerDiscardEnable : false;\n' - ' if (in_struct->pViewportState && has_rasterization) {\n' - ' bool is_dynamic_viewports = false;\n' - ' bool is_dynamic_scissors = false;\n' - ' if (in_struct->pDynamicState && in_struct->pDynamicState->pDynamicStates) {\n' - ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_viewports; ++i)\n' - ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_VIEWPORT)\n' - ' is_dynamic_viewports = true;\n' - ' for (uint32_t i = 0; i < in_struct->pDynamicState->dynamicStateCount && !is_dynamic_scissors; ++i)\n' - ' if (in_struct->pDynamicState->pDynamicStates[i] == VK_DYNAMIC_STATE_SCISSOR)\n' - ' is_dynamic_scissors = true;\n' - ' }\n' - ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(in_struct->pViewportState, is_dynamic_viewports, is_dynamic_scissors);\n' - ' } else\n' - ' pViewportState = NULL; // original pViewportState pointer ignored\n' - ' if (in_struct->pRasterizationState)\n' - ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(in_struct->pRasterizationState);\n' - ' else\n' - ' pRasterizationState = NULL;\n' - ' if (in_struct->pMultisampleState && has_rasterization)\n' - ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(in_struct->pMultisampleState);\n' - ' else\n' - ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' - ' // needs a tracked subpass state uses_depthstencil_attachment\n' - ' if (in_struct->pDepthStencilState && has_rasterization && uses_depthstencil_attachment)\n' - ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(in_struct->pDepthStencilState);\n' - ' else\n' - ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' - ' // needs a tracked subpass state usesColorAttachment\n' - ' if (in_struct->pColorBlendState && has_rasterization && uses_color_attachment)\n' - ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(in_struct->pColorBlendState);\n' - ' else\n' - ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' - ' if (in_struct->pDynamicState)\n' - ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(in_struct->pDynamicState);\n' - ' else\n' - ' pDynamicState = NULL;\n', - # VkPipelineViewportStateCreateInfo is special case because its pointers may be non-null but ignored - 'VkPipelineViewportStateCreateInfo' : - ' if (in_struct->pViewports && !is_dynamic_viewports) {\n' - ' pViewports = new VkViewport[in_struct->viewportCount];\n' - ' memcpy ((void *)pViewports, (void *)in_struct->pViewports, sizeof(VkViewport)*in_struct->viewportCount);\n' - ' }\n' - ' else\n' - ' pViewports = NULL;\n' - ' if (in_struct->pScissors && !is_dynamic_scissors) {\n' - ' pScissors = new VkRect2D[in_struct->scissorCount];\n' - ' memcpy ((void *)pScissors, (void *)in_struct->pScissors, sizeof(VkRect2D)*in_struct->scissorCount);\n' - ' }\n' - ' else\n' - ' pScissors = NULL;\n', - # VkDescriptorSetLayoutBinding is special case because its pImmutableSamplers pointer may be non-null but ignored - 'VkDescriptorSetLayoutBinding' : - ' const bool sampler_type = in_struct->descriptorType == VK_DESCRIPTOR_TYPE_SAMPLER || in_struct->descriptorType == VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n' - ' if (descriptorCount && in_struct->pImmutableSamplers && sampler_type) {\n' - ' pImmutableSamplers = new VkSampler[descriptorCount];\n' - ' for (uint32_t i=0; ipImmutableSamplers[i];\n' - ' }\n' - ' }\n', - } - - custom_copy_txt = { - # VkGraphicsPipelineCreateInfo is special case because it has custom construct parameters - 'VkGraphicsPipelineCreateInfo' : - ' if (stageCount && src.pStages) {\n' - ' pStages = new safe_VkPipelineShaderStageCreateInfo[stageCount];\n' - ' for (uint32_t i=0; irasterizerDiscardEnable : false;\n' - ' if (src.pViewportState && has_rasterization) {\n' - ' pViewportState = new safe_VkPipelineViewportStateCreateInfo(*src.pViewportState);\n' - ' } else\n' - ' pViewportState = NULL; // original pViewportState pointer ignored\n' - ' if (src.pRasterizationState)\n' - ' pRasterizationState = new safe_VkPipelineRasterizationStateCreateInfo(*src.pRasterizationState);\n' - ' else\n' - ' pRasterizationState = NULL;\n' - ' if (src.pMultisampleState && has_rasterization)\n' - ' pMultisampleState = new safe_VkPipelineMultisampleStateCreateInfo(*src.pMultisampleState);\n' - ' else\n' - ' pMultisampleState = NULL; // original pMultisampleState pointer ignored\n' - ' if (src.pDepthStencilState && has_rasterization)\n' - ' pDepthStencilState = new safe_VkPipelineDepthStencilStateCreateInfo(*src.pDepthStencilState);\n' - ' else\n' - ' pDepthStencilState = NULL; // original pDepthStencilState pointer ignored\n' - ' if (src.pColorBlendState && has_rasterization)\n' - ' pColorBlendState = new safe_VkPipelineColorBlendStateCreateInfo(*src.pColorBlendState);\n' - ' else\n' - ' pColorBlendState = NULL; // original pColorBlendState pointer ignored\n' - ' if (src.pDynamicState)\n' - ' pDynamicState = new safe_VkPipelineDynamicStateCreateInfo(*src.pDynamicState);\n' - ' else\n' - ' pDynamicState = NULL;\n', - # VkPipelineViewportStateCreateInfo is special case because it has custom construct parameters - 'VkPipelineViewportStateCreateInfo' : - ' if (src.pViewports) {\n' - ' pViewports = new VkViewport[src.viewportCount];\n' - ' memcpy ((void *)pViewports, (void *)src.pViewports, sizeof(VkViewport)*src.viewportCount);\n' - ' }\n' - ' else\n' - ' pViewports = NULL;\n' - ' if (src.pScissors) {\n' - ' pScissors = new VkRect2D[src.scissorCount];\n' - ' memcpy ((void *)pScissors, (void *)src.pScissors, sizeof(VkRect2D)*src.scissorCount);\n' - ' }\n' - ' else\n' - ' pScissors = NULL;\n', - } - - custom_destruct_txt = {'VkShaderModuleCreateInfo' : - ' if (pCode)\n' - ' delete[] reinterpret_cast(pCode);\n' } - - for member in item.members: - m_type = member.type - if member.type in self.structNames: - member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) - if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: - m_type = 'safe_%s' % member.type - if member.ispointer and 'safe_' not in m_type and self.TypeContainsObjectHandle(member.type, False) == False: - # Ptr types w/o a safe_struct, for non-null case need to allocate new ptr and copy data in - if m_type in ['void', 'char']: - # For these exceptions just copy initial value over for now - init_list += '\n %s(in_struct->%s),' % (member.name, member.name) - init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) - else: - default_init_list += '\n %s(nullptr),' % (member.name) - init_list += '\n %s(nullptr),' % (member.name) - init_func_txt += ' %s = nullptr;\n' % (member.name) - if 'pNext' != member.name and 'void' not in m_type: - if not member.isstaticarray and (member.len is None or '/' in member.len): - construct_txt += ' if (in_struct->%s) {\n' % member.name - construct_txt += ' %s = new %s(*in_struct->%s);\n' % (member.name, m_type, member.name) - construct_txt += ' }\n' - destruct_txt += ' if (%s)\n' % member.name - destruct_txt += ' delete %s;\n' % member.name - else: - construct_txt += ' if (in_struct->%s) {\n' % member.name - construct_txt += ' %s = new %s[in_struct->%s];\n' % (member.name, m_type, member.len) - construct_txt += ' memcpy ((void *)%s, (void *)in_struct->%s, sizeof(%s)*in_struct->%s);\n' % (member.name, member.name, m_type, member.len) - construct_txt += ' }\n' - destruct_txt += ' if (%s)\n' % member.name - destruct_txt += ' delete[] %s;\n' % member.name - elif member.isstaticarray or member.len is not None: - if member.len is None: - # Extract length of static array by grabbing val between [] - static_array_size = re.match(r"[^[]*\[([^]]*)\]", member.cdecl) - construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % static_array_size.group(1) - construct_txt += ' %s[i] = in_struct->%s[i];\n' % (member.name, member.name) - construct_txt += ' }\n' - else: - # Init array ptr to NULL - default_init_list += '\n %s(nullptr),' % member.name - init_list += '\n %s(nullptr),' % member.name - init_func_txt += ' %s = nullptr;\n' % member.name - array_element = 'in_struct->%s[i]' % member.name - if member.type in self.structNames: - member_index = next((i for i, v in enumerate(self.structMembers) if v[0] == member.type), None) - if member_index is not None and self.NeedSafeStruct(self.structMembers[member_index]) == True: - array_element = '%s(&in_struct->safe_%s[i])' % (member.type, member.name) - construct_txt += ' if (%s && in_struct->%s) {\n' % (member.len, member.name) - construct_txt += ' %s = new %s[%s];\n' % (member.name, m_type, member.len) - destruct_txt += ' if (%s)\n' % member.name - destruct_txt += ' delete[] %s;\n' % member.name - construct_txt += ' for (uint32_t i=0; i<%s; ++i) {\n' % (member.len) - if 'safe_' in m_type: - construct_txt += ' %s[i].initialize(&in_struct->%s[i]);\n' % (member.name, member.name) - else: - construct_txt += ' %s[i] = %s;\n' % (member.name, array_element) - construct_txt += ' }\n' - construct_txt += ' }\n' - elif member.ispointer == True: - construct_txt += ' if (in_struct->%s)\n' % member.name - construct_txt += ' %s = new %s(in_struct->%s);\n' % (member.name, m_type, member.name) - construct_txt += ' else\n' - construct_txt += ' %s = NULL;\n' % member.name - destruct_txt += ' if (%s)\n' % member.name - destruct_txt += ' delete %s;\n' % member.name - elif 'safe_' in m_type: - init_list += '\n %s(&in_struct->%s),' % (member.name, member.name) - init_func_txt += ' %s.initialize(&in_struct->%s);\n' % (member.name, member.name) - else: - init_list += '\n %s(in_struct->%s),' % (member.name, member.name) - init_func_txt += ' %s = in_struct->%s;\n' % (member.name, member.name) - if '' != init_list: - init_list = init_list[:-1] # hack off final comma - if item.name in custom_construct_txt: - construct_txt = custom_construct_txt[item.name] - if item.name in custom_destruct_txt: - destruct_txt = custom_destruct_txt[item.name] - safe_struct_body.append("\n%s::%s(const %s* in_struct%s) :%s\n{\n%s}" % (ss_name, ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_list, construct_txt)) - if '' != default_init_list: - default_init_list = " :%s" % (default_init_list[:-1]) - safe_struct_body.append("\n%s::%s()%s\n{}" % (ss_name, ss_name, default_init_list)) - # Create slight variation of init and construct txt for copy constructor that takes a src object reference vs. struct ptr - copy_construct_init = init_func_txt.replace('in_struct->', 'src.') - copy_construct_txt = construct_txt.replace(' (in_struct->', ' (src.') # Exclude 'if' blocks from next line - copy_construct_txt = copy_construct_txt.replace('(in_struct->', '(*src.') # Pass object to copy constructors - copy_construct_txt = copy_construct_txt.replace('in_struct->', 'src.') # Modify remaining struct refs for src object - if item.name in custom_copy_txt: - copy_construct_txt = custom_copy_txt[item.name] - copy_assign_txt = ' if (&src == this) return *this;\n\n' + destruct_txt + '\n' + copy_construct_init + copy_construct_txt + '\n return *this;' - safe_struct_body.append("\n%s::%s(const %s& src)\n{\n%s%s}" % (ss_name, ss_name, ss_name, copy_construct_init, copy_construct_txt)) # Copy constructor - safe_struct_body.append("\n%s& %s::operator=(const %s& src)\n{\n%s\n}" % (ss_name, ss_name, ss_name, copy_assign_txt)) # Copy assignment operator - safe_struct_body.append("\n%s::~%s()\n{\n%s}" % (ss_name, ss_name, destruct_txt)) - safe_struct_body.append("\nvoid %s::initialize(const %s* in_struct%s)\n{\n%s%s}" % (ss_name, item.name, self.custom_construct_params.get(item.name, ''), init_func_txt, construct_txt)) - # Copy initializer uses same txt as copy constructor but has a ptr and not a reference - init_copy = copy_construct_init.replace('src.', 'src->') - init_construct = copy_construct_txt.replace('src.', 'src->') - safe_struct_body.append("\nvoid %s::initialize(const %s* src)\n{\n%s%s}" % (ss_name, ss_name, init_copy, init_construct)) - if item.ifdef_protect != None: - safe_struct_body.append("#endif // %s\n" % item.ifdef_protect) - return "\n".join(safe_struct_body) - # - # Generate the type map - def GenerateTypeMapHelperHeader(self): - prefix = 'Lvl' - fprefix = 'lvl_' - typemap = prefix + 'TypeMap' - idmap = prefix + 'STypeMap' - type_member = 'Type' - id_member = 'kSType' - id_decl = 'static const VkStructureType ' - generic_header = prefix + 'GenericHeader' - generic_mod_header = prefix + 'GenericModHeader' - typename_func = fprefix + 'typename' - idname_func = fprefix + 'stype_name' - find_func = fprefix + 'find_in_chain' - find_mod_func = fprefix + 'find_mod_in_chain' - init_func = fprefix + 'init_struct' - - explanatory_comment = '\n'.join(( - '// These empty generic templates are specialized for each type with sType', - '// members and for each sType -- providing a two way map between structure', - '// types and sTypes')) - - empty_typemap = 'template struct ' + typemap + ' {};' - typemap_format = 'template <> struct {template}<{typename}> {{\n' - typemap_format += ' {id_decl}{id_member} = {id_value};\n' - typemap_format += '}};\n' - - empty_idmap = 'template struct ' + idmap + ' {};' - idmap_format = ''.join(( - 'template <> struct {template}<{id_value}> {{\n', - ' typedef {typename} {typedef};\n', - '}};\n')) - - # Define the utilities (here so any renaming stays consistent), if this grows large, refactor to a fixed .h file - utilities_format = '\n'.join(( - '// Header "base class" for pNext chain traversal', - 'struct {header} {{', - ' VkStructureType sType;', - ' const {header} *pNext;', - '}};', - 'struct {mod_header} {{', - ' VkStructureType sType;', - ' {mod_header} *pNext;', - '}};', - '', - '// Find an entry of the given type in the pNext chain', - 'template const T *{find_func}(const void *next) {{', - ' const {header} *current = reinterpret_cast(next);', - ' const T *found = nullptr;', - ' while (current) {{', - ' if ({type_map}::{id_member} == current->sType) {{', - ' found = reinterpret_cast(current);', - ' current = nullptr;', - ' }} else {{', - ' current = current->pNext;', - ' }}', - ' }}', - ' return found;', - '}}', - '// Find an entry of the given type in the pNext chain', - 'template T *{find_mod_func}(void *next) {{', - ' {mod_header} *current = reinterpret_cast<{mod_header} *>(next);', - ' T *found = nullptr;', - ' while (current) {{', - ' if ({type_map}::{id_member} == current->sType) {{', - ' found = reinterpret_cast(current);', - ' current = nullptr;', - ' }} else {{', - ' current = current->pNext;', - ' }}', - ' }}', - ' return found;', - '}}', - '', - '// Init the header of an sType struct with pNext', - 'template T {init_func}(void *p_next) {{', - ' T out = {{}};', - ' out.sType = {type_map}::kSType;', - ' out.pNext = p_next;', - ' return out;', - '}}', - '', - '// Init the header of an sType struct', - 'template T {init_func}() {{', - ' T out = {{}};', - ' out.sType = {type_map}::kSType;', - ' return out;', - '}}', - - '')) - - code = [] - - # Generate header - code.append('\n'.join(( - '#pragma once', - '#include \n', - explanatory_comment, '', - empty_idmap, - empty_typemap, ''))) - - # Generate the specializations for each type and stype - for item in self.structMembers: - typename = item.name - info = self.structTypes.get(typename) - if not info: - continue - - if item.ifdef_protect != None: - code.append('#ifdef %s' % item.ifdef_protect) - - code.append('// Map type {} to id {}'.format(typename, info.value)) - code.append(typemap_format.format(template=typemap, typename=typename, id_value=info.value, - id_decl=id_decl, id_member=id_member)) - code.append(idmap_format.format(template=idmap, typename=typename, id_value=info.value, typedef=type_member)) - - if item.ifdef_protect != None: - code.append('#endif // %s' % item.ifdef_protect) - - # Generate utilities for all types - code.append('\n'.join(( - utilities_format.format(id_member=id_member, id_map=idmap, type_map=typemap, - type_member=type_member, header=generic_header, mod_header=generic_mod_header, - typename_func=typename_func, idname_func=idname_func, find_func=find_func, - find_mod_func=find_mod_func, init_func=init_func), '' - ))) - - return "\n".join(code) - - # - # Create a helper file and return it as a string - def OutputDestFile(self): - if self.helper_file_type == 'enum_string_header': - return self.GenerateEnumStringHelperHeader() - elif self.helper_file_type == 'safe_struct_header': - return self.GenerateSafeStructHelperHeader() - elif self.helper_file_type == 'safe_struct_source': - return self.GenerateSafeStructHelperSource() - elif self.helper_file_type == 'object_types_header': - return self.GenerateObjectTypesHelperHeader() - elif self.helper_file_type == 'extension_helper_header': - return self.GenerateExtensionHelperHeader() - elif self.helper_file_type == 'typemap_helper_header': - return self.GenerateTypeMapHelperHeader() - else: - return 'Bad Helper File Generator Option %s' % self.helper_file_type diff --git a/scripts/vulkaninfo_generator.py b/scripts/vulkaninfo_generator.py deleted file mode 100644 index 20e408e4..00000000 --- a/scripts/vulkaninfo_generator.py +++ /dev/null @@ -1,1729 +0,0 @@ -#!/usr/bin/python3 -# -# Copyright (c) 2019-2022 Valve Corporation -# Copyright (c) 2019-2022 LunarG, Inc. -# Copyright (c) 2019-2022 Google Inc. -# Copyright (c) 2023-2024 RasterGrid Kft. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# Author: Charles Giessen - -import re -import os -import sys -import copy -import operator -from collections import OrderedDict -import generator as gen -from common_codegen import GetFeatureProtect -from generator import GeneratorOptions, OutputGenerator -import xml.etree.ElementTree as etree - -LICENSE_HEADER = ''' -/* - * Copyright (c) 2019-2022 The Khronos Group Inc. - * Copyright (c) 2019-2022 Valve Corporation - * Copyright (c) 2019-2022 LunarG, Inc. - * Copyright (c) 2023-2024 RasterGrid Kft. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Author: Charles Giessen - * - */ - -/* - * This file is generated from the Khronos Vulkan XML API Registry. - */ -''' - -CUSTOM_FORMATTERS = r''' -template -std::string to_hex_str(const T i) { - std::stringstream stream; - stream << "0x" << std::setfill('0') << std::setw(sizeof(T)) << std::hex << i; - return stream.str(); -} - -template -std::string to_hex_str(Printer &p, const T i) { - if (p.Type() == OutputType::json) - return std::to_string(i); - else if (p.Type() == OutputType::vkconfig_output) - return std::string("\"") + to_hex_str(i) + std::string("\""); - else - return to_hex_str(i); -} - -''' - - -# used in the .cpp code -STRUCTURES_TO_GEN = ['VkExtent3D', 'VkExtent2D', 'VkPhysicalDeviceLimits', 'VkPhysicalDeviceFeatures', 'VkPhysicalDeviceSparseProperties', - 'VkSurfaceCapabilitiesKHR', 'VkSurfaceFormatKHR', 'VkLayerProperties', 'VkPhysicalDeviceToolProperties', 'VkFormatProperties', - 'VkSurfacePresentScalingCapabilitiesKHR', 'VkSurfacePresentModeCompatibilityKHR', 'VkPhysicalDeviceHostImageCopyProperties', - 'VkVideoProfileInfoKHR', 'VkVideoCapabilitiesKHR', 'VkVideoFormatPropertiesKHR'] -ENUMS_TO_GEN = ['VkResult', 'VkFormat', 'VkPresentModeKHR', - 'VkPhysicalDeviceType', 'VkImageTiling'] -FLAGS_TO_GEN = ['VkSurfaceTransformFlagsKHR', 'VkCompositeAlphaFlagsKHR', 'VkSurfaceCounterFlagsEXT', 'VkQueueFlags', - 'VkDeviceGroupPresentModeFlagsKHR', 'VkFormatFeatureFlags', 'VkFormatFeatureFlags2', 'VkMemoryPropertyFlags', 'VkMemoryHeapFlags'] -FLAG_STRINGS_TO_GEN = ['VkQueueFlags'] - -STRUCT_SHORT_VERSIONS_TO_GEN = ['VkExtent3D'] - -STRUCT_COMPARISONS_TO_GEN = ['VkSurfaceFormatKHR', 'VkSurfaceFormat2KHR', 'VkSurfaceCapabilitiesKHR', - 'VkSurfaceCapabilities2KHR', 'VkSurfaceCapabilities2EXT'] -# don't generate these structures -STRUCT_BLACKLIST = ['VkVideoProfileListInfoKHR', 'VkDrmFormatModifierPropertiesListEXT', 'VkDrmFormatModifierPropertiesEXT', 'VkDrmFormatModifierPropertiesList2EXT'] -# These structures are only used in version 1.1, otherwise they are included in the promoted structs -STRUCT_1_1_LIST = ['VkPhysicalDeviceProtectedMemoryFeatures', 'VkPhysicalDeviceShaderDrawParametersFeatures', 'VkPhysicalDeviceSubgroupProperties', 'VkPhysicalDeviceProtectedMemoryProperties'] - -# generate these structures such that they only print when not in json mode (as json wants them separate) -PORTABILITY_STRUCTS = ['VkPhysicalDevicePortabilitySubsetFeaturesKHR', 'VkPhysicalDevicePortabilitySubsetPropertiesKHR'] - -# iostream or custom outputter handles these types -PREDEFINED_TYPES = ['char', 'VkBool32', 'uint32_t', 'uint8_t', 'int32_t', - 'float', 'uint64_t', 'size_t', 'VkDeviceSize', 'int64_t'] - -NAMES_TO_IGNORE = ['sType', 'pNext'] - -EXTENSION_TYPE_INSTANCE = 'instance' -EXTENSION_TYPE_DEVICE = 'device' -EXTENSION_TYPE_BOTH = 'both' - -# Types that need pNext Chains built. 'extends' is the xml tag used in the structextends member. 'type' can be device, instance, or both -EXTENSION_CATEGORIES = OrderedDict(( - ('phys_device_props2', - {'extends': 'VkPhysicalDeviceProperties2', - 'type': EXTENSION_TYPE_BOTH, - 'holder_type': 'VkPhysicalDeviceProperties2', - 'print_iterator': True, - 'can_show_promoted_structs': True, - 'ignore_vendor_exclusion': False}), - ('phys_device_mem_props2', - {'extends': 'VkPhysicalDeviceMemoryProperties2', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type':'VkPhysicalDeviceMemoryProperties2', - 'print_iterator': False, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': False}), - ('phys_device_features2', - {'extends': 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type': 'VkPhysicalDeviceFeatures2', - 'print_iterator': True, - 'can_show_promoted_structs': True, - 'ignore_vendor_exclusion': False}), - ('surface_capabilities2', - {'extends': 'VkSurfaceCapabilities2KHR', - 'type': EXTENSION_TYPE_BOTH, - 'holder_type': 'VkSurfaceCapabilities2KHR', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': False, - 'exclude': ['VkSurfacePresentScalingCapabilitiesKHR', 'VkSurfacePresentModeCompatibilityKHR']}), - ('format_properties2', - {'extends': 'VkFormatProperties2', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type':'VkFormatProperties2', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': False}), - ('queue_properties2', - {'extends': 'VkQueueFamilyProperties2', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type': 'VkQueueFamilyProperties2', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': False}), - ('video_profile_info', - {'extends': 'VkVideoProfileInfoKHR', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type': 'VkVideoProfileInfoKHR', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': True}), - ('video_capabilities', - {'extends': 'VkVideoCapabilitiesKHR', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type': 'VkVideoCapabilitiesKHR', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': True,}), - ('video_format_properties', - {'extends': 'VkVideoFormatPropertiesKHR', - 'type': EXTENSION_TYPE_DEVICE, - 'holder_type': 'VkVideoFormatPropertiesKHR', - 'print_iterator': True, - 'can_show_promoted_structs': False, - 'ignore_vendor_exclusion': True}) - )) -class VulkanInfoGeneratorOptions(GeneratorOptions): - def __init__(self, - conventions=None, - input=None, - filename=None, - directory='.', - genpath = None, - apiname=None, - profile=None, - versions='.*', - emitversions='.*', - defaultExtensions=None, - addExtensions=None, - removeExtensions=None, - emitExtensions=None, - sortProcedure=None, - prefixText='', - genFuncPointers=True, - protectFile=True, - protectFeature=True, - protectProto=None, - protectProtoStr=None, - apicall='', - apientry='', - apientryp='', - indentFuncProto=True, - indentFuncPointer=False, - alignFuncParam=0, - expandEnumerants=True, - registryFile='vk.xml' - ): - GeneratorOptions.__init__(self, - conventions = conventions, - filename = filename, - directory = directory, - genpath = genpath, - apiname = apiname, - profile = profile, - versions = versions, - emitversions = emitversions, - defaultExtensions = defaultExtensions, - addExtensions = addExtensions, - removeExtensions = removeExtensions, - emitExtensions = emitExtensions, - sortProcedure = sortProcedure) - self.input = input - self.prefixText = prefixText - self.genFuncPointers = genFuncPointers - self.protectFile = protectFile - self.protectFeature = protectFeature - self.protectProto = protectProto - self.protectProtoStr = protectProtoStr - self.apicall = apicall - self.apientry = apientry - self.apientryp = apientryp - self.indentFuncProto = indentFuncProto - self.indentFuncPointer = indentFuncPointer - self.alignFuncParam = alignFuncParam - self.registryFile = registryFile - -# VulkanInfoGenerator - subclass of OutputGenerator. -# Generates a vulkan info output helper function - - -class VulkanInfoGenerator(OutputGenerator): - - def __init__(self, - errFile=sys.stderr, - warnFile=sys.stderr, - diagFile=sys.stdout): - OutputGenerator.__init__(self, errFile, warnFile, diagFile) - - self.constants = OrderedDict() - - self.types_to_gen = set() - - self.extension_sets = OrderedDict() - for ext_cat in EXTENSION_CATEGORIES.keys(): - self.extension_sets[ext_cat] = set() - - self.enums = [] - self.flags = [] - self.bitmasks = [] - self.format_ranges = [] - self.all_structures = [] - self.aliases = OrderedDict() - - self.extFuncs = OrderedDict() - self.extTypes = OrderedDict() - - self.vendor_abbreviations = [] - self.vulkan_versions = [] - - def beginFile(self, genOpts): - gen.OutputGenerator.beginFile(self, genOpts) - - for node in self.registry.reg.findall('enums'): - if node.get('name') == 'API Constants': - for item in node.findall('enum'): - self.constants[item.get('name')] = item.get('value') - - for node in self.registry.reg.find('extensions').findall('extension'): - ext = VulkanExtension(node) - for item in ext.vktypes: - if item not in self.extTypes: - self.extTypes[item] = [] - self.extTypes[item].append(ext) - for item in ext.vkfuncs: - self.extFuncs[item] = ext - - # need list of venders to blacklist vendor extensions - for tag in self.registry.reg.find('tags'): - if tag.get('name') not in ['KHR', 'EXT']: - self.vendor_abbreviations.append('_' + tag.get('name')) - - for ver in self.registry.reg.findall('feature'): - self.vulkan_versions.append(VulkanVersion(ver)) - - def endFile(self): - self.findFormatRanges() - - # gather the types that are needed to generate - types_to_gen = set() - for s in ENUMS_TO_GEN: - types_to_gen.add(s) - - for f in FLAGS_TO_GEN: - types_to_gen.add(f) - - types_to_gen.update( - GatherTypesToGen(self.all_structures, STRUCTURES_TO_GEN)) - for key, info in EXTENSION_CATEGORIES.items(): - types_to_gen.update( - GatherTypesToGen(self.all_structures, self.extension_sets[key], info.get('exclude'))) - types_to_gen = sorted(types_to_gen) - - names_of_structures_to_gen = set() - for s in self.all_structures: - if s.name in types_to_gen: - names_of_structures_to_gen.add(s.name) - names_of_structures_to_gen = sorted(names_of_structures_to_gen) - - structs_to_comp = set() - for s in STRUCT_COMPARISONS_TO_GEN: - structs_to_comp.add(s) - structs_to_comp.update( - GatherTypesToGen(self.all_structures, STRUCT_COMPARISONS_TO_GEN)) - - for key, value in self.extension_sets.items(): - self.extension_sets[key] = sorted(value) - - self.enums = sorted(self.enums, key=operator.attrgetter('name')) - self.flags = sorted(self.flags, key=operator.attrgetter('name')) - self.bitmasks = sorted(self.bitmasks, key=operator.attrgetter('name')) - self.all_structures = sorted(self.all_structures, key=operator.attrgetter('name')) - - # print the types gathered - out = '' - out += LICENSE_HEADER + '\n' - out += '#include "vulkaninfo.h"\n' - out += '#include "outputprinter.h"\n' - out += CUSTOM_FORMATTERS - - out += self.genVideoEnums() - - for enum in (e for e in self.enums if e.name in types_to_gen): - out += PrintEnumToString(enum, self) - out += PrintEnum(enum, self) - - for flag in self.flags: - if flag.name in types_to_gen or flag.enum in types_to_gen: - for bitmask in (b for b in self.bitmasks if b.name == flag.enum): - out += PrintBitMask(bitmask, flag.name, self) - - if flag.name in FLAG_STRINGS_TO_GEN: - for bitmask in (b for b in self.bitmasks if b.name == flag.enum): - out += PrintBitMaskToString(bitmask, flag.name, self) - - for s in (x for x in self.all_structures if x.name in types_to_gen and x.name not in STRUCT_BLACKLIST): - out += PrintStructure(s) - - for key, value in EXTENSION_CATEGORIES.items(): - out += PrintChainStruct(key, self.extension_sets[key], self.all_structures, value, self.extTypes, self.aliases, self.vulkan_versions) - - for s in (x for x in self.all_structures if x.name in structs_to_comp): - out += PrintStructComparisonForwardDecl(s) - for s in (x for x in self.all_structures if x.name in structs_to_comp): - out += PrintStructComparison(s) - for s in (x for x in self.all_structures if x.name in STRUCT_SHORT_VERSIONS_TO_GEN): - out += PrintStructShort(s) - - out += 'auto format_ranges = std::array{\n' - for f in self.format_ranges: - out += f' FormatRange{{{f.minimum_instance_version}, {f.extension_name if f.extension_name is not None else "nullptr"}, ' - out += f'static_cast({f.first_format}), static_cast({f.last_format})}},\n' - out += '};\n' - - out += self.genVideoProfileUtils() - - gen.write(out, file=self.outFile) - - gen.OutputGenerator.endFile(self) - - def genVideoEnums(self): - # We need to add dumping utilities for enums declared in the video std headers and directly - # present in the Vulkan API structures. In order to do that we really have no choice but - # to parse the video.xml and generate the utilities based on the enum types defined there - videoRegistryFile = self.genOpts.registryFile.replace('vk.xml', 'video.xml') - if os.path.isfile(videoRegistryFile): - videoxml = etree.parse(videoRegistryFile) - else: - assert False, "Could not find video.xml to generate utilities for video enum types" - out = '' - for enum in videoxml.findall("./enums[@name]"): - enumname = enum.get('name') - out += f'std::string {enumname}String({enumname} value) {{\n' - out += ' switch (value) {\n' - for option in enum.findall("./enum[@name]"): - name = option.get('name') - # Ignore aliases - if option.get('value') is not None: - out += f' case {name}: return "{name}";\n' - out += f' default: return std::string("UNKNOWN_{enumname}_value") + std::to_string(value);\n' - out += ' }\n}\n' - out += f'void Dump{enumname}(Printer &p, std::string name, {enumname} value) {{\n' - out += f' p.PrintKeyString(name, {enumname}String(value));\n}}\n' - return out - - def genVideoProfileUtils(self): - out = '' - - # Parse video codec information from the XML - videoCodecs = OrderedDict() - xmlVideoCodecs = self.registry.reg.find("./videocodecs") - for xmlVideoCodec in xmlVideoCodecs.findall("./videocodec"): - name = xmlVideoCodec.get('name') - extend = xmlVideoCodec.get('extend') - value = xmlVideoCodec.get('value') - if value is None: - # Video codec category - videoCodecs[name] = VulkanVideoCodec(name) - else: - # Specific video codec - videoCodecs[name] = VulkanVideoCodec(name, videoCodecs[extend], value) - videoCodec = videoCodecs[name] - - for xmlVideoProfiles in xmlVideoCodec.findall("./videoprofiles"): - videoProfileStructName = xmlVideoProfiles.get('struct') - videoCodec.profileStructs[videoProfileStructName] = VulkanVideoProfileStruct(videoProfileStructName) - videoProfileStruct = videoCodec.profileStructs[videoProfileStructName] - - for xmlVideoProfileMember in xmlVideoProfiles.findall("./videoprofilemember"): - memberName = xmlVideoProfileMember.get('name') - videoProfileStruct.members[memberName] = VulkanVideoProfileStructMember(memberName) - videoProfileStructMember = videoProfileStruct.members[memberName] - - for xmlVideoProfile in xmlVideoProfileMember.findall("./videoprofile"): - videoProfileStructMember.values[xmlVideoProfile.get('value')] = xmlVideoProfile.get('name') - - for xmlVideoCapabilities in xmlVideoCodec.findall("./videocapabilities"): - capabilityStructName = xmlVideoCapabilities.get('struct') - videoCodec.capabilities[capabilityStructName] = capabilityStructName - - for xmlVideoFormat in xmlVideoCodec.findall("./videoformat"): - videoFormatName = xmlVideoFormat.get('name') - videoFormatExtend = xmlVideoFormat.get('extend') - if videoFormatName is not None: - # This is a new video format category - videoFormatUsage = xmlVideoFormat.get('usage') - videoCodec.formats[videoFormatName] = VulkanVideoFormat(videoFormatName, videoFormatUsage) - videoFormat = videoCodec.formats[videoFormatName] - elif videoFormatExtend is not None: - # This is an extension to an already defined video format category - if videoFormatExtend in videoCodec.formats: - videoFormat = videoCodec.formats[videoFormatExtend] - else: - assert False, f"Video format category '{videoFormatExtend}' not found but it is attempted to be extended" - else: - assert False, "'name' or 'extend' is attribute is required for 'videoformat' element" - - for xmlVideoFormatProperties in xmlVideoFormat.findall("./videoformatproperties"): - propertiesStructName = xmlVideoFormatProperties.get('struct') - videoFormat.properties[propertiesStructName] = propertiesStructName - - for xmlVideoFormatRequiredCap in xmlVideoFormat.findall("./videorequirecapabilities"): - requiredCapStruct = xmlVideoFormatRequiredCap.get('struct') - requiredCapMember = xmlVideoFormatRequiredCap.get('member') - requiredCapValue = xmlVideoFormatRequiredCap.get('value') - videoFormat.requiredCaps.append(VulkanVideoRequiredCapabilities(requiredCapStruct, requiredCapMember, requiredCapValue)) - - # Collect flag types in a set because we will need to look this up - flagTypes = set() - for flagType in self.flags: - flagTypes.add(flagType.name) - - # Utility to get structure definition from structure name - def GetStructDef(name): - for s in self.all_structures: - if s.name == name: - return s - assert False, f"Definition for structure '{name}' is missing" - - # Utility to get the extension / version precondition of a list of type names - def GetTypesPrecondition(typelist, indent): - indent = ' ' * indent - out = '' - extEnables = {} - for typename in typelist: - for k, elem in self.extTypes.items(): - if k == typename or (typename in self.aliases.keys() and k in self.aliases[typename]): - for e in elem: - extEnables[e.extNameStr] = e.type - - version = None - for typename in typelist: - for v in self.vulkan_versions: - if typename in v.names: - if version is not None and (v.major > version.major or (v.major == version.major and v.minor > version.minor)): - version = v - - has_version = version is not None - has_extNameStr = len(extEnables) > 0 or typename in self.aliases.keys() - if has_version or has_extNameStr: - out += f'{indent}if (' - has_printed_condition = False - if has_extNameStr: - for key, value in extEnables.items(): - if has_printed_condition: - out += f'\n{indent} || ' - else: - has_printed_condition = True - if has_version: - out += '(' - if value == EXTENSION_TYPE_DEVICE: - out += f'gpu.CheckPhysicalDeviceExtensionIncluded({key})' - else: - assert False, 'Should never get here' - if has_version: - if has_printed_condition: - out += f'\n{indent} || (gpu.api_version >= {version.constant})' - else: - out += f'gpu.api_version >= {version.constant}' - out += ') {\n' - else: - out = f'{indent}{{\n' - return out - - # Utility to construct a capability prerequisite condition evaluation expression - def GetRequiredCapsCondition(structName, memberName, memberRef, value): - condition = '' - requiredCapStructDef = GetStructDef(structName) - for member in requiredCapStructDef.members: - if member.name == memberName: - if member.typeID in flagTypes: - # Check that the flags contain all the required values - def genExpressionFromValue(value): - return value if value == "" else f"({memberRef} & {value}) != 0" - - for char in condition: - if char in ['(', ')', '+', ',']: - condition += genExpressionFromValue(value) - value = "" - if char == '+': - # '+' means AND - condition += ' && ' - elif char == ',': - # ',' means OR - condition += ' || ' - else: - condition += char - else: - value += char - condition += genExpressionFromValue(value) - else: - condition = f'{memberRef} == {value}' - if condition == '': - return 'true' - else: - return f'({condition})' - - # Generate video format properties comparator - out += ''' -bool is_video_format_same(const VkVideoFormatPropertiesKHR &format_a, const VkVideoFormatPropertiesKHR &format_b) { - auto a = reinterpret_cast(&format_a); - auto b = reinterpret_cast(&format_b); - bool same = true; - while (same && a != nullptr && b != nullptr) { - if (a->sType != b->sType) { - // Structure type mismatch (extension structures are expected to be chained in the same order) - same = false; - } else { - switch (a->sType) {''' - - if 'VkVideoFormatPropertiesKHR' in self.registry.validextensionstructs: - for extstruct in ['VkVideoFormatPropertiesKHR'] + self.registry.validextensionstructs['VkVideoFormatPropertiesKHR']: - extstructDef = GetStructDef(extstruct) - out += f''' - case {extstructDef.sTypeName}: - same = same && memcmp(reinterpret_cast(a) + sizeof(VkBaseInStructure), - reinterpret_cast(b) + sizeof(VkBaseInStructure), - sizeof({extstruct}) - sizeof(VkBaseInStructure)) == 0; - break;''' - - out += ''' - default: - // Unexpected structure type - same = false; - break; - } - } - a = a->pNext; - b = b->pNext; - } - return same; -} -''' - - # Generate video profile info capture utilities - out += ''' -std::vector> enumerate_supported_video_profiles(AppGpu &gpu) { - std::vector> result{}; - - struct ChromaSubsamplingInfo { - VkVideoChromaSubsamplingFlagsKHR value; - const char* name; - }; - const std::vector chroma_subsampling_list = { - {VK_VIDEO_CHROMA_SUBSAMPLING_420_BIT_KHR, "4:2:0"}, - {VK_VIDEO_CHROMA_SUBSAMPLING_422_BIT_KHR, "4:2:2"}, - {VK_VIDEO_CHROMA_SUBSAMPLING_444_BIT_KHR, "4:4:4"}, - {VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR, "monochrome"} - }; - - struct BitDepthInfo { - VkVideoComponentBitDepthFlagsKHR value; - const char* name; - }; - const std::vector bit_depth_list = { - {VK_VIDEO_COMPONENT_BIT_DEPTH_8_BIT_KHR, "8"}, - {VK_VIDEO_COMPONENT_BIT_DEPTH_10_BIT_KHR, "10"}, - {VK_VIDEO_COMPONENT_BIT_DEPTH_12_BIT_KHR, "12"} - }; - - auto find_caps_struct = [](const VkVideoCapabilitiesKHR &capabilities, VkStructureType stype) -> const VkBaseInStructure* { - auto p = reinterpret_cast(&capabilities); - while (p != nullptr) { - if (p->sType == stype) { - return p; - } - p = p->pNext; - } - return nullptr; - }; - - auto base_format = [] - (const ChromaSubsamplingInfo &chroma_subsampling, const BitDepthInfo &luma_bit_depth, const BitDepthInfo &chroma_bit_depth) { - std::string result{}; - result += " ("; - result += chroma_subsampling.name; - result += " "; - result += luma_bit_depth.name; - if (luma_bit_depth.value != chroma_bit_depth.value) { - result += ":"; - result += chroma_bit_depth.name; - } - result += "-bit)"; - return result; - }; - - auto add_profile = [&]( - const std::string &name, - const VkVideoProfileInfoKHR &profile_info, - AppVideoProfile::CreateProfileInfoChainCb create_profile_info_chain, - AppVideoProfile::CreateCapabilitiesChainCb create_capabilities_chain, - const AppVideoProfile::CreateFormatPropertiesChainCbList &create_format_properties_chain_list, - AppVideoProfile::InitProfileCb init_profile) { - auto profile = std::make_unique(gpu, gpu.phys_device, - name, profile_info, - create_profile_info_chain, - create_capabilities_chain, - create_format_properties_chain_list, - init_profile); - if (profile->supported) { - result.push_back(std::move(profile)); - } - }; -''' - - # Generate individual video profiles from the video codec metadata - for videoCodec in videoCodecs.values(): - # Ignore video codec categories - if videoCodec.value is None: - continue - - out += '\n' - out += GetTypesPrecondition(videoCodec.profileStructs, 4) - out += f'{" " * 8}const std::string codec_name = "{videoCodec.name}";\n' - - out += ''' - for (auto chroma_subsampling : chroma_subsampling_list) { - for (auto luma_bit_depth : bit_depth_list) { - for (auto chroma_bit_depth : bit_depth_list) { - if (chroma_subsampling.value == VK_VIDEO_CHROMA_SUBSAMPLING_MONOCHROME_BIT_KHR && luma_bit_depth.value != chroma_bit_depth.value) { - // Ignore the chroma bit depth dimension for monochrome - continue; - } - - std::string profile_base_name = codec_name + base_format(chroma_subsampling, luma_bit_depth, chroma_bit_depth); -''' - - # Setup video profile info - out += f'{" " * 20}VkVideoProfileInfoKHR profile_info{{\n' - out += f'{" " * 20} VK_STRUCTURE_TYPE_VIDEO_PROFILE_INFO_KHR,\n' - out += f'{" " * 20} nullptr,\n' - out += f'{" " * 20} {videoCodec.value},\n' - out += f'{" " * 20} chroma_subsampling.value,\n' - out += f'{" " * 20} luma_bit_depth.value,\n' - out += f'{" " * 20} chroma_bit_depth.value\n' - out += f'{" " * 20}}};\n\n' - - # Setup video profile info chain creation callback - out += f'{" " * 20}auto create_profile_info_chain = [&](const void **ppnext) -> std::unique_ptr {{\n' - out += f'{" " * 20} auto profile_info_chain = std::make_unique();\n' - for profileStruct in videoCodec.profileStructs: - structDef = GetStructDef(profileStruct) - out += AddGuardHeader(structDef) - out += f'{" " * 24}if (profile_info_chain != nullptr) {{\n' - out += f'{" " * 28}profile_info_chain->{profileStruct[2:]}.sType = {structDef.sTypeName};\n' - out += f'{" " * 28}profile_info_chain->{profileStruct[2:]}.pNext = nullptr;\n' - out += f'{" " * 28}*ppnext = &profile_info_chain->{profileStruct[2:]};\n' - out += f'{" " * 28}ppnext = &profile_info_chain->{profileStruct[2:]}.pNext;\n' - out += f'{" " * 24}}}\n' - if structDef.guard: - out += f'#else\n{" " * 20}profile_info_chain = nullptr;\n' - out += AddGuardFooter(structDef) - out += f'{" " * 20} return profile_info_chain;\n' - out += f'{" " * 20}}};\n\n' - - # Setup video capabilities chain creation callback - out += f'{" " * 20}auto create_capabilities_chain = [&](void **ppnext) -> std::unique_ptr {{\n' - out += f'{" " * 20} auto capabilities_chain = std::make_unique();\n' - for capabilities in videoCodec.capabilities: - structDef = GetStructDef(capabilities) - out += AddGuardHeader(structDef) - out += f'{" " * 24}if (capabilities_chain != nullptr) {{\n' - out += GetTypesPrecondition([capabilities], 28) - out += f'{" " * 32}capabilities_chain->{capabilities[2:]}.sType = {structDef.sTypeName};\n' - out += f'{" " * 32}capabilities_chain->{capabilities[2:]}.pNext = nullptr;\n' - out += f'{" " * 32}*ppnext = &capabilities_chain->{capabilities[2:]};\n' - out += f'{" " * 32}ppnext = &capabilities_chain->{capabilities[2:]}.pNext;\n' - out += f'{" " * 28}}}\n' - out += f'{" " * 24}}}\n' - out += AddGuardFooter(structDef) - out += f'{" " * 20} return capabilities_chain;\n' - out += f'{" " * 20}}};\n\n' - - # Setup video format properties chain creation callbacks - out += f'{" " * 20}const AppVideoProfile::CreateFormatPropertiesChainCbList create_format_properties_chain_list = {{\n' - for format in videoCodec.formats.values(): - out += f'{" " * 24}AppVideoProfile::CreateFormatPropertiesChainCb {{\n' - out += f'{" " * 28}"{format.name}",\n' - out += f'{" " * 28}{format.usage.replace("+", " | ")},\n' - - # Callback to check required capabilities - out += f'{" " * 28}[&](const VkVideoCapabilitiesKHR &capabilities) -> bool {{\n' - out += f'{" " * 28} bool supported = true;\n' - for requiredCap in format.requiredCaps: - structDef = GetStructDef(requiredCap.struct) - out += AddGuardHeader(structDef) - out += GetTypesPrecondition([requiredCap.struct], 32) - out += f'{" " * 32} auto caps = reinterpret_cast(find_caps_struct(capabilities, {structDef.sTypeName}));\n' - out += f'{" " * 32} if (caps != nullptr) {{\n' - out += f'{" " * 32} supported = supported && {GetRequiredCapsCondition(requiredCap.struct, requiredCap.member, f"caps->{requiredCap.member}", requiredCap.value)};\n' - out += f'{" " * 32} }} else {{\n' - out += f'{" " * 32} supported = false;\n' - out += f'{" " * 32} }}\n' - out += f'{" " * 32}}} else {{\n' - out += f'{" " * 32} supported = false;\n' - out += f'{" " * 32}}}\n' - if structDef.guard: - out += f'#else\n{" " * 32}supported = false;\n' - out += AddGuardFooter(structDef) - out += f'{" " * 28} return supported;\n' - out += f'{" " * 28}}},\n' - - # Callback to create video format properties chain - out += f'{" " * 28}[&](void **ppnext) -> std::unique_ptr {{\n' - out += f'{" " * 28} auto format_properties_chain = std::make_unique();\n' - for formatProps in format.properties: - structDef = GetStructDef(formatProps) - out += AddGuardHeader(structDef) - out += f'{" " * 32}if (format_properties_chain != nullptr) {{\n' - out += GetTypesPrecondition([formatProps], 36) - out += f'{" " * 40}format_properties_chain->{formatProps[2:]}.sType = {structDef.sTypeName};\n' - out += f'{" " * 40}format_properties_chain->{formatProps[2:]}.pNext = nullptr;\n' - out += f'{" " * 40}*ppnext = &format_properties_chain->{formatProps[2:]};\n' - out += f'{" " * 40}ppnext = &format_properties_chain->{formatProps[2:]}.pNext;\n' - out += f'{" " * 36}}}\n' - out += f'{" " * 32}}}\n' - out += AddGuardFooter(structDef) - out += f'{" " * 28} return format_properties_chain;\n' - out += f'{" " * 28}}},\n' - - out += f'{" " * 24}}},\n' - out += f'{" " * 20}}};\n\n' - - # Permute profiles for each profile struct member value - profiles = {'': []} - for profileStruct in videoCodec.profileStructs.values(): - for profileStructMember in profileStruct.members.values(): - newProfiles = {} - for profileStructMemberValue, profileStructMemberName in profileStructMember.values.items(): - for profileName, profile in profiles.items(): - # Only add video profile name suffix to the full descriptive name if not empty to avoid excess whitespace - newProfileName = profileName if profileStructMemberName == '' else f'{profileName} {profileStructMemberName}' - newProfiles[newProfileName] = profile + [{ - "struct": profileStruct.struct, - "member": profileStructMember.name, - "value": profileStructMemberValue - }] - profiles = newProfiles - - for profileName, profile in profiles.items(): - out += f'{" " * 20}add_profile(profile_base_name + "{profileName}", profile_info,\n' - out += f'{" " * 20} create_profile_info_chain, create_capabilities_chain,\n' - out += f'{" " * 20} create_format_properties_chain_list,\n' - out += f'{" " * 20} [](AppVideoProfile& profile) {{\n' - for profileStruct in videoCodec.profileStructs: - structDef = GetStructDef(profileStruct) - out += AddGuardHeader(structDef) - for elem in profile: - if elem['struct'] == profileStruct: - out += f'{" " * 24}profile.profile_info_chain->{elem["struct"][2:]}.{elem["member"]} = {elem["value"]};\n' - out += AddGuardFooter(structDef) - out += f'{" " * 20}}});\n' - - out += f'{" " * 16}}}\n' - out += f'{" " * 12}}}\n' - out += f'{" " * 8}}}\n' - out += f'{" " * 4}}}\n' - - out += ' return result;\n' - out += '}\n\n' - - return out - - def genCmd(self, cmd, name, alias): - gen.OutputGenerator.genCmd(self, cmd, name, alias) - - # These are actually constants - def genEnum(self, enuminfo, name, alias): - gen.OutputGenerator.genEnum(self, enuminfo, name, alias) - - # These are actually enums - def genGroup(self, groupinfo, groupName, alias): - gen.OutputGenerator.genGroup(self, groupinfo, groupName, alias) - - if alias is not None: - if alias in self.aliases.keys(): - self.aliases[alias].append(groupName) - else: - self.aliases[alias] = [groupName, ] - return - - if groupinfo.elem.get('type') == 'bitmask': - self.bitmasks.append(VulkanBitmask(groupinfo.elem)) - elif groupinfo.elem.get('type') == 'enum': - self.enums.append(VulkanEnum(groupinfo.elem)) - - def genType(self, typeinfo, name, alias): - gen.OutputGenerator.genType(self, typeinfo, name, alias) - - if alias is not None: - if alias in self.aliases.keys(): - self.aliases[alias].append(name) - else: - self.aliases[alias] = [name, ] - return - - if typeinfo.elem.get('category') == 'bitmask': - self.flags.append(VulkanFlags(typeinfo.elem)) - - if typeinfo.elem.get('category') == 'struct': - self.all_structures.append(VulkanStructure( - name, typeinfo.elem, self.constants, self.extTypes)) - - is_vendor_type = False - for vendor in self.vendor_abbreviations: - for node in typeinfo.elem.findall('member'): - if node.get('values') is not None: - if node.get('values').find(vendor) != -1: - is_vendor_type = True - break - if is_vendor_type: - break - - for key, value in EXTENSION_CATEGORIES.items(): - if str(typeinfo.elem.get('structextends')).find(value.get('extends')) != -1: - if value.get('exclude') is None or name not in value.get('exclude'): - if not is_vendor_type or value.get('ignore_vendor_exclusion'): - self.extension_sets[key].add(name) - - # finds all the ranges of formats from core (1.0), core versions (1.1+), and extensions - def findFormatRanges(self): - for enums in self.registry.reg.findall('enums'): - if enums.get('name') == 'VkFormat': - min_val = 2**32 - max_val = 0 - for enum in enums.findall('enum'): - if enum.get('value') is None: - continue - value = int(enum.get('value')) - min_val = min(min_val, value) - max_val = max(max_val, value) - if min_val < 2**32 and max_val > 0: - self.format_ranges.append(VulkanFormatRange(0, None, min_val, max_val)) - - for feature in self.registry.reg.findall('feature'): - for require in feature.findall('require'): - comment = require.get('comment') - original_ext = None - if comment is not None and comment.find('Promoted from') >= 0: - # may need tweaking in the future - some ext names aren't just the upper case version - original_ext = comment.split(' ')[2].upper() + '_EXTENSION_NAME' - # insert an underscore before numbers in the name define - original_ext = re.sub(r'([A-Z])(\d+)', r'\1_\2', original_ext) - min_val = 2**32 - max_val = 0 - for enum in require.findall('enum'): - if enum.get('extends') == 'VkFormat': - value = CalcEnumValue(int(enum.get('extnumber')), int(enum.get('offset'))) - min_val = min(min_val, value) - max_val = max(max_val, value) - if min_val < 2**32 and max_val > 0: - self.format_ranges.append(VulkanFormatRange(feature.get('name').replace('_VERSION_', '_API_VERSION_'), None, min_val, max_val)) - # If the formats came from an extension, add a format range for that extension so it'll be printed if the ext is supported but not the core version - if original_ext is not None: - self.format_ranges.append(VulkanFormatRange(0, original_ext, min_val, max_val)) - - for extension in self.registry.reg.find('extensions').findall('extension'): - if not self.genOpts.apiname in extension.get('supported').split(','): - continue - - min_val = 2**32 - max_val = 0 - enum_name_string = '' - for require in extension.findall('require'): - for enum in require.findall('enum'): - if enum.get('value') is not None and enum.get('value').find(extension.get('name')): - enum_name_string = enum.get('name') - if enum.get('extends') == 'VkFormat': - if enum.get('offset') is None: - continue - value = CalcEnumValue(int(extension.get('number')), int(enum.get('offset'))) - min_val = min(min_val, value) - max_val = max(max_val, value) - if min_val < 2**32 and max_val > 0: - self.format_ranges.append(VulkanFormatRange(0, enum_name_string, min_val, max_val)) - - - -def GatherTypesToGen(structure_list, structures, exclude = None): - if exclude is None: - exclude = [] - types = set() - for s in structures: - types.add(s) - added_stuff = True # repeat until no new types are added - while added_stuff is True: - added_stuff = False - for s in structure_list: - if s.name in types: - for m in s.members: - if m.typeID not in PREDEFINED_TYPES and m.name not in NAMES_TO_IGNORE: - if m.typeID not in types: - if s.name not in exclude: - types.add(m.typeID) - added_stuff = True - return types - - -def GetExtension(name, generator): - if name in generator.extFuncs: - return generator.extFuncs[name] - elif name in generator.extTypes: - return generator.extTypes[name][0] - else: - return None - - -def AddGuardHeader(obj): - if obj is not None and obj.guard is not None: - return f'#ifdef {obj.guard}\n' - else: - return '' - - -def AddGuardFooter(obj): - if obj is not None and obj.guard is not None: - return f'#endif // {obj.guard}\n' - else: - return '' - -def CalcEnumValue(num, offset): - base = 1000000000 - block_size = 1000 - return base + (num - 1) * block_size + offset - -def PrintEnumToString(enum, generator): - out = '' - out += AddGuardHeader(GetExtension(enum.name, generator)) - out += f'std::string {enum.name}String({enum.name} value) {{\n' - out += ' switch (value) {\n' - for v in enum.options: - out += f' case ({v.name}): return "{v.name[3:]}";\n' - out += f' default: return std::string("UNKNOWN_{enum.name}_value") + std::to_string(value);\n' - out += ' }\n}\n' - out += AddGuardFooter(GetExtension(enum.name, generator)) - return out - - -def PrintEnum(enum, generator): - out = '' - out += AddGuardHeader(GetExtension(enum.name, generator)) - out += f'''void Dump{enum.name}(Printer &p, std::string name, {enum.name} value) {{ - if (p.Type() == OutputType::json) - p.PrintKeyString(name, std::string("VK_") + {enum.name}String(value)); - else - p.PrintKeyString(name, {enum.name}String(value)); -}} -''' - out += AddGuardFooter(GetExtension(enum.name, generator)) - return out - - -def PrintGetFlagStrings(name, bitmask): - out = '' - out += f'std::vector {name}GetStrings({name} value) {{\n' - out += ' std::vector strings;\n' - # If a bitmask contains a field whose value is zero, we want to support printing the correct bitflag - # Otherwise, use "None" for when there are not bits set in the bitmask - if bitmask.options[0].value != 0: - out += ' if (value == 0) { strings.push_back("None"); return strings; }\n' - else: - out += f' if (value == 0) {{ strings.push_back("{bitmask.options[0].name[3:]}"); return strings; }}\n' - for v in bitmask.options: - # only check single-bit flags - if v.value != 0 and (v.value & (v.value - 1)) == 0: - out += f' if ({v.name} & value) strings.push_back("{v.name[3:]}");\n' - out += ' return strings;\n}\n' - return out - - -def PrintFlags(bitmask, name): - out = f'void Dump{name}(Printer &p, std::string name, {name} value) {{\n' - out += f''' if (static_cast<{bitmask.name}>(value) == 0) {{ - ArrayWrapper arr(p, name, 0); - if (p.Type() != OutputType::json && p.Type() != OutputType::vkconfig_output) - p.SetAsType().PrintString("None"); - return; - }} - auto strings = {bitmask.name}GetStrings(static_cast<{bitmask.name}>(value)); - ArrayWrapper arr(p, name, strings.size()); - for(auto& str : strings){{ - if (p.Type() == OutputType::json) - p.SetAsType().PrintString(std::string("VK_") + str); - else - p.SetAsType().PrintString(str); - }} -}} -''' - return out - - -def PrintFlagBits(bitmask): - return f'''void Dump{bitmask.name}(Printer &p, std::string name, {bitmask.name} value) {{ - auto strings = {bitmask.name}GetStrings(value); - if (strings.size() > 0) {{ - if (p.Type() == OutputType::json) - p.PrintKeyString(name, std::string("VK_") + strings.at(0)); - else - p.PrintKeyString(name, strings.at(0)); - }} -}} -''' - - - -def PrintBitMask(bitmask, name, generator): - out = PrintGetFlagStrings(bitmask.name, bitmask) - out += AddGuardHeader(GetExtension(bitmask.name, generator)) - out += PrintFlags(bitmask, name) - out += PrintFlagBits(bitmask) - out += AddGuardFooter(GetExtension(bitmask.name, generator)) - out += '\n' - return out - - -def PrintBitMaskToString(bitmask, name, generator): - out = AddGuardHeader(GetExtension(bitmask.name, generator)) - out += f'std::string {name}String({name} value) {{\n' - out += ' std::string out;\n' - out += ' bool is_first = true;\n' - for v in bitmask.options: - out += f' if ({v.name} & value) {{\n' - out += ' if (is_first) { is_first = false; } else { out += " | "; }\n' - out += f' out += "{str(v.name)[3:]}";\n' - out += ' }\n' - out += ' return out;\n' - out += '}\n' - out += AddGuardFooter(GetExtension(bitmask.name, generator)) - return out - - -def PrintStructure(struct): - if len(struct.members) == 0: - return '' - out = '' - out += AddGuardHeader(struct) - max_key_len = 0 - for v in struct.members: - if v.arrayLength is not None: - if len(v.name) + len(v.arrayLength) + 2 > max_key_len: - max_key_len = len(v.name) + len(v.arrayLength) + 2 - elif v.typeID in PREDEFINED_TYPES or v.typeID in STRUCT_BLACKLIST: - if len(v.name) > max_key_len: - max_key_len = len(v.name) - - out += f'void Dump{struct.name}(Printer &p, std::string name, const {struct.name} &obj) {{\n' - if struct.name == 'VkPhysicalDeviceLimits': - out += ' if (p.Type() == OutputType::json)\n' - out += ' p.ObjectStart("limits");\n' - out += ' else\n' - out += ' p.SetSubHeader().ObjectStart(name);\n' - elif struct.name == 'VkPhysicalDeviceSparseProperties': - out += ' if (p.Type() == OutputType::json)\n' - out += ' p.ObjectStart("sparseProperties");\n' - out += ' else\n' - out += ' p.SetSubHeader().ObjectStart(name);\n' - else: - out += ' ObjectWrapper object{p, name};\n' - if max_key_len > 0: - out += f' p.SetMinKeyWidth({max_key_len});\n' - for v in struct.members: - # arrays - if v.arrayLength is not None: - # strings - if v.typeID == 'char': - out += f' p.PrintKeyString("{v.name}", obj.{v.name});\n' - # uuid's - elif v.typeID == 'uint8_t' and (v.arrayLength == '8' or v.arrayLength == '16'): # VK_UUID_SIZE - if v.arrayLength == '8': - out += ' if (obj.deviceLUIDValid) { // special case\n' - out += f' p.PrintKeyValue("{v.name}", obj.{v.name});\n' - if v.arrayLength == '8': - out += ' }\n' - elif struct.name == 'VkQueueFamilyGlobalPriorityProperties' and v.name == 'priorities': - out += f' ArrayWrapper arr(p,"{v.name}", obj.priorityCount);\n' - out += ' for (uint32_t i = 0; i < obj.priorityCount; i++) {\n' - out += ' if (p.Type() == OutputType::json)\n' - out += ' p.PrintString(std::string("VK_") + VkQueueGlobalPriorityString(obj.priorities[i]));\n' - out += ' else\n' - out += ' p.PrintString(VkQueueGlobalPriorityString(obj.priorities[i]));\n' - out += ' }\n' - elif v.arrayLength.isdigit(): - out += f' {{\n ArrayWrapper arr(p,"{v.name}", ' + v.arrayLength + ');\n' - out += f' for (uint32_t i = 0; i < {v.arrayLength}; i++) {{ p.PrintElement(obj.{v.name}[i]); }}\n' - out += ' }\n' - else: # dynamic array length based on other member - out += f' if (obj.{v.arrayLength} == 0 || obj.{v.name} == nullptr) {{\n' - out += f' p.PrintKeyString("{v.name}", "NULL");\n' - out += ' } else {\n' - out += f' ArrayWrapper arr(p,"{v.name}", obj.{v.arrayLength});\n' - out += f' for (uint32_t i = 0; i < obj.{v.arrayLength}; i++) {{\n' - out += f' Dump{v.typeID}(p, std::to_string(i), obj.{v.name}[i]);\n' - out += ' }\n' - out += ' }\n' - elif v.typeID == 'VkBool32': - out += f' p.PrintKeyBool("{v.name}", static_cast(obj.{v.name}));\n' - elif v.typeID == 'uint8_t': - out += f' p.PrintKeyValue("{v.name}", static_cast(obj.{v.name}));\n' - elif v.typeID == 'VkDeviceSize' or (v.typeID == 'uint32_t' and v.name in ['vendorID', 'deviceID']): - out += f' p.PrintKeyValue("{v.name}", to_hex_str(p, obj.{v.name}));\n' - elif v.typeID in PREDEFINED_TYPES: - out += f' p.PrintKeyValue("{v.name}", obj.{v.name});\n' - elif v.name not in NAMES_TO_IGNORE: - # if it is an enum/flag/bitmask - if v.typeID in ['VkFormatFeatureFlags', 'VkFormatFeatureFlags2']: - out += ' p.SetOpenDetails();\n' # special case so that feature flags are open in html output - out += f' Dump{v.typeID}(p, "{v.name}", obj.{v.name});\n' - - if struct.name in ['VkPhysicalDeviceLimits', 'VkPhysicalDeviceSparseProperties']: - out += ' p.ObjectEnd();\n' - out += '}\n' - - out += AddGuardFooter(struct) - return out - - -def PrintStructShort(struct): - out = '' - out += AddGuardHeader(struct) - out += f'std::ostream &operator<<(std::ostream &o, {struct.name} &obj) {{\n' - out += ' return o << "(" << ' - - first = True - for v in struct.members: - if first: - first = False - out += f'obj.{v.name} << ' - else: - out += f'\',\' << obj.{v.name} << ' - out += '")";\n' - out += '}\n' - out += AddGuardFooter(struct) - return out - -def PrintChainStruct(listName, structures, all_structures, chain_details, extTypes, aliases, vulkan_versions): - sorted_structures = sorted( - all_structures, key=operator.attrgetter('name')) - - version_desc = '' - if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: - version_desc = 'gpu.api_version' - else: - version_desc = 'inst.instance_version' - - out = '' - structs_to_print = [] - for s in sorted_structures: - if s.name in structures: - structs_to_print.append(s) - # use default constructor and delete copy & move operators - out += f'''struct {listName}_chain {{ - {listName}_chain() = default; - {listName}_chain(const {listName}_chain &) = delete; - {listName}_chain& operator=(const {listName}_chain &) = delete; - {listName}_chain({listName}_chain &&) = delete; - {listName}_chain& operator=({listName}_chain &&) = delete; -''' - - out += ' void* start_of_chain = nullptr;\n' - for s in structs_to_print: - if s.name in STRUCT_BLACKLIST: - continue - out += AddGuardHeader(s) - if s.sTypeName is not None: - out += f' {s.name} {s.name[2:]}{{}};\n' - # Specific versions of drivers have an incorrect definition of the size of these structs. - # We need to artificially pad the structure it just so the driver doesn't write out of bounds and - # into other structures that are adjacent. This bug comes from the in-development version of - # the extension having a larger size than the final version, so older drivers try to write to - # members which don't exist. - if s.name in ['VkPhysicalDeviceShaderIntegerDotProductFeatures', 'VkPhysicalDeviceHostImageCopyFeaturesEXT']: - out += f' char {s.name}_padding[64];\n' - if s.hasLengthmember: - for member in s.members: - if member.lengthMember: - out += f' std::vector<{member.typeID}> {s.name}_{member.name};\n' - out += AddGuardFooter(s) - out += ' void initialize_chain(' - if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: - out += 'AppInstance &inst, ' - if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: - out += 'AppGpu &gpu ' - if chain_details.get('can_show_promoted_structs'): - out += ', bool show_promoted_structs' - out += ') noexcept {\n' - for s in structs_to_print: - if s.name in STRUCT_BLACKLIST: - continue - out += AddGuardHeader(s) - out += f' {s.name[2:]}.sType = {s.sTypeName};\n' - out += AddGuardFooter(s) - - - out += ' std::vector chain_members{};\n' - for s in structs_to_print: - if s.name in STRUCT_BLACKLIST: - continue - out += AddGuardHeader(s) - extEnables = {} - for k, elem in extTypes.items(): - if k == s.name or (s.name in aliases.keys() and k in aliases[s.name]): - for e in elem: - extEnables[e.extNameStr] = e.type - - version = None - oldVersionName = None - for v in vulkan_versions: - if s.name in v.names: - version = v - if s.name in aliases.keys(): - for alias in aliases[s.name]: - oldVersionName = alias - - has_version = version is not None - has_extNameStr = len(extEnables) > 0 or s.name in aliases.keys() - if has_version or has_extNameStr: - out += ' if (' - has_printed_condition = False - if has_extNameStr: - for key, value in extEnables.items(): - if has_printed_condition: - out += '\n || ' - else: - has_printed_condition = True - if has_version: - out += '(' - if value == EXTENSION_TYPE_DEVICE: - out += f'gpu.CheckPhysicalDeviceExtensionIncluded({key})' - elif value == EXTENSION_TYPE_INSTANCE: - out += f'inst.CheckExtensionEnabled({key})' - else: - assert False, 'Should never get here' - if has_version: - str_show_promoted_structs = '|| show_promoted_structs' if chain_details.get('can_show_promoted_structs') else '' - if s.name in STRUCT_1_1_LIST: - out += f'{version_desc} == {version.constant} {str_show_promoted_structs}' - elif has_printed_condition: - out += f')\n && ({version_desc} < {version.constant} {str_show_promoted_structs})' - else: - out += f'({version_desc} >= {version.constant})' - out += ')\n ' - else: - out += ' ' - out += f'chain_members.push_back(reinterpret_cast(&{s.name[2:]}));\n' - out += AddGuardFooter(s) - chain_param_list = [] - chain_arg_list = [] - if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: - chain_param_list.append('AppInstance &inst') - chain_arg_list.append('inst') - if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: - chain_param_list.append('AppGpu &gpu') - chain_arg_list.append('gpu') - if chain_details.get('can_show_promoted_structs'): - chain_param_list.append('bool show_promoted_structs') - chain_arg_list.append('show_promoted_structs') - - out += f''' - if (!chain_members.empty()) {{ - for(size_t i = 0; i < chain_members.size() - 1; i++){{ - chain_members[i]->pNext = chain_members[i + 1]; - }} - start_of_chain = chain_members[0]; - }} - }} -}}; -void setup_{listName}_chain({chain_details['holder_type']}& start, std::unique_ptr<{listName}_chain>& chain, {','.join(chain_param_list)}){{ - chain = std::unique_ptr<{listName}_chain>(new {listName}_chain()); - chain->initialize_chain({','.join(chain_arg_list)}); - start.pNext = chain->start_of_chain; -}}; -''' - if chain_details.get('print_iterator'): - out += '\n' - out += f'void chain_iterator_{listName}(Printer &p, ' - if chain_details.get('type') in [EXTENSION_TYPE_INSTANCE, EXTENSION_TYPE_BOTH]: - out += 'AppInstance &inst, ' - if chain_details.get('type') in [EXTENSION_TYPE_DEVICE, EXTENSION_TYPE_BOTH]: - out += 'AppGpu &gpu, ' - if chain_details.get('can_show_promoted_structs'): - out += 'bool show_promoted_structs, ' - out += 'const void * place) {\n' - out += ' while (place) {\n' - out += ' const VkBaseOutStructure *structure = (const VkBaseOutStructure *)place;\n' - out += ' p.SetSubHeader();\n' - - for s in sorted_structures: - if s.sTypeName is None or s.name in STRUCT_BLACKLIST: - continue - - extEnables = {} - for k, elem in extTypes.items(): - if k == s.name or (s.name in aliases.keys() and k in aliases[s.name]): - for e in elem: - extEnables[e.extNameStr] = e.type - - version = None - oldVersionName = None - for v in vulkan_versions: - if s.name in v.names: - version = v - if s.name in aliases.keys(): - for alias in aliases[s.name]: - oldVersionName = alias - - if s.name in structures: - out += AddGuardHeader(s) - out += f' if (structure->sType == {s.sTypeName}' - if s.name in PORTABILITY_STRUCTS: - out += ' && p.Type() != OutputType::json' - has_version = version is not None - has_extNameStr = len(extEnables) > 0 or s.name in aliases.keys() - out += ') {\n' - out += f' const {s.name}* props = (const {s.name}*)structure;\n' - out += f' Dump{s.name}(p, ' - if s.name in aliases.keys() and version is not None: - out += f'{version_desc} >= {version.constant} ?"{s.name}":"{oldVersionName}"' - else: - out += f'"{s.name}"' - out += ', *props);\n' - out += ' p.AddNewline();\n' - out += ' }\n' - out += AddGuardFooter(s) - out += ' place = structure->pNext;\n' - out += ' }\n' - out += '}\n' - - out += '\n' - out += f'bool prepare_{listName}_twocall_chain_vectors(std::unique_ptr<{listName}_chain>& chain) {{\n' - out += ' (void)chain;\n' - is_twocall = False - for s in structs_to_print: - if not s.hasLengthmember: - continue - if s.name in STRUCT_BLACKLIST: - continue - out += AddGuardHeader(s) - for member in s.members: - if member.lengthMember: - out += f' chain->{s.name}_{member.name}.resize(chain->{s.name[2:]}.{member.arrayLength});\n' - out += f' chain->{s.name[2:]}.{member.name} = chain->{s.name}_{member.name}.data();\n' - out += AddGuardFooter(s) - is_twocall = True - out += f' return {"true" if is_twocall else "false"};\n' - out += '}\n' - - return out - - -def PrintStructComparisonForwardDecl(structure): - out = '' - out += f'bool operator==(const {structure.name} & a, const {structure.name} b);\n' - return out - - -def PrintStructComparison(structure): - out = '' - out += f'bool operator==(const {structure.name} & a, const {structure.name} b) {{\n' - out += ' return ' - is_first = True - for m in structure.members: - if m.name not in NAMES_TO_IGNORE: - if not is_first: - out += '\n && ' - else: - is_first = False - out += f'a.{m.name} == b.{m.name}' - out += ';\n' - out += '}\n' - return out - - -class VulkanEnum: - class Option: - - def __init__(self, name, value, bitpos, comment): - self.name = name - self.comment = comment - - if bitpos is not None: - value = 1 << int(bitpos) - elif isinstance(value, str): - if value.lower().startswith('0x'): - value = int(value, 16) - else: - value = int(value) - - self.value = value - - def values(self): - return { - 'optName': self.name, - 'optValue': self.value, - 'optComment': self.comment, - } - - def __init__(self, rootNode): - self.name = rootNode.get('name') - self.type = rootNode.get('type') - self.options = [] - - for child in rootNode: - childName = child.get('name') - childValue = child.get('value') - childBitpos = child.get('bitpos') - childComment = child.get('comment') - childExtends = child.get('extends') - childOffset = child.get('offset') - childExtNum = child.get('extnumber') - support = child.get('supported') - if support == 'disabled': - continue - - if childName is None: - continue - if childValue is None and childBitpos is None and childOffset is None: - continue - - if childExtends is not None and childExtNum is not None and childOffset is not None: - childValue = CalcEnumValue(int(childExtNum), int(childOffset)) - if 'dir' in child.keys(): - childValue = -childValue - duplicate = False - for o in self.options: - if o.values()['optName'] == childName: - duplicate = True - if duplicate: - continue - - self.options.append(VulkanEnum.Option( - childName, childValue, childBitpos, childComment)) - - -class VulkanBitmask: - - def __init__(self, rootNode): - self.name = rootNode.get('name') - self.type = rootNode.get('type') - - # Read each value that the enum contains - self.options = [] - for child in rootNode: - childName = child.get('name') - childValue = child.get('value') - childBitpos = child.get('bitpos') - childComment = child.get('comment') - support = child.get('supported') - if childName is None or (childValue is None and childBitpos is None): - continue - if support == 'disabled': - continue - - duplicate = False - for option in self.options: - if option.name == childName: - duplicate = True - if duplicate: - continue - - self.options.append(VulkanEnum.Option( - childName, childValue, childBitpos, childComment)) - - -class VulkanFlags: - - def __init__(self, rootNode): - self.name = rootNode.get('name') - self.type = rootNode.get('type') - self.enum = rootNode.get('requires') - # 64 bit flags use bitvalues, not requires - if self.enum is None: - self.enum = rootNode.get('bitvalues') - - -class VulkanVariable: - def __init__(self, rootNode, constants): - self.name = rootNode.find('name').text - # Typename, dereferenced and converted to a useable C++ token - self.typeID = rootNode.find('type').text - self.baseType = self.typeID - self.childType = None - self.arrayLength = None - self.text = '' - for node in rootNode.itertext(): - comment = rootNode.find('comment') - if comment is not None and comment.text == node: - continue - self.text += node - - typeMatch = re.search('.+?(?=' + self.name + ')', self.text) - self.type = typeMatch.string[typeMatch.start():typeMatch.end()] - self.type = ' '.join(self.type.split()) - bracketMatch = re.search('(?<=\\[)[a-zA-Z0-9_]+(?=\\])', self.text) - if bracketMatch is not None: - matchText = bracketMatch.string[bracketMatch.start( - ):bracketMatch.end()] - self.childType = self.type - self.type += '[' + matchText + ']' - if matchText in constants: - self.arrayLength = constants[matchText] - else: - self.arrayLength = matchText - - self.lengthMember = False - lengthString = rootNode.get('len') - lengths = [] - if lengthString is not None: - lengths = re.split(',', lengthString) - lengths = list(filter(('null-terminated').__ne__, lengths)) - if self.arrayLength is None and len(lengths) > 0: - self.childType = '*'.join(self.type.split('*')[0:-1]) - self.arrayLength = lengths[0] - self.lengthMember = True - if self.arrayLength is not None and self.arrayLength.startswith('latexmath'): - code = self.arrayLength[10:len(self.arrayLength)] - code = re.sub('\\[', '', code) - code = re.sub('\\]', '', code) - code = re.sub('\\\\(lceil|rceil)', '', code) - code = re.sub('{|}', '', code) - code = re.sub('\\\\mathit', '', code) - code = re.sub('\\\\over', '/', code) - code = re.sub('\\\\textrm', '', code) - self.arrayLength = code - - # Dereference if necessary and handle members of variables - if self.arrayLength is not None: - self.arrayLength = re.sub('::', '->', self.arrayLength) - sections = self.arrayLength.split('->') - if sections[-1][0] == 'p' and sections[0][1].isupper(): - self.arrayLength = '*' + self.arrayLength - - -class VulkanStructure: - def __init__(self, name, rootNode, constants, extTypes): - self.name = name - self.members = [] - self.guard = None - self.sTypeName = None - self.extendsStruct = rootNode.get('structextends') - self.hasLengthmember = False - - for node in rootNode.findall('member'): - if node.get('values') is not None: - self.sTypeName = node.get('values') - self.members.append(VulkanVariable(node, constants)) - - for member in self.members: - if member.lengthMember: - self.hasLengthmember = True - break - - for k, elem in extTypes.items(): - if k == self.name: - for e in elem: - if e.guard is not None: - self.guard = e.guard - - -class VulkanExtension: - def __init__(self, rootNode): - self.name = rootNode.get('name') - self.number = int(rootNode.get('number')) - self.type = rootNode.get('type') - self.dependency = rootNode.get('requires') - self.guard = GetFeatureProtect(rootNode) - self.supported = rootNode.get('supported') - self.extNameStr = None - self.vktypes = [] - self.vkfuncs = [] - self.constants = OrderedDict() - self.enumValues = OrderedDict() - self.node = rootNode - - for req in rootNode.findall('require'): - for ty in req.findall('type'): - self.vktypes.append(ty.get('name')) - - for func in req.findall('command'): - self.vkfuncs.append(func.get('name')) - - for enum in req.findall('enum'): - base = enum.get('extends') - name = enum.get('name') - value = enum.get('value') - bitpos = enum.get('bitpos') - offset = enum.get('offset') - # gets the VK_XXX_EXTENSION_NAME string - if value == f'"{self.name}"': - self.extNameStr = name - - if value is None and bitpos is not None: - value = 1 << int(bitpos) - - if offset is not None: - offset = int(offset) - if base is not None and offset is not None: - enumValue = 1000000000 + 1000*(self.number - 1) + offset - if enum.get('dir') == '-': - enumValue = -enumValue - self.enumValues[base] = (name, enumValue) - else: - self.constants[name] = value - - -class VulkanVersion: - def __init__(self, rootNode): - self.name = rootNode.get('name') - self.constant = self.name.replace('_VERSION_', '_API_VERSION_') - self.names = set() - - match = re.search(r"^[A-Z]+_VERSION_([1-9][0-9]*)_([0-9]+)$", self.name) - self.major = int(match.group(1)) - self.minor = int(match.group(2)) - - for req in rootNode.findall('require'): - for ty in req.findall('type'): - self.names.add(ty.get('name')) - for func in req.findall('command'): - self.names.add(func.get('name')) - for enum in req.findall('enum'): - self.names.add(enum.get('name')) - self.names = sorted(self.names) - -class VulkanFormatRange: - def __init__(self, min_inst_version, ext_name, first, last): - self.minimum_instance_version = min_inst_version - self.extension_name = ext_name - self.first_format = first - self.last_format = last - -class VulkanVideoRequiredCapabilities(): - def __init__(self, struct, member, value): - self.struct = struct - self.member = member - self.value = value - -class VulkanVideoFormat(): - def __init__(self, name, usage): - self.name = name - self.usage = usage - self.properties = OrderedDict() - self.requiredCaps = list() - super().__init__() - -class VulkanVideoProfileStructMember(): - def __init__(self, name): - self.name = name - self.values = OrderedDict() - -class VulkanVideoProfileStruct(): - def __init__(self, struct): - self.struct = struct - self.members = OrderedDict() - -class VulkanVideoCodec(): - def __init__(self, name, extend = None, value = None): - self.name = name - self.value = value - self.profileStructs = OrderedDict() - self.capabilities = OrderedDict() - self.formats = OrderedDict() - if extend is not None: - self.profileStructs = copy.deepcopy(extend.profileStructs) - self.capabilities = copy.deepcopy(extend.capabilities) - self.formats = copy.deepcopy(extend.formats) -- cgit v1.2.3