layers: Add UniqueObjects layer to wrap objects in unique ptr
authorTobin Ehlis <tobine@google.com>
Tue, 8 Dec 2015 17:50:10 +0000 (10:50 -0700)
committerJon Ashburn <jon@lunarg.com>
Thu, 7 Jan 2016 18:57:31 +0000 (11:57 -0700)
This layer should sit at the BOTTOM of the layer stack (closest to the driver, furthest from the app). It interecpts all created non-dispatchable-objects and wraps them in a struct, returning that struct ptr up the chain.

For all API calls that use NDOs, this layer will unwrap them, and overwrite the wrapped handle with the actual handle before passing it down. Then, after calling down to the driver, the layer will re-overwrite the NDO handles with the original, wrapped handle.

When an NDO object is destroyed, the actual handle is passed down, then the wrap struct object is destroyed.

demos/cube.c
layers/CMakeLists.txt
layers/linux/VkLayer_unique_objects.json [new file with mode: 0644]
layers/unique_objects.h [new file with mode: 0644]
layers/windows/VkLayer_unique_objects.json [new file with mode: 0644]
vk-layer-generate.py

index f1202cb..1f290ce 100644 (file)
@@ -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 */
index 1c47165..2299421 100644 (file)
@@ -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 (file)
index 0000000..056ad7b
--- /dev/null
@@ -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 (file)
index 0000000..f12cf8c
--- /dev/null
@@ -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 (file)
index 0000000..8e046ef
--- /dev/null
@@ -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"
+    }
+}
index a14024d..465b8a8 100755 (executable)
@@ -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"),
 # 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]):