diff options
| -rw-r--r-- | demos/cube.c | 4 | ||||
| -rw-r--r-- | layers/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | layers/linux/VkLayer_unique_objects.json | 11 | ||||
| -rw-r--r-- | layers/unique_objects.h | 671 | ||||
| -rw-r--r-- | layers/windows/VkLayer_unique_objects.json | 11 | ||||
| -rwxr-xr-x | vk-layer-generate.py | 308 |
6 files changed, 993 insertions, 15 deletions
diff --git a/demos/cube.c b/demos/cube.c index f1202cbc..1f290ce6 100644 --- a/demos/cube.c +++ b/demos/cube.c @@ -2142,6 +2142,8 @@ static void demo_init_vk(struct demo *demo) "VK_LAYER_LUNARG_swapchain", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_image", + /* IMPORTANT : UniqueObjects should be at bottom of layer stack */ + "VK_LAYER_GOOGLE_unique_objects", }; char *device_validation_layers[] = { @@ -2153,6 +2155,8 @@ static void demo_init_vk(struct demo *demo) "VK_LAYER_LUNARG_swapchain", "VK_LAYER_LUNARG_device_limits", "VK_LAYER_LUNARG_image", + /* IMPORTANT : UniqueObjects should be at bottom of layer stack */ + "VK_LAYER_GOOGLE_unique_objects", }; /* Look for validation layers */ diff --git a/layers/CMakeLists.txt b/layers/CMakeLists.txt index 1c47165b..22994214 100644 --- a/layers/CMakeLists.txt +++ b/layers/CMakeLists.txt @@ -23,6 +23,7 @@ set(LAYER_JSON_FILES VkLayer_mem_tracker VkLayer_multi VkLayer_object_tracker + VkLayer_unique_objects VkLayer_param_checker VkLayer_screenshot VkLayer_swapchain @@ -129,6 +130,7 @@ run_vk_layer_generate(generic generic_layer.cpp) run_vk_layer_generate(api_dump api_dump.cpp) run_vk_layer_generate(object_tracker object_tracker.cpp) run_vk_layer_generate(threading threading.cpp) +run_vk_layer_generate(unique_objects unique_objects.cpp) add_library(layer_utils SHARED vk_layer_config.cpp vk_layer_extension_utils.cpp vk_layer_utils.cpp) if (WIN32) @@ -153,3 +155,4 @@ add_vk_layer(generic generic_layer.cpp vk_layer_table.cpp) add_vk_layer(api_dump api_dump.cpp vk_layer_table.cpp) add_vk_layer(object_tracker object_tracker.cpp vk_layer_table.cpp) add_vk_layer(threading threading.cpp vk_layer_table.cpp) +add_vk_layer(unique_objects unique_objects.cpp vk_layer_table.cpp) diff --git a/layers/linux/VkLayer_unique_objects.json b/layers/linux/VkLayer_unique_objects.json new file mode 100644 index 00000000..056ad7bd --- /dev/null +++ b/layers/linux/VkLayer_unique_objects.json @@ -0,0 +1,11 @@ +{ + "file_format_version" : "1.0.0", + "layer" : { + "name": "VK_LAYER_GOOGLE_unique_objects", + "type": "GLOBAL", + "library_path": "./libVkLayer_unique_objects.so", + "api_version": "0.210.0", + "implementation_version": "1", + "description": "Google Validation Layer" + } +} diff --git a/layers/unique_objects.h b/layers/unique_objects.h new file mode 100644 index 00000000..f12cf8c3 --- /dev/null +++ b/layers/unique_objects.h @@ -0,0 +1,671 @@ +/* + * + * Copyright (C) 2015 Google, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Author: Tobin Ehlis <tobine@google.com> + */ + +// CODEGEN : file vk-layer-generate.py line #1757 +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "vulkan/vulkan.h" +#include "vk_loader_platform.h" + +#include <vector> +#include <unordered_map> + +#include "vulkan/vk_layer.h" +#include "vk_layer_config.h" +//#include "vulkan/vk_lunarg_debug_report.h" +#include "vk_layer_table.h" +#include "vk_layer_data.h" +#include "vk_layer_logging.h" +#include "vk_layer_extension_utils.h" + +struct layer_data { + debug_report_data *report_data; + VkDebugReportCallbackEXT logging_callback; + bool wsi_enabled; + + layer_data() : + report_data(nullptr), + logging_callback(VK_NULL_HANDLE), + wsi_enabled(false) + {}; +}; + +struct instExts { + bool wsi_enabled; +}; + +static std::unordered_map<void*, struct instExts> instanceExtMap; +static std::unordered_map<void*, layer_data *> layer_data_map; +static device_table_map unique_objects_device_table_map; +static instance_table_map unique_objects_instance_table_map; +// Structure to wrap returned non-dispatchable objects to guarantee they have unique handles +// address of struct will be used as the unique handle +struct VkUniqueObject +{ + uint64_t actualObject; +}; + +static void +initUniqueObjects( + layer_data *my_data, + const VkAllocationCallbacks *pAllocator) +{ + uint32_t report_flags = 0; + uint32_t debug_action = 0; + FILE *log_output = NULL; + const char *option_str; + // initialize UniqueObjects options + report_flags = getLayerOptionFlags("UniqueObjectsReportFlags", 0); + getLayerOptionEnum("UniqueObjectsDebugAction", (uint32_t *) &debug_action); + + if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG) + { + option_str = getLayerOption("UniqueObjectsLogFilename"); + log_output = getLayerLogOutput(option_str, "UniqueObjects"); + VkDebugReportCallbackCreateInfoEXT dbgInfo; + memset(&dbgInfo, 0, sizeof(dbgInfo)); + dbgInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT; + dbgInfo.pfnCallback = log_callback; + dbgInfo.pUserData = log_output; + dbgInfo.flags = report_flags; + layer_create_msg_callback(my_data->report_data, &dbgInfo, pAllocator, &my_data->logging_callback); + } +} + +// Handle CreateInstance +static void createInstanceRegisterExtensions(const VkInstanceCreateInfo* pCreateInfo, VkInstance instance) +{ + uint32_t i; + VkLayerInstanceDispatchTable *pDisp = get_dispatch_table(unique_objects_instance_table_map, instance); + PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr; + pDisp->GetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR"); + pDisp->GetPhysicalDeviceSurfaceCapabilitiesKHR = (PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceCapabilitiesKHR"); + pDisp->GetPhysicalDeviceSurfaceFormatsKHR = (PFN_vkGetPhysicalDeviceSurfaceFormatsKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceFormatsKHR"); + pDisp->GetPhysicalDeviceSurfacePresentModesKHR = (PFN_vkGetPhysicalDeviceSurfacePresentModesKHR) gpa(instance, "vkGetPhysicalDeviceSurfacePresentModesKHR"); +#if VK_USE_PLATFORM_WIN32_KHR + pDisp->CreateWin32SurfaceKHR = (PFN_vkCreateWin32SurfaceKHR) gpa(instance, "vkCreateWin32SurfaceKHR"); + pDisp->GetPhysicalDeviceWin32PresentationSupportKHR = (PFN_vkGetPhysicalDeviceWin32PresentationSupportKHR) gpa(instance, "vkGetPhysicalDeviceWin32PresentationSupportKHR"); +#endif // VK_USE_PLATFORM_WIN32_KHR +#ifdef VK_USE_PLATFORM_XCB_KHR + pDisp->CreateXcbSurfaceKHR = (PFN_vkCreateXcbSurfaceKHR) gpa(instance, "vkCreateXcbSurfaceKHR"); + pDisp->GetPhysicalDeviceXcbPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXcbPresentationSupportKHR) gpa(instance, "vkGetPhysicalDeviceXcbPresentationSupportKHR"); +#endif // VK_USE_PLATFORM_XCB_KHR +#ifdef VK_USE_PLATFORM_XLIB_KHR + pDisp->CreateXlibSurfaceKHR = (PFN_vkCreateXlibSurfaceKHR) gpa(instance, "vkCreateXlibSurfaceKHR"); + pDisp->GetPhysicalDeviceXlibPresentationSupportKHR = (PFN_vkGetPhysicalDeviceXlibPresentationSupportKHR) gpa(instance, "vkGetPhysicalDeviceXlibPresentationSupportKHR"); +#endif // VK_USE_PLATFORM_XLIB_KHR +#ifdef VK_USE_PLATFORM_MIR_KHR + pDisp->CreateMirSurfaceKHR = (PFN_vkCreateMirSurfaceKHR) gpa(instance, "vkCreateMirSurfaceKHR"); + pDisp->GetPhysicalDeviceMirPresentationSupportKHR = (PFN_vkGetPhysicalDeviceMirPresentationSupportKHR) gpa(instance, "vkGetPhysicalDeviceMirPresentationSupportKHR"); +#endif // VK_USE_PLATFORM_MIR_KHR +#ifdef VK_USE_PLATFORM_WAYLAND_KHR + pDisp->CreateWaylandSurfaceKHR = (PFN_vkCreateWaylandSurfaceKHR) gpa(instance, "vkCreateWaylandSurfaceKHR"); + pDisp->GetPhysicalDeviceWaylandPresentationSupportKHR = (PFN_vkGetPhysicalDeviceWaylandPresentationSupportKHR) gpa(instance, "vkGetPhysicalDeviceWaylandPresentationSupportKHR"); +#endif // VK_USE_PLATFORM_WAYLAND_KHR +#ifdef VK_USE_PLATFORM_ANDROID_KHR + pDisp->CreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR) gpa(instance, "vkCreateAndroidSurfaceKHR"); +#endif // VK_USE_PLATFORM_ANDROID_KHR + + instanceExtMap[pDisp].wsi_enabled = false; + for (i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) { + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SURFACE_EXTENSION_NAME) == 0) + instanceExtMap[pDisp].wsi_enabled = true; + } +} + +VkResult +explicit_CreateInstance( + const VkInstanceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkInstance *pInstance) +{ + + VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(unique_objects_instance_table_map, *pInstance); + VkResult result = pInstanceTable->CreateInstance(pCreateInfo, pAllocator, pInstance); + + if (result == VK_SUCCESS) { + layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map); + my_data->report_data = debug_report_create_instance( + pInstanceTable, + *pInstance, + pCreateInfo->enabledExtensionNameCount, + pCreateInfo->ppEnabledExtensionNames); + createInstanceRegisterExtensions(pCreateInfo, *pInstance); + + initUniqueObjects(my_data, pAllocator); + } + return result; +} + +// Handle CreateDevice +static void createDeviceRegisterExtensions(const VkDeviceCreateInfo* pCreateInfo, VkDevice device) +{ + layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + VkLayerDispatchTable *pDisp = get_dispatch_table(unique_objects_device_table_map, device); + PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr; + pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) gpa(device, "vkCreateSwapchainKHR"); + pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) gpa(device, "vkDestroySwapchainKHR"); + pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) gpa(device, "vkGetSwapchainImagesKHR"); + pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) gpa(device, "vkAcquireNextImageKHR"); + pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR) gpa(device, "vkQueuePresentKHR"); + my_device_data->wsi_enabled = false; + for (uint32_t i = 0; i < pCreateInfo->enabledExtensionNameCount; i++) { + if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) + my_device_data->wsi_enabled = true; + } +} + +VkResult +explicit_CreateDevice( + VkPhysicalDevice gpu, + const VkDeviceCreateInfo *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDevice *pDevice) +{ + VkLayerDispatchTable *pDeviceTable = get_dispatch_table(unique_objects_device_table_map, *pDevice); + VkResult result = pDeviceTable->CreateDevice(gpu, pCreateInfo, pAllocator, pDevice); + if (result == VK_SUCCESS) { + layer_data *my_instance_data = get_my_data_ptr(get_dispatch_key(gpu), layer_data_map); + layer_data *my_device_data = get_my_data_ptr(get_dispatch_key(*pDevice), layer_data_map); + my_device_data->report_data = layer_debug_report_create_device(my_instance_data->report_data, *pDevice); + createDeviceRegisterExtensions(pCreateInfo, *pDevice); + } + return result; +} + +VkResult explicit_QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence) +{ +// UNWRAP USES: +// 0 : fence,VkFence + if (VK_NULL_HANDLE != fence) { + fence = (VkFence)((VkUniqueObject*)fence)->actualObject; + } +// waitSemaphoreCount : pSubmits[submitCount]->pWaitSemaphores,VkSemaphore + std::vector<VkSemaphore> original_pWaitSemaphores = {}; +// signalSemaphoreCount : pSubmits[submitCount]->pSignalSemaphores,VkSemaphore + std::vector<VkSemaphore> original_pSignalSemaphores = {}; + if (pSubmits) { + for (uint32_t index0=0; index0<submitCount; ++index0) { + if (pSubmits[index0].pWaitSemaphores) { + for (uint32_t index1=0; index1<pSubmits[index0].waitSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pSubmits[index0].pWaitSemaphores); + original_pWaitSemaphores.push_back(pSubmits[index0].pWaitSemaphores[index1]); + *(ppSemaphore[index1]) = (VkSemaphore)((VkUniqueObject*)pSubmits[index0].pWaitSemaphores[index1])->actualObject; + } + } + if (pSubmits[index0].pSignalSemaphores) { + for (uint32_t index1=0; index1<pSubmits[index0].signalSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pSubmits[index0].pSignalSemaphores); + original_pSignalSemaphores.push_back(pSubmits[index0].pSignalSemaphores[index1]); + *(ppSemaphore[index1]) = (VkSemaphore)((VkUniqueObject*)pSubmits[index0].pSignalSemaphores[index1])->actualObject; + } + } + } + } + VkResult result = get_dispatch_table(unique_objects_device_table_map, queue)->QueueSubmit(queue, submitCount, pSubmits, fence); + if (pSubmits) { + for (uint32_t index0=0; index0<submitCount; ++index0) { + if (pSubmits[index0].pWaitSemaphores) { + for (uint32_t index1=0; index1<pSubmits[index0].waitSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pSubmits[index0].pWaitSemaphores); + *(ppSemaphore[index1]) = original_pWaitSemaphores[index1]; + } + } + if (pSubmits[index0].pSignalSemaphores) { + for (uint32_t index1=0; index1<pSubmits[index0].signalSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pSubmits[index0].pSignalSemaphores); + *(ppSemaphore[index1]) = original_pSignalSemaphores[index1]; + } + } + } + } + return result; +} + +VkResult explicit_QueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo* pBindInfo, VkFence fence) +{ +// UNWRAP USES: +// 0 : pBindInfo[bindInfoCount]->pBufferBinds[bufferBindCount]->buffer,VkBuffer, pBindInfo[bindInfoCount]->pBufferBinds[bufferBindCount]->pBinds[bindCount]->memory,VkDeviceMemory, pBindInfo[bindInfoCount]->pImageOpaqueBinds[imageOpaqueBindCount]->image,VkImage, pBindInfo[bindInfoCount]->pImageOpaqueBinds[imageOpaqueBindCount]->pBinds[bindCount]->memory,VkDeviceMemory, pBindInfo[bindInfoCount]->pImageBinds[imageBindCount]->image,VkImage, pBindInfo[bindInfoCount]->pImageBinds[imageBindCount]->pBinds[bindCount]->memory,VkDeviceMemory + std::vector<VkBuffer> original_buffer = {}; + std::vector<VkDeviceMemory> original_memory1 = {}; + std::vector<VkImage> original_image1 = {}; + std::vector<VkDeviceMemory> original_memory2 = {}; + std::vector<VkImage> original_image2 = {}; + std::vector<VkDeviceMemory> original_memory3 = {}; + std::vector<VkSemaphore> original_pWaitSemaphores = {}; + std::vector<VkSemaphore> original_pSignalSemaphores = {}; + if (pBindInfo) { + for (uint32_t index0=0; index0<bindInfoCount; ++index0) { + if (pBindInfo[index0].pBufferBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].bufferBindCount; ++index1) { + if (pBindInfo[index0].pBufferBinds[index1].buffer) { + VkBuffer* pBuffer = (VkBuffer*)&(pBindInfo[index0].pBufferBinds[index1].buffer); + original_buffer.push_back(pBindInfo[index0].pBufferBinds[index1].buffer); + *(pBuffer) = (VkBuffer)((VkUniqueObject*)pBindInfo[index0].pBufferBinds[index1].buffer)->actualObject; + } + if (pBindInfo[index0].pBufferBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pBufferBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory); + original_memory1.push_back(pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = (VkDeviceMemory)((VkUniqueObject*)pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory)->actualObject; + } + } + } + } + } + if (pBindInfo[index0].pImageOpaqueBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].imageOpaqueBindCount; ++index1) { + if (pBindInfo[index0].pImageOpaqueBinds[index1].image) { + VkImage* pImage = (VkImage*)&(pBindInfo[index0].pImageOpaqueBinds[index1].image); + original_image1.push_back(pBindInfo[index0].pImageOpaqueBinds[index1].image); + *(pImage) = (VkImage)((VkUniqueObject*)pBindInfo[index0].pImageOpaqueBinds[index1].image)->actualObject; + } + if (pBindInfo[index0].pImageOpaqueBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pImageOpaqueBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory); + original_memory2.push_back(pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = (VkDeviceMemory)((VkUniqueObject*)pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory)->actualObject; + } + } + } + } + } + if (pBindInfo[index0].pImageBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].imageBindCount; ++index1) { + if (pBindInfo[index0].pImageBinds[index1].image) { + VkImage* pImage = (VkImage*)&(pBindInfo[index0].pImageBinds[index1].image); + original_image2.push_back(pBindInfo[index0].pImageBinds[index1].image); + *(pImage) = (VkImage)((VkUniqueObject*)pBindInfo[index0].pImageBinds[index1].image)->actualObject; + } + if (pBindInfo[index0].pImageBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pImageBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory); + original_memory3.push_back(pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = (VkDeviceMemory)((VkUniqueObject*)pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory)->actualObject; + } + } + } + } + } + if (pBindInfo[index0].pWaitSemaphores) { + for (uint32_t index1=0; index1<pBindInfo[index0].waitSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pBindInfo[index0].pWaitSemaphores); + original_pWaitSemaphores.push_back(pBindInfo[index0].pWaitSemaphores[index1]); + *(ppSemaphore[index1]) = (VkSemaphore)((VkUniqueObject*)pBindInfo[index0].pWaitSemaphores[index1])->actualObject; + } + } + if (pBindInfo[index0].pSignalSemaphores) { + for (uint32_t index1=0; index1<pBindInfo[index0].signalSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pBindInfo[index0].pSignalSemaphores); + original_pSignalSemaphores.push_back(pBindInfo[index0].pSignalSemaphores[index1]); + *(ppSemaphore[index1]) = (VkSemaphore)((VkUniqueObject*)pBindInfo[index0].pSignalSemaphores[index1])->actualObject; + } + } + } + } + if (VK_NULL_HANDLE != fence) { + fence = (VkFence)((VkUniqueObject*)fence)->actualObject; + } + VkResult result = get_dispatch_table(unique_objects_device_table_map, queue)->QueueBindSparse(queue, bindInfoCount, pBindInfo, fence); + if (pBindInfo) { + for (uint32_t index0=0; index0<bindInfoCount; ++index0) { + if (pBindInfo[index0].pBufferBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].bufferBindCount; ++index1) { + if (pBindInfo[index0].pBufferBinds[index1].buffer) { + VkBuffer* pBuffer = (VkBuffer*)&(pBindInfo[index0].pBufferBinds[index1].buffer); + *(pBuffer) = original_buffer[index1]; + } + if (pBindInfo[index0].pBufferBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pBufferBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pBufferBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = original_memory1[index2]; + } + } + } + } + } + if (pBindInfo[index0].pImageOpaqueBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].imageOpaqueBindCount; ++index1) { + if (pBindInfo[index0].pImageOpaqueBinds[index1].image) { + VkImage* pImage = (VkImage*)&(pBindInfo[index0].pImageOpaqueBinds[index1].image); + *(pImage) = original_image1[index1]; + } + if (pBindInfo[index0].pImageOpaqueBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pImageOpaqueBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pImageOpaqueBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = original_memory2[index2]; + } + } + } + } + } + if (pBindInfo[index0].pImageBinds) { + for (uint32_t index1=0; index1<pBindInfo[index0].imageBindCount; ++index1) { + if (pBindInfo[index0].pImageBinds[index1].image) { + VkImage* pImage = (VkImage*)&(pBindInfo[index0].pImageBinds[index1].image); + *(pImage) = original_image2[index1]; + } + if (pBindInfo[index0].pImageBinds[index1].pBinds) { + for (uint32_t index2=0; index2<pBindInfo[index0].pImageBinds[index1].bindCount; ++index2) { + if (pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory) { + VkDeviceMemory* pDeviceMemory = (VkDeviceMemory*)&(pBindInfo[index0].pImageBinds[index1].pBinds[index2].memory); + *(pDeviceMemory) = original_memory3[index2]; + } + } + } + } + } + if (pBindInfo[index0].pWaitSemaphores) { + for (uint32_t index1=0; index1<pBindInfo[index0].waitSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pBindInfo[index0].pWaitSemaphores); + *(ppSemaphore[index1]) = original_pWaitSemaphores[index1]; + } + } + if (pBindInfo[index0].pSignalSemaphores) { + for (uint32_t index1=0; index1<pBindInfo[index0].signalSemaphoreCount; ++index1) { + VkSemaphore** ppSemaphore = (VkSemaphore**)&(pBindInfo[index0].pSignalSemaphores); + *(ppSemaphore[index1]) = original_pSignalSemaphores[index1]; + } + } + } + } + return result; +} + +VkResult explicit_CreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) +{ +// UNWRAP USES: +// 0 : pipelineCache,VkPipelineCache, pCreateInfos[createInfoCount]->stage[0]->module,VkShaderModule, pCreateInfos[createInfoCount]->layout,VkPipelineLayout, pCreateInfos[createInfoCount]->basePipelineHandle,VkPipeline + if (VK_NULL_HANDLE != pipelineCache) { + pipelineCache = (VkPipelineCache)((VkUniqueObject*)pipelineCache)->actualObject; + } + std::vector<VkShaderModule> original_module = {}; + std::vector<VkPipelineLayout> original_layout = {}; + std::vector<VkPipeline> original_basePipelineHandle = {}; + if (pCreateInfos) { + for (uint32_t index0=0; index0<createInfoCount; ++index0) { + if (pCreateInfos[index0].stage.module) { + VkShaderModule* pShaderModule = (VkShaderModule*)&(pCreateInfos[index0].stage.module); + original_module.push_back(pCreateInfos[index0].stage.module); + *(pShaderModule) = (VkShaderModule)((VkUniqueObject*)pCreateInfos[index0].stage.module)->actualObject; + } + if (pCreateInfos[index0].layout) { + VkPipelineLayout* pPipelineLayout = (VkPipelineLayout*)&(pCreateInfos[index0].layout); + original_layout.push_back(pCreateInfos[index0].layout); + *(pPipelineLayout) = (VkPipelineLayout)((VkUniqueObject*)pCreateInfos[index0].layout)->actualObject; + } + if (pCreateInfos[index0].basePipelineHandle) { + VkPipeline* pPipeline = (VkPipeline*)&(pCreateInfos[index0].basePipelineHandle); + original_basePipelineHandle.push_back(pCreateInfos[index0].basePipelineHandle); + *(pPipeline) = (VkPipeline)((VkUniqueObject*)pCreateInfos[index0].basePipelineHandle)->actualObject; + } + } + } + VkResult result = get_dispatch_table(unique_objects_device_table_map, device)->CreateComputePipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); + if (pCreateInfos) { + for (uint32_t index0=0; index0<createInfoCount; ++index0) { + if (pCreateInfos[index0].stage.module) { + VkShaderModule* pShaderModule = (VkShaderModule*)&(pCreateInfos[index0].stage.module); + *(pShaderModule) = original_module[index0]; + } + if (pCreateInfos[index0].layout) { + VkPipelineLayout* pPipelineLayout = (VkPipelineLayout*)&(pCreateInfos[index0].layout); + *(pPipelineLayout) = original_layout[index0]; + } + if (pCreateInfos[index0].basePipelineHandle) { + VkPipeline* pPipeline = (VkPipeline*)&(pCreateInfos[index0].basePipelineHandle); + *(pPipeline) = original_basePipelineHandle[index0]; + } + } + } + if (VK_SUCCESS == result) { + std::vector<VkUniqueObject*> uniquePipelines = {}; + for (uint32_t i=0; i<createInfoCount; ++i) { + uniquePipelines.push_back(new VkUniqueObject()); + uniquePipelines[i]->actualObject = (uint64_t)pPipelines[i]; + pPipelines[i] = (VkPipeline)uniquePipelines[i]; + } + } + return result; +} + +VkResult explicit_CreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo* pCreateInfos, const VkAllocationCallbacks* pAllocator, VkPipeline* pPipelines) +{ +// UNWRAP USES: +// 0 : pipelineCache,VkPipelineCache, pCreateInfos[createInfoCount]->pStages[stageCount]->module,VkShaderModule, pCreateInfos[createInfoCount]->layout,VkPipelineLayout, pCreateInfos[createInfoCount]->renderPass,VkRenderPass, pCreateInfos[createInfoCount]->basePipelineHandle,VkPipeline + if (VK_NULL_HANDLE != pipelineCache) { + pipelineCache = (VkPipelineCache)((VkUniqueObject*)pipelineCache)->actualObject; + } + std::vector<VkShaderModule> original_module = {}; + std::vector<VkPipelineLayout> original_layout = {}; + std::vector<VkRenderPass> original_renderPass = {}; + std::vector<VkPipeline> original_basePipelineHandle = {}; + if (pCreateInfos) { + for (uint32_t index0=0; index0<createInfoCount; ++index0) { + if (pCreateInfos[index0].pStages) { + for (uint32_t index1=0; index1<pCreateInfos[index0].stageCount; ++index1) { + if (pCreateInfos[index0].pStages[index1].module) { + VkShaderModule* pShaderModule = (VkShaderModule*)&(pCreateInfos[index0].pStages[index1].module); + original_module.push_back(pCreateInfos[index0].pStages[index1].module); + *(pShaderModule) = (VkShaderModule)((VkUniqueObject*)pCreateInfos[index0].pStages[index1].module)->actualObject; + } + } + } + if (pCreateInfos[index0].layout) { + VkPipelineLayout* pPipelineLayout = (VkPipelineLayout*)&(pCreateInfos[index0].layout); + original_layout.push_back(pCreateInfos[index0].layout); + *(pPipelineLayout) = (VkPipelineLayout)((VkUniqueObject*)pCreateInfos[index0].layout)->actualObject; + } + if (pCreateInfos[index0].renderPass) { + VkRenderPass* pRenderPass = (VkRenderPass*)&(pCreateInfos[index0].renderPass); + original_renderPass.push_back(pCreateInfos[index0].renderPass); + *(pRenderPass) = (VkRenderPass)((VkUniqueObject*)pCreateInfos[index0].renderPass)->actualObject; + } + if (pCreateInfos[index0].basePipelineHandle) { + VkPipeline* pPipeline = (VkPipeline*)&(pCreateInfos[index0].basePipelineHandle); + original_basePipelineHandle.push_back(pCreateInfos[index0].basePipelineHandle); + *(pPipeline) = (VkPipeline)((VkUniqueObject*)pCreateInfos[index0].basePipelineHandle)->actualObject; + } + } + } + VkResult result = get_dispatch_table(unique_objects_device_table_map, device)->CreateGraphicsPipelines(device, pipelineCache, createInfoCount, pCreateInfos, pAllocator, pPipelines); + if (pCreateInfos) { + for (uint32_t index0=0; index0<createInfoCount; ++index0) { + if (pCreateInfos[index0].pStages) { + for (uint32_t index1=0; index1<pCreateInfos[index0].stageCount; ++index1) { + if (pCreateInfos[index0].pStages[index1].module) { + VkShaderModule* pShaderModule = (VkShaderModule*)&(pCreateInfos[index0].pStages[index1].module); + *(pShaderModule) = original_module[index1]; + } + } + } + if (pCreateInfos[index0].layout) { + VkPipelineLayout* pPipelineLayout = (VkPipelineLayout*)&(pCreateInfos[index0].layout); + *(pPipelineLayout) = original_layout[index0]; + } + if (pCreateInfos[index0].renderPass) { + VkRenderPass* pRenderPass = (VkRenderPass*)&(pCreateInfos[index0].renderPass); + *(pRenderPass) = original_renderPass[index0]; + } + if (pCreateInfos[index0].basePipelineHandle) { + VkPipeline* pPipeline = (VkPipeline*)&(pCreateInfos[index0].basePipelineHandle); + *(pPipeline) = original_basePipelineHandle[index0]; + } + } + } + if (VK_SUCCESS == result) { + std::vector<VkUniqueObject*> uniquePipelines = {}; + for (uint32_t i=0; i<createInfoCount; ++i) { + uniquePipelines.push_back(new VkUniqueObject()); + uniquePipelines[i]->actualObject = (uint64_t)pPipelines[i]; + pPipelines[i] = (VkPipeline)uniquePipelines[i]; + } + } + return result; +} + +void explicit_UpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet* pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet* pDescriptorCopies) +{ +// UNWRAP USES: +// 0 : pDescriptorWrites[descriptorWriteCount]->dstSet,VkDescriptorSet, pDescriptorWrites[descriptorWriteCount]->pImageInfo[descriptorCount]->sampler,VkSampler, pDescriptorWrites[descriptorWriteCount]->pImageInfo[descriptorCount]->imageView,VkImageView, pDescriptorWrites[descriptorWriteCount]->pBufferInfo[descriptorCount]->buffer,VkBuffer, pDescriptorCopies[descriptorCopyCount]->srcSet,VkDescriptorSet, pDescriptorCopies[descriptorCopyCount]->dstSet,VkDescriptorSet + std::vector<VkDescriptorSet> original_dstSet1 = {}; + std::vector<VkSampler> original_sampler = {}; + std::vector<VkImageView> original_imageView = {}; + std::vector<VkBuffer> original_buffer = {}; + std::vector<VkDescriptorSet> original_srcSet = {}; + std::vector<VkDescriptorSet> original_dstSet2 = {}; +// descriptorCount : pDescriptorWrites[descriptorWriteCount]->pTexelBufferView,VkBufferView + std::vector<VkBufferView> original_pTexelBufferView = {}; + if (pDescriptorWrites) { + for (uint32_t index0=0; index0<descriptorWriteCount; ++index0) { + if (pDescriptorWrites[index0].dstSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorWrites[index0].dstSet); + original_dstSet1.push_back(pDescriptorWrites[index0].dstSet); + *(pDescriptorSet) = (VkDescriptorSet)((VkUniqueObject*)pDescriptorWrites[index0].dstSet)->actualObject; + } + if (pDescriptorWrites[index0].pImageInfo) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + if (pDescriptorWrites[index0].pImageInfo[index1].sampler) { + VkSampler* pSampler = (VkSampler*)&(pDescriptorWrites[index0].pImageInfo[index1].sampler); + original_sampler.push_back(pDescriptorWrites[index0].pImageInfo[index1].sampler); + *(pSampler) = (VkSampler)((VkUniqueObject*)pDescriptorWrites[index0].pImageInfo[index1].sampler)->actualObject; + } + if (pDescriptorWrites[index0].pImageInfo[index1].imageView) { + VkImageView* pImageView = (VkImageView*)&(pDescriptorWrites[index0].pImageInfo[index1].imageView); + original_imageView.push_back(pDescriptorWrites[index0].pImageInfo[index1].imageView); + *(pImageView) = (VkImageView)((VkUniqueObject*)pDescriptorWrites[index0].pImageInfo[index1].imageView)->actualObject; + } + } + } + if (pDescriptorWrites[index0].pBufferInfo) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + if (pDescriptorWrites[index0].pBufferInfo[index1].buffer) { + VkBuffer* pBuffer = (VkBuffer*)&(pDescriptorWrites[index0].pBufferInfo[index1].buffer); + original_buffer.push_back(pDescriptorWrites[index0].pBufferInfo[index1].buffer); + *(pBuffer) = (VkBuffer)((VkUniqueObject*)pDescriptorWrites[index0].pBufferInfo[index1].buffer)->actualObject; + } + } + } + if (pDescriptorWrites[index0].pTexelBufferView) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + VkBufferView** ppBufferView = (VkBufferView**)&(pDescriptorWrites[index0].pTexelBufferView); + original_pTexelBufferView.push_back(pDescriptorWrites[index0].pTexelBufferView[index1]); + *(ppBufferView[index1]) = (VkBufferView)((VkUniqueObject*)pDescriptorWrites[index0].pTexelBufferView[index1])->actualObject; + } + } + } + } + if (pDescriptorCopies) { + for (uint32_t index0=0; index0<descriptorCopyCount; ++index0) { + if (pDescriptorCopies[index0].srcSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorCopies[index0].srcSet); + original_srcSet.push_back(pDescriptorCopies[index0].srcSet); + *(pDescriptorSet) = (VkDescriptorSet)((VkUniqueObject*)pDescriptorCopies[index0].srcSet)->actualObject; + } + if (pDescriptorCopies[index0].dstSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorCopies[index0].dstSet); + original_dstSet2.push_back(pDescriptorCopies[index0].dstSet); + *(pDescriptorSet) = (VkDescriptorSet)((VkUniqueObject*)pDescriptorCopies[index0].dstSet)->actualObject; + } + } + } + get_dispatch_table(unique_objects_device_table_map, device)->UpdateDescriptorSets(device, descriptorWriteCount, pDescriptorWrites, descriptorCopyCount, pDescriptorCopies); + if (pDescriptorWrites) { + for (uint32_t index0=0; index0<descriptorWriteCount; ++index0) { + if (pDescriptorWrites[index0].dstSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorWrites[index0].dstSet); + *(pDescriptorSet) = original_dstSet1[index0]; + } + if (pDescriptorWrites[index0].pImageInfo) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + if (pDescriptorWrites[index0].pImageInfo[index1].sampler) { + VkSampler* pSampler = (VkSampler*)&(pDescriptorWrites[index0].pImageInfo[index1].sampler); + *(pSampler) = original_sampler[index1]; + } + if (pDescriptorWrites[index0].pImageInfo[index1].imageView) { + VkImageView* pImageView = (VkImageView*)&(pDescriptorWrites[index0].pImageInfo[index1].imageView); + *(pImageView) = original_imageView[index1]; + } + } + } + if (pDescriptorWrites[index0].pBufferInfo) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + if (pDescriptorWrites[index0].pBufferInfo[index1].buffer) { + VkBuffer* pBuffer = (VkBuffer*)&(pDescriptorWrites[index0].pBufferInfo[index1].buffer); + *(pBuffer) = original_buffer[index1]; + } + } + } + if (pDescriptorWrites[index0].pTexelBufferView) { + for (uint32_t index1=0; index1<pDescriptorWrites[index0].descriptorCount; ++index1) { + VkBufferView** ppBufferView = (VkBufferView**)&(pDescriptorWrites[index0].pTexelBufferView); + *(ppBufferView[index1]) = original_pTexelBufferView[index1]; + } + } + } + } + if (pDescriptorCopies) { + for (uint32_t index0=0; index0<descriptorCopyCount; ++index0) { + if (pDescriptorCopies[index0].srcSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorCopies[index0].srcSet); + *(pDescriptorSet) = original_srcSet[index0]; + } + if (pDescriptorCopies[index0].dstSet) { + VkDescriptorSet* pDescriptorSet = (VkDescriptorSet*)&(pDescriptorCopies[index0].dstSet); + *(pDescriptorSet) = original_dstSet2[index0]; + } + } + } +} + +VkResult explicit_GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages) +{ +// UNWRAP USES: +// 0 : swapchain,VkSwapchainKHR, pSwapchainImages,VkImage + if (VK_NULL_HANDLE != swapchain) { + swapchain = (VkSwapchainKHR)((VkUniqueObject*)swapchain)->actualObject; + } + VkResult result = get_dispatch_table(unique_objects_device_table_map, device)->GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages); + // TODO : Need to add corresponding code to delete these images + if (VK_SUCCESS == result) { + if ((*pSwapchainImageCount > 0) && pSwapchainImages) { + std::vector<VkUniqueObject*> uniqueImages = {}; + for (uint32_t i=0; i<*pSwapchainImageCount; ++i) { + uniqueImages.push_back(new VkUniqueObject()); + uniqueImages[i]->actualObject = (uint64_t)pSwapchainImages[i]; + pSwapchainImages[i] = (VkImage)uniqueImages[i]; + } + } + } + return result; +} diff --git a/layers/windows/VkLayer_unique_objects.json b/layers/windows/VkLayer_unique_objects.json new file mode 100644 index 00000000..8e046ef2 --- /dev/null +++ b/layers/windows/VkLayer_unique_objects.json @@ -0,0 +1,11 @@ +{ + "file_format_version" : "1.0.0", + "layer" : { + "name": "VK_LAYER_GOOGLE_unique_objects", + "type": "GLOBAL", + "library_path": ".\\VkLayer_unique_objects.dll", + "api_version": "0.210.0", + "implementation_version": "1", + "description": "Google Validation Layer" + } +} diff --git a/vk-layer-generate.py b/vk-layer-generate.py index a14024d4..465b8a8c 100755 --- a/vk-layer-generate.py +++ b/vk-layer-generate.py @@ -3,7 +3,7 @@ # VK # # Copyright (C) 2015 Valve Corporation -# Copyright (C) 2015 Google Inc. +# Copyright (C) 2015 Google, Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), @@ -23,12 +23,13 @@ # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # -# Author: Courtney Goeltzenleuchter <courtney@LunarG.com> +# Author: Tobin Ehlis <tobine@google.com> +# Author: Courtney Goeltzenleuchter <courtneygo@google.com> # Author: Jon Ashburn <jon@lunarg.com> # Author: Mark Lobodzinski <mark@lunarg.com> -# Author: Mike Stroyan <mike@LunarG.com> +# Author: Mike Stroyan <stroyan@google.com> # Author: Tony Barbour <tony@LunarG.com> -# Author: Chia-I Wu <olv@lunarg.com> +# Author: Chia-I Wu <olv@google.com> import sys import os @@ -139,6 +140,7 @@ class Subcommand(object): /* * * Copyright (C) 2015 Valve Corporation + * Copyright (C) 2015 Google, Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -158,10 +160,11 @@ class Subcommand(object): * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * Author: Courtney Goeltzenleuchter <courtney@LunarG.com> + * Author: Tobin Ehlis <tobine@google.com> + * Author: Courtney Goeltzenleuchter <courtneygo@google.com> * Author: Jon Ashburn <jon@lunarg.com> * Author: Mark Lobodzinski <mark@lunarg.com> - * Author: Mike Stroyan <mike@LunarG.com> + * Author: Mike Stroyan <stroyan@google.com> * Author: Tony Barbour <tony@LunarG.com> */""" @@ -234,7 +237,7 @@ class Subcommand(object): r_body.append(' VkDebugReportCallbackEXT* pCallback)') r_body.append('{') # Switch to this code section for the new per-instance storage and debug callbacks - if self.layer_name == 'object_tracker' or self.layer_name == 'threading': + if self.layer_name in ['object_tracker', 'threading', 'unique_objects']: r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name ) r_body.append(' VkResult result = pInstanceTable->CreateDebugReportCallbackEXT(instance, pCreateInfo, pAllocator, pCallback);') r_body.append(' if (VK_SUCCESS == result) {') @@ -261,7 +264,7 @@ class Subcommand(object): r_body.append('VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT msgCallback, const VkAllocationCallbacks *pAllocator)') r_body.append('{') # Switch to this code section for the new per-instance storage and debug callbacks - if self.layer_name == 'object_tracker' or self.layer_name == 'threading': + if self.layer_name in ['object_tracker', 'threading', 'unique_objects']: r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = get_dispatch_table(%s_instance_table_map, instance);' % self.layer_name ) else: r_body.append(' VkLayerInstanceDispatchTable *pInstanceTable = instance_dispatch_table(instance);') @@ -446,7 +449,7 @@ class Subcommand(object): # # New style of GPA Functions for the new layer_data/layer_logging changes # - if self.layer_name == 'object_tracker' or self.layer_name == 'threading': + if self.layer_name in ['object_tracker', 'threading', 'unique_objects']: func_body.append("VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkDevice device, const char* funcName)\n" "{\n" " PFN_vkVoidFunction addr;\n" @@ -869,7 +872,7 @@ class GenericLayerSubcommand(Subcommand): 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', 'vkGetPhysicalDeviceSurfaceFormatsKHR', 'vkGetPhysicalDeviceSurfacePresentModesKHR'])] - extensions=[('wsi_enabled', + extensions=[('wsi_enabled', ['vkCreateSwapchainKHR', 'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR', 'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])] @@ -1391,6 +1394,10 @@ class ObjectTrackerSubcommand(Subcommand): procs_txt.append(' return log_msg(mdd(dispatchable_object), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT ) 0, reinterpret_cast<uint64_t>(object), __LINE__, OBJTRACK_INVALID_OBJECT, "OBJTRACK",') procs_txt.append(' "Invalid %s Object 0x%%" PRIx64 ,reinterpret_cast<uint64_t>(object));' % o) else: + if o == "VkPipelineCache": + procs_txt.append(' // VkPipelineCache object can be NULL if not caching') + procs_txt.append(' if (object == VK_NULL_HANDLE) return VK_TRUE;') + procs_txt.append('') if o == "VkImage": procs_txt.append(' // We need to validate normal image objects and those from the swapchain') procs_txt.append(' if ((%sMap.find((uint64_t)object) == %sMap.end()) &&' % (o, o)) @@ -1654,6 +1661,7 @@ class ObjectTrackerSubcommand(Subcommand): create_line = '' destroy_line = '' # Dict below tracks params that are vk objects. Dict is "loop count"->["params w/ that loop count"] where '0' is params that aren't in an array + # TODO : Should integrate slightly better code for this purpose from unique_objects layer loop_params = defaultdict(list) # Dict uses loop count as key to make final code generation cleaner so params shared in single loop where needed loop_types = defaultdict(list) # TODO : For now skipping objs that can be NULL. Really should check these and have special case that allows them to be NULL @@ -1775,11 +1783,6 @@ class ObjectTrackerSubcommand(Subcommand): using_line += ' if (fence != VK_NULL_HANDLE) {\n' using_line += ' skipCall |= validate_%s(%s, %s);\n' % (name, param0_name, opn) using_line += ' }\n' - elif ('CreateGraphicsPipelines' in proto.name or 'CreateComputePipelines' in proto.name) and 'pipelineCache' == opn: - using_line += ' // PipelineCache is optional, validate if present\n' - using_line += ' if (pipelineCache != VK_NULL_HANDLE) {\n' - using_line += ' skipCall |= validate_%s(%s, %s);\n' % (name, param0_name, opn) - using_line += ' }\n' else: using_line += ' skipCall |= validate_%s(%s, %s);\n' % (name, param0_name, opn) else: @@ -1883,6 +1886,280 @@ class ObjectTrackerSubcommand(Subcommand): instance_extensions)] return "\n\n".join(body) +class UniqueObjectsSubcommand(Subcommand): + def generate_header(self): + header_txt = [] + header_txt.append('%s' % self.lineinfo.get()) + header_txt.append('#include "unique_objects.h"') + header_txt.append('') + header_txt.append('static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(initOnce);') + return "\n".join(header_txt) + + # Parse complete struct chain and add any new ndo_uses to the dict + def _gather_struct_ndos(self, name_prefix, struct_type, ndo_uses): + if vk_helper.typedef_rev_dict[struct_type] in vk_helper.struct_dict: + struct_type = vk_helper.typedef_rev_dict[struct_type] + # Parse elements of this struct param to identify objects and/or arrays of objects + for m in sorted(vk_helper.struct_dict[struct_type]): + array_len = "%s" % (str(vk_helper.struct_dict[struct_type][m]['array_size'])) + base_type = vk_helper.struct_dict[struct_type][m]['type'] + struct_name = vk_helper.struct_dict[struct_type][m]['name'] + if base_type in vulkan.object_non_dispatch_list: + if array_len not in ndo_uses: + ndo_uses[array_len] = [] + ndo_uses[array_len].append("%s%s,%s" % (name_prefix, struct_name, base_type)) + elif vk_helper.is_type(base_type, 'struct'): + ndo_uses = self._gather_struct_ndos("%s%s[%s]->" % (name_prefix, struct_name, array_len), base_type, ndo_uses) + return ndo_uses + + # Parse the given list of params and return true if any ndos + # TODO : This analysis could be done up-front at vk_helper time + def _get_ndo_uses(self, params): + ndo_uses = {} + param_count = 'NONE' # track params that give array sizes + for p in params: + base_type = p.ty.replace('const ', '').strip('*') + array_len = '0' + is_ptr = False + if 'count' in p.name.lower(): + param_count = p.name + if '*' in p.ty: + is_ptr = True + if base_type in vulkan.object_non_dispatch_list: + if is_ptr and 'const' in p.ty and param_count != 'NONE': + array_len = param_count + if array_len not in ndo_uses: + ndo_uses[array_len] = [] + ndo_uses[array_len].append("%s,%s" % (p.name, base_type)) + elif vk_helper.is_type(base_type, 'struct'): + struct_name = p.name + if 'NONE' != param_count: + struct_name = "%s[%s]" % (struct_name, param_count) + ndo_uses = self._gather_struct_ndos("%s->" % struct_name, base_type, ndo_uses) + return ndo_uses + + def generate_intercept(self, proto, qual): + create_func = False + destroy_func = False + last_param_index = None #typcially we look at all params for ndos + pre_call_txt = '' # code prior to calling down chain such as unwrap uses of ndos + post_call_txt = '' # code following call down chain such to wrap newly created ndos, or destroy local wrap struct + funcs = [] + indent = ' ' # indent level for generated code + decl = proto.c_func(prefix="vk", attr="VKAPI") + # TODO : A few API cases that will be manual code initially, could potentially move + # them to generated code + # Also, here's generated functions that could be improved: vkAllocateDescriptorSets, vkCmdBeginRenderPass + explicit_object_tracker_functions = ['QueueSubmit', + 'QueueBindSparse', + 'CreateComputePipelines', + 'CreateGraphicsPipelines', + 'UpdateDescriptorSets', + 'GetSwapchainImagesKHR', + 'CreateInstance', + 'CreateDevice',] + # Give special treatment to create functions that return multiple new objects + # This dict stores array name and size of array + custom_create_dict = {'pDescriptorSets' : 'pAllocateInfo->setLayoutCount'} + if proto.name in explicit_object_tracker_functions: + funcs.append('%s%s\n' + '{\n' + ' return explicit_%s;\n' + '}' % (qual, decl, proto.c_call())) + return "".join(funcs) + if True in [create_txt in proto.name for create_txt in ['Create', 'Allocate']]: + create_func = True + last_param_index = -1 # For create funcs don't care if last param is ndo + if True in [destroy_txt in proto.name for destroy_txt in ['Destroy', 'Free']]: + destroy_obj_type = proto.params[-2].ty + if destroy_obj_type in vulkan.object_non_dispatch_list: + destroy_func = True + + # First thing we need to do is update any uses for non-dispatchable-objects (ndos) + ndo_uses = self._get_ndo_uses(proto.params[1:last_param_index]) + if len(ndo_uses) > 0: + pre_call_txt = '// UNWRAP USES:\n' + for ndo in ndo_uses: + pre_call_txt += '// %s : %s\n' % (ndo, ', '.join(ndo_uses[ndo])) + for member in ndo_uses[ndo]: + # pairs of (m)ember (n)ames and (t)ypes + mnt_array = member.split(',') + has_ptr = False + pname = mnt_array[0] + if '->' in pname: + has_ptr = True + pname = mnt_array[0].split('->')[-1] + if not has_ptr and '0' == ndo: + if destroy_func: + pre_call_txt += '%s%s local_%s = %s;\n' % (indent, mnt_array[1], pname, pname) + pre_call_txt += '%s\n' % (self.lineinfo.get()) + pre_call_txt += '%sif (VK_NULL_HANDLE != %s) {\n' % (indent, mnt_array[0]) + indent += ' ' + pre_call_txt += '%s%s = (%s)((VkUniqueObject*)%s)->actualObject;\n' % (indent, pname, mnt_array[1], pname) + indent = indent [4:] + pre_call_txt += '%s}\n' % (indent) + else: # ptr and/or loop case + name_hier = mnt_array[0].split('->') + last_seg = False # is this last seg of the name? + prev_seg = '' + loop_indicies = ['0'] # track all the loop indices + loop_idx_num = 0 + loop_count = '' # Upper limit of current loop + orig_indent = indent # store this so we can close out blocks at the end + # Declare vector of ndos in order to restore them after call + pre_call_txt += '%s\n' % (self.lineinfo.get()) + pre_call_txt += '%sstd::vector<%s> original_%s = {};\n' % (indent, mnt_array[1], name_hier[-1]) + for seg in name_hier: + array = False + if seg == name_hier[-1]: + last_seg = True + if '[' in seg or (last_seg and '0' != ndo): # array access, so store off array counter and update name + array = True + loop_indicies.append('index%s' % str(loop_idx_num)) + loop_idx_num += 1 + if '[' in seg: # explicit array case is not ndo + (seg, loop_count) = seg.split('[') + loop_count = loop_count.strip(']') + else: # ndo case the loop_count is key + loop_count = ndo + pre_call_txt += '%sif (%s%s) {\n' % (indent, prev_seg, seg) + # We replicate the ndo update code after the call to restore original handle + post_call_txt += '%sif (%s%s) {\n' % (indent, prev_seg, seg) + indent += ' ' + if array: + pre_call_txt += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, loop_indicies[-1], loop_indicies[-1], prev_seg, loop_count, loop_indicies[-1]) + post_call_txt += '%sfor (uint32_t %s=0; %s<%s%s; ++%s) {\n' % (indent, loop_indicies[-1], loop_indicies[-1], prev_seg, loop_count, loop_indicies[-1]) + indent += ' ' + if last_seg: + p_name = 'p%s' % mnt_array[1][2:] # Used to allow overwriting of ndo object in const ptr chain + # TODO - need type of element ABOVE NDO in this case, this is BROKEN right now + ndo_ref_name = prev_seg.strip('->').strip('.') + ndo_name = '%s%s' % (prev_seg, seg) + if array: + ndo_ref_name = '%s%s' % (prev_seg, seg) + ndo_name = '%s[%s]' % (ndo_ref_name, loop_indicies[-1]) + pre_call_txt += '%s%s* %s = (%s*)&(%s);\n' % (indent, mnt_array[1], p_name, mnt_array[1], ndo_name) + post_call_txt += '%s%s* %s = (%s*)&(%s);\n' % (indent, mnt_array[1], p_name, mnt_array[1], ndo_name) + # Save off this object to restore it after the call + pre_call_txt += '%soriginal_%s.push_back(%s);\n' % (indent, seg, ndo_name) + pre_call_txt += '%s*(%s) = (%s)((VkUniqueObject*)%s)->actualObject;\n' % (indent, p_name, mnt_array[1], ndo_name) + post_call_txt += '%s*(%s) = original_%s[%s];\n' % (indent, p_name, seg, loop_indicies[-1]) + indent = indent[4:] + # Update prev segment to be used in next loop iteration + if not array: + prev_seg = '%s%s->' % (prev_seg, seg) + else: + prev_seg = '%s%s[%s].' % (prev_seg, seg, loop_indicies[-1]) + if indent != orig_indent: + while indent != ' ': # close previous code blocks + pre_call_txt += '%s}\n' % (indent) + post_call_txt += '%s}\n' % (indent) + indent = indent[4:] + pre_call_txt += '%s}\n' % (indent) + post_call_txt += '%s}\n' % (indent) + elif create_func: + base_type = proto.params[-1].ty.replace('const ', '').strip('*') + if base_type not in vulkan.object_non_dispatch_list: + return None + else: + return None + + ret_val = '' + ret_stmt = '' + if proto.ret != "void": + ret_val = "%s result = " % proto.ret + ret_stmt = " return result;\n" + dispatch_param = proto.params[0].name + if 'CreateInstance' in proto.name: + dispatch_param = '*' + proto.params[1].name + if create_func: + obj_type = proto.params[-1].ty.strip('*') + obj_name = proto.params[-1].name + if obj_type in vulkan.object_non_dispatch_list: + local_name = "unique%s" % obj_type[2:] + post_call_txt += '%sif (VK_SUCCESS == result) {\n' % (indent) + indent += ' ' + if obj_name in custom_create_dict: + post_call_txt += '%s\n' % (self.lineinfo.get()) + local_name = '%ss' % (local_name) # add 's' to end for vector of many + post_call_txt += '%sstd::vector<VkUniqueObject*> %s = {};\n' % (indent, local_name) + post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, custom_create_dict[obj_name]) + indent += ' ' + post_call_txt += '%s%s.push_back(new VkUniqueObject());\n' % (indent, local_name) + post_call_txt += '%s%s[i]->actualObject = (uint64_t)%s[i];\n' % (indent, local_name, obj_name) + post_call_txt += '%s%s[i] = (%s)%s[i];\n' % (indent, obj_name, obj_type, local_name) + indent = indent[4:] + post_call_txt += '%s}\n' % (indent) + else: + post_call_txt += '%s\n' % (self.lineinfo.get()) + post_call_txt += '%sVkUniqueObject* %s = new VkUniqueObject();\n' % (indent, local_name) + post_call_txt += '%s%s->actualObject = (uint64_t)*%s;\n' % (indent, local_name, obj_name) + post_call_txt += '%s*%s = (%s)%s;\n' % (indent, obj_name, obj_type, local_name) + indent = indent[4:] + post_call_txt += '%s}\n' % (indent) + elif destroy_func: + del_obj = proto.params[-2].name + if 'count' in del_obj.lower(): + post_call_txt += '%s\n' % (self.lineinfo.get()) + post_call_txt += '%sfor (uint32_t i=0; i<%s; ++i) {\n' % (indent, del_obj) + del_obj = proto.params[-1].name + indent += ' ' + post_call_txt += '%sdelete (VkUniqueObject*)%s[i];\n' % (indent, del_obj) + indent = indent[4:] + post_call_txt += '%s}\n' % (indent) + else: + post_call_txt += '%s\n' % (self.lineinfo.get()) + post_call_txt = '%sdelete (VkUniqueObject*)local_%s;\n' % (indent, proto.params[-2].name) + + call_sig = proto.c_call() + if proto_is_global(proto): + table_type = "instance" + else: + table_type = "device" + pre_call_txt += '%s\n' % (self.lineinfo.get()) + funcs.append('%s%s\n' + '{\n' + '%s' + ' %sget_dispatch_table(unique_objects_%s_table_map, %s)->%s;\n' + '%s' + '%s' + '}' % (qual, decl, pre_call_txt, ret_val, table_type, dispatch_param, call_sig, post_call_txt, ret_stmt)) + return "\n\n".join(funcs) + + def generate_body(self): + self.layer_name = "unique_objects" + extensions=[('wsi_enabled', + ['vkCreateSwapchainKHR', + 'vkDestroySwapchainKHR', 'vkGetSwapchainImagesKHR', + 'vkAcquireNextImageKHR', 'vkQueuePresentKHR'])] + if sys.platform.startswith('win32'): + instance_extensions=[('wsi_enabled', + ['vkGetPhysicalDeviceSurfaceSupportKHR', + 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', + 'vkGetPhysicalDeviceSurfaceFormatsKHR', + 'vkGetPhysicalDeviceSurfacePresentModesKHR', + 'vkCreateWin32SurfaceKHR', + 'vkGetPhysicalDeviceWin32PresentationSupportKHR'])] + elif sys.platform.startswith('linux'): + instance_extensions=[('wsi_enabled', + ['vkGetPhysicalDeviceSurfaceSupportKHR', + 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', + 'vkGetPhysicalDeviceSurfaceFormatsKHR', + 'vkGetPhysicalDeviceSurfacePresentModesKHR', + 'vkCreateXcbSurfaceKHR', + 'vkGetPhysicalDeviceXcbPresentationSupportKHR'])] + # TODO: Add cases for Mir, Wayland and Xlib + else: # android + instance_extensions=[('wsi_enabled', + ['vkGetPhysicalDeviceSurfaceSupportKHR', + 'vkGetPhysicalDeviceSurfaceCapabilitiesKHR', + 'vkGetPhysicalDeviceSurfaceFormatsKHR', + 'vkGetPhysicalDeviceSurfacePresentModesKHR'])] + body = [self._generate_dispatch_entrypoints("VK_LAYER_EXPORT"), + self._generate_layer_gpa_function(extensions, + instance_extensions)] + return "\n\n".join(body) + class ThreadingSubcommand(Subcommand): thread_check_dispatchable_objects = [ "VkQueue", @@ -2161,6 +2438,7 @@ def main(): "api_dump" : APIDumpSubcommand, "object_tracker" : ObjectTrackerSubcommand, "threading" : ThreadingSubcommand, + "unique_objects" : UniqueObjectsSubcommand, } if len(sys.argv) < 3 or sys.argv[1] not in subcommands or not os.path.exists(sys.argv[2]): |
