Swapchain: Validating supported surface for presenting with a queue.
authorIan Elliott <ianelliott@google.com>
Thu, 21 Jan 2016 21:29:45 +0000 (14:29 -0700)
committerJon Ashburn <jon@lunarg.com>
Thu, 28 Jan 2016 18:19:07 +0000 (11:19 -0700)
This validation involves multiple levels of indirection as vkQueuePresentKHR()
receives a queue parameter, and a pPresentInfo->pSwapchains array.  For each
swapchain, it's surface must have been seen to be supported with a
queueFamilyIndex that is associated with the queue parameter.  Info must be
recorded at various previous calls, and be correlatable at this point in time.
Very complicated!

layers/swapchain.cpp
layers/swapchain.h
layers/vk_validation_layer_details.md

index d75a0ac..47e4fe8 100644 (file)
@@ -89,6 +89,7 @@ static void createDeviceRegisterExtensions(VkPhysicalDevice physicalDevice, cons
     pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) gpa(device, "vkGetSwapchainImagesKHR");
     pDisp->AcquireNextImageKHR   = (PFN_vkAcquireNextImageKHR) gpa(device, "vkAcquireNextImageKHR");
     pDisp->QueuePresentKHR       = (PFN_vkQueuePresentKHR) gpa(device, "vkQueuePresentKHR");
+    pDisp->GetDeviceQueue        = (PFN_vkGetDeviceQueue) gpa(device, "vkGetDeviceQueue");
 
     SwpPhysicalDevice *pPhysicalDevice = &my_instance_data->physicalDeviceMap[physicalDevice];
     if (pPhysicalDevice) {
@@ -121,7 +122,6 @@ static void createInstanceRegisterExtensions(const VkInstanceCreateInfo* pCreate
     layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
     VkLayerInstanceDispatchTable *pDisp  = my_data->instance_dispatch_table;
     PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
-    pDisp->GetPhysicalDeviceQueueFamilyProperties = (PFN_vkGetPhysicalDeviceQueueFamilyProperties) gpa(instance, "vkGetPhysicalDeviceQueueFamilyProperties");
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     pDisp->CreateAndroidSurfaceKHR = (PFN_vkCreateAndroidSurfaceKHR) gpa(instance, "vkCreateAndroidSurfaceKHR");
 #endif // VK_USE_PLATFORM_ANDROID_KHR
@@ -403,7 +403,7 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyPropert
         if (pPhysicalDevice &&
             pQueueFamilyPropertyCount && !pQueueFamilyProperties) {
             pPhysicalDevice->gotQueueFamilyPropertyCount = true;
-            pPhysicalDevice->pQueueFamilyPropertyCount =
+            pPhysicalDevice->numOfQueueFamilies =
                 *pQueueFamilyPropertyCount;
         }
     }
@@ -460,6 +460,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateAndroidSurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -521,6 +523,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateMirSurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -551,12 +555,12 @@ VK_LAYER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceMirPresentatio
                               __FUNCTION__, VK_KHR_MIR_SURFACE_EXTENSION_NAME);
     }
     if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+        (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
 
     if (VK_FALSE == skipCall) {
@@ -619,6 +623,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateWaylandSurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -649,12 +655,12 @@ VK_LAYER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWaylandPresent
                               __FUNCTION__, VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME);
     }
     if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+        (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
 
     if (VK_FALSE == skipCall) {
@@ -717,6 +723,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateWin32SurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -746,12 +754,12 @@ VK_LAYER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceWin32Presentat
                               __FUNCTION__, VK_KHR_WIN32_SURFACE_EXTENSION_NAME);
     }
     if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+        (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
 
     if (VK_FALSE == skipCall) {
@@ -814,6 +822,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateXcbSurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -845,12 +855,12 @@ VK_LAYER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXcbPresentatio
                               __FUNCTION__, VK_KHR_XCB_SURFACE_EXTENSION_NAME);
     }
     if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+        (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
 
     if (VK_FALSE == skipCall) {
@@ -913,6 +923,8 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateXlibSurfaceKHR(
             my_data->surfaceMap[*pSurface].pInstance = pInstance;
             my_data->surfaceMap[*pSurface].usedAllocatorToCreate =
                 (pAllocator != NULL);
+            my_data->surfaceMap[*pSurface].numQueueFamilyIndexSupport = 0;
+            my_data->surfaceMap[*pSurface].pQueueFamilyIndexSupport = NULL;
             // Point to the associated SwpInstance:
             pInstance->surfaces[*pSurface] = &my_data->surfaceMap[*pSurface];
         }
@@ -944,12 +956,12 @@ VK_LAYER_EXPORT VKAPI_ATTR VkBool32 VKAPI_CALL vkGetPhysicalDeviceXlibPresentati
                               __FUNCTION__, VK_KHR_XLIB_SURFACE_EXTENSION_NAME);
     }
     if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+        (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
 
     if (VK_FALSE == skipCall) {
@@ -1136,13 +1148,22 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupport
                               "%s() called even though the %s extension was not enabled for this VkInstance.",
                               __FUNCTION__, VK_KHR_SURFACE_EXTENSION_NAME);
     }
-    if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
-        (queueFamilyIndex >= pPhysicalDevice->pQueueFamilyPropertyCount)) {
+    if (!pPhysicalDevice->gotQueueFamilyPropertyCount) {
+        skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+                              pPhysicalDevice,
+                              "VkPhysicalDevice",
+                              SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,
+                              "%s() called before calling the "
+                              "vkGetPhysicalDeviceQueueFamilyProperties "
+                              "function.",
+                              __FUNCTION__);
+    } else if (pPhysicalDevice->gotQueueFamilyPropertyCount &&
+               (queueFamilyIndex >= pPhysicalDevice->numOfQueueFamilies)) {
         skipCall |= LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
                                                            pPhysicalDevice,
                                                            "VkPhysicalDevice",
                                                            queueFamilyIndex,
-                                                           pPhysicalDevice->pQueueFamilyPropertyCount);
+                                                           pPhysicalDevice->numOfQueueFamilies);
     }
     if (!pSupported) {
         skipCall |= LOG_ERROR_NULL_POINTER(VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
@@ -1158,13 +1179,27 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupport
 
         if ((result == VK_SUCCESS) && pSupported && pPhysicalDevice) {
             // Record the result of this query:
-            pPhysicalDevice->queueFamilyIndexSupport[queueFamilyIndex] =
-                surface;
-            pPhysicalDevice->surfaceSupport[surface] =
-                queueFamilyIndex;
-            // TODO: We need to compare this with the actual queue used for
-            // presentation, to ensure it was advertised to the application as
-            // supported for presentation.
+            SwpInstance *pInstance = pPhysicalDevice->pInstance;
+            SwpSurface *pSurface =
+                (pInstance) ? pInstance->surfaces[surface] : NULL;
+            if (pSurface) {
+                pPhysicalDevice->supportedSurfaces[surface] = pSurface;
+                if (!pSurface->numQueueFamilyIndexSupport) {
+                    if (pPhysicalDevice->gotQueueFamilyPropertyCount) {
+                        pSurface->pQueueFamilyIndexSupport = (VkBool32 *)
+                            malloc(pPhysicalDevice->numOfQueueFamilies *
+                                   sizeof(VkBool32));
+                        if (pSurface->pQueueFamilyIndexSupport != NULL) {
+                            pSurface->numQueueFamilyIndexSupport =
+                                pPhysicalDevice->numOfQueueFamilies;
+                        }
+                    }
+                }
+                if (pSurface->numQueueFamilyIndexSupport) {
+                    pSurface->pQueueFamilyIndexSupport[queueFamilyIndex] =
+                        *pSupported;
+                }
+            }
         }
 
         return result;
@@ -1414,8 +1449,10 @@ static VkBool32 validateCreateSwapchainKHR(
         // Validate pCreateInfo->surface to make sure that
         // vkGetPhysicalDeviceSurfaceSupportKHR() reported this as a supported
         // surface:
-        uint32_t queueFamilyIndex = pPhysicalDevice->surfaceSupport[pCreateInfo->surface];
-        if (!queueFamilyIndex) {
+        SwpSurface *pSurface =
+            ((pPhysicalDevice) ?
+             pPhysicalDevice->supportedSurfaces[pCreateInfo->surface] : NULL);
+        if (!pSurface) {
             skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT, device, "VkDevice",
                                   SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE,
                                   "%s() called with pCreateInfo->surface that "
@@ -1760,8 +1797,10 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateSwapchainKHR(
             SwpDevice *pDevice = &my_data->deviceMap[device];
 
             my_data->swapchainMap[*pSwapchain].swapchain = *pSwapchain;
-            pDevice->swapchains[*pSwapchain] =
-                &my_data->swapchainMap[*pSwapchain];
+            if (pDevice) {
+                pDevice->swapchains[*pSwapchain] =
+                    &my_data->swapchainMap[*pSwapchain];
+            }
             my_data->swapchainMap[*pSwapchain].pDevice = pDevice;
             my_data->swapchainMap[*pSwapchain].imageCount = 0;
             my_data->swapchainMap[*pSwapchain].usedAllocatorToCreate =
@@ -1999,8 +2038,6 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
 //   sname:VkSemaphore in pname:pWaitSemaphores must: refer to a prior signal
 //   of that sname:VkSemaphore that won't be consumed by any other wait on that
 //   semaphore
-// - Ensure that the queue is active, and is one of the queueFamilyIndex's
-//   that was returned by a previuos query.
 // - Record/update the state of the swapchain, in case an error occurs
 //   (e.g. VK_ERROR_OUT_OF_DATE_KHR).
     VkResult result = VK_SUCCESS;
@@ -2078,6 +2115,26 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
                                           __FUNCTION__, index);
                 }
             }
+            SwpQueue *pQueue = &my_data->queueMap[queue];
+            SwpSurface *pSurface = pSwapchain->pSurface;
+            if (pQueue && pSurface && pSurface->numQueueFamilyIndexSupport) {
+                uint32_t queueFamilyIndex = pQueue->queueFamilyIndex;
+                // Note: the 1st test is to ensure queueFamilyIndex is in range,
+                // and the 2nd test is the validation check:
+                if ((pSurface->numQueueFamilyIndexSupport > queueFamilyIndex) &&
+                    (!pSurface->pQueueFamilyIndexSupport[queueFamilyIndex])) {
+                    skipCall |= LOG_ERROR(VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT,
+                                          pPresentInfo->pSwapchains[i],
+                                          "VkSwapchainKHR",
+                                          SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE,
+                                          "%s() called with a swapchain whose "
+                                          "surface is not supported for "
+                                          "presention on this device with the "
+                                          "queueFamilyIndex (i.e. %d) of the "
+                                          "given queue.",
+                                          __FUNCTION__, queueFamilyIndex);
+                }
+            }
         }
     }
 
@@ -2105,6 +2162,32 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR(
     return VK_ERROR_VALIDATION_FAILED_EXT;
 }
 
+VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
+    VkDevice                                    device,
+    uint32_t                                    queueFamilyIndex,
+    uint32_t                                    queueIndex,
+    VkQueue*                                    pQueue)
+{
+    VkBool32 skipCall = VK_FALSE;
+    layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
+
+    if (VK_FALSE == skipCall) {
+        // Call down the call chain:
+        my_data->device_dispatch_table->GetDeviceQueue(
+                device, queueFamilyIndex, queueIndex, pQueue);
+
+        // Remember the queue's handle, and link it to the device:
+        SwpDevice *pDevice = &my_data->deviceMap[device];
+        my_data->queueMap[&pQueue].queue = *pQueue;
+        if (pDevice) {
+            pDevice->queues[*pQueue] = &my_data->queueMap[*pQueue];
+        }
+        my_data->queueMap[&pQueue].pDevice = pDevice;
+        my_data->queueMap[&pQueue].queueFamilyIndex = queueFamilyIndex;
+    }
+}
+
+
 VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugReportCallbackEXT(
         VkInstance                                      instance,
         const VkDebugReportCallbackCreateInfoEXT*       pCreateInfo,
@@ -2169,6 +2252,8 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkD
         if (!strcmp("vkQueuePresentKHR", funcName))
             return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
     }
+    if (!strcmp("vkGetDeviceQueue", funcName))
+        return reinterpret_cast<PFN_vkVoidFunction>(vkGetDeviceQueue);
 
     if (pDisp->GetDeviceProcAddr == NULL)
         return NULL;
@@ -2191,6 +2276,8 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(V
         return (PFN_vkVoidFunction) vkEnumerateInstanceLayerProperties;
     if (!strcmp(funcName, "vkEnumerateInstanceExtensionProperties"))
         return (PFN_vkVoidFunction) vkEnumerateInstanceExtensionProperties;
+    if (!strcmp(funcName, "vkGetPhysicalDeviceQueueFamilyProperties"))
+        return (PFN_vkVoidFunction) vkGetPhysicalDeviceQueueFamilyProperties;
 
     if (instance == VK_NULL_HANDLE) {
         return NULL;
@@ -2206,8 +2293,6 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetInstanceProcAddr(V
         return addr;
     }
 
-    if (!strcmp("vkGetPhysicalDeviceQueueFamilyProperties", funcName))
-        return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceQueueFamilyProperties);
 #ifdef VK_USE_PLATFORM_ANDROID_KHR
     if (my_data->instanceMap.size() != 0 &&
         my_data->instanceMap[instance].androidSurfaceExtensionEnabled)
index 6fc3819..154b921 100644 (file)
@@ -89,8 +89,10 @@ typedef enum _SWAPCHAIN_ERROR
     SWAPCHAIN_WRONG_STYPE,                      // The sType for a struct has the wrong value
     SWAPCHAIN_WRONG_NEXT,                       // The pNext for a struct is not NULL
     SWAPCHAIN_ZERO_VALUE,                       // A value should be non-zero
-    SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by vkGetPhysicalDeviceQueueFamilyProperties()
     SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,           // pAllocator must be compatible (i.e. NULL or not) when object is created and destroyed
+    SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,     // A function using a queueFamilyIndex was called before vkGetPhysicalDeviceQueueFamilyProperties() was called
+    SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by vkGetPhysicalDeviceQueueFamilyProperties()
+    SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, // A surface is not supported by a given queueFamilyIndex, as seen by vkGetPhysicalDeviceSurfaceSupportKHR()
 } SWAPCHAIN_ERROR;
 
 
@@ -171,6 +173,7 @@ struct _SwpPhysicalDevice;
 struct _SwpDevice;
 struct _SwpSwapchain;
 struct _SwpImage;
+struct _SwpQueue;
 
 typedef _SwpInstance SwpInstance;
 typedef _SwpSurface SwpSurface;;
@@ -178,6 +181,7 @@ typedef _SwpPhysicalDevice SwpPhysicalDevice;
 typedef _SwpDevice SwpDevice;
 typedef _SwpSwapchain SwpSwapchain;
 typedef _SwpImage SwpImage;
+typedef _SwpQueue SwpQueue;
 
 // Create one of these for each VkInstance:
 struct _SwpInstance {
@@ -235,6 +239,16 @@ struct _SwpSurface {
 
     // 'true' if pAllocator was non-NULL when vkCreate*SurfaceKHR was called:
     bool usedAllocatorToCreate;
+
+    // Value of pQueueFamilyPropertyCount that was returned by the
+    // vkGetPhysicalDeviceQueueFamilyProperties() function:
+    uint32_t numQueueFamilyIndexSupport;
+    // Array of VkBool32's that is intialized by the
+    // vkGetPhysicalDeviceSurfaceSupportKHR() function.  First call for a given
+    // surface allocates and initializes this array to false for all
+    // queueFamilyIndex's (and sets numQueueFamilyIndexSupport to non-zero).
+    // All calls set the entry for a given queueFamilyIndex:
+    VkBool32 *pQueueFamilyIndexSupport;
 };
 
 // Create one of these for each VkPhysicalDevice within a VkInstance:
@@ -249,17 +263,13 @@ struct _SwpPhysicalDevice {
     SwpInstance *pInstance;
 
     // Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
-    // pQueueFamilyPropertyCount parameter when pQueueFamilyProperties is NULL:
+    // numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
     bool gotQueueFamilyPropertyCount;
-    uint32_t pQueueFamilyPropertyCount;
+    uint32_t numOfQueueFamilies;
 
-    // Record all supported queueFamilyIndex-surface pairs that support
-    // presenting with WSI swapchains:
-    unordered_map<uint32_t, VkSurfaceKHR> queueFamilyIndexSupport;
-
-    // Record all supported surface-queueFamilyIndex pairs that support
-    // presenting with WSI swapchains:
-    unordered_map<VkSurfaceKHR, uint32_t> surfaceSupport;
+    // Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
+    // called for:
+    unordered_map<const void*, SwpSurface*> supportedSurfaces;
 
 // TODO: Record/use this info per-surface, not per-device, once a
 // non-dispatchable surface object is added to WSI:
@@ -294,6 +304,9 @@ struct _SwpDevice {
     // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
     // remembered:
     unordered_map<VkSwapchainKHR, SwpSwapchain*> swapchains;
+
+    // When vkGetDeviceQueue is called, the VkQueue's are remembered:
+    unordered_map<VkQueue, SwpQueue*> queues;
 };
 
 // Create one of these for each VkImage within a VkSwapchainKHR:
@@ -329,6 +342,18 @@ struct _SwpSwapchain {
     bool usedAllocatorToCreate;
 };
 
+// Create one of these for each VkQueue within a VkDevice:
+struct _SwpQueue {
+    // The actual handle for this VkQueue:
+    VkQueue queue;
+
+    // Corresponding VkDevice (and info) to this VkSwapchainKHR:
+    SwpDevice *pDevice;
+
+    // Which queueFamilyIndex this VkQueue is associated with:
+    uint32_t queueFamilyIndex;
+};
+
 struct layer_data {
     debug_report_data *report_data;
     std::vector<VkDebugReportCallbackEXT> logging_callback;
@@ -341,6 +366,7 @@ struct layer_data {
     std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
     std::unordered_map<void *, SwpDevice>         deviceMap;
     std::unordered_map<VkSwapchainKHR, SwpSwapchain>    swapchainMap;
+    std::unordered_map<void *, SwpQueue>          queueMap;
 
     layer_data() :
         report_data(nullptr),
index 5ebe0d7..3d6d9ee 100644 (file)
@@ -348,7 +348,7 @@ This layer is a work in progress. VK_LAYER_LUNARG_swapchain layer is intended to
 | Valid pointer | If a NULL pointer is used, this error will be flagged | NULL_POINTER | vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfacePresentModesKHR vkCreateSwapchainKHR vkGetSwapchainImagesKHR vkAcquireNextImageKHR vkQueuePresentKHR | NA | None |
 | Extension enabled before use | Validates that a WSI extension is enabled before its functions are used | EXT_NOT_ENABLED_BUT_USED | vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfacePresentModesKHR vkCreateSwapchainKHR vkDestroySwapchainKHR vkGetSwapchainImagesKHR vkAcquireNextImageKHR vkQueuePresentKHR | NA | None |
 | Swapchains destroyed before devices | Validates that  vkDestroySwapchainKHR() is called for all swapchains associated with a device before vkDestroyDevice() is called | DEL_OBJECT_BEFORE_CHILDREN | vkDestroyDevice vkDestroySurfaceKHR | NA | None |
-| Supported surface used with a swapchain | Validates that vkGetPhysicalDeviceSurfaceSupportKHR() was seen to support the surface used with a swapchain | CREATE_SWAP_UNSUPPORTED_SURFACE | vkCreateSwapchainKHR | NA | None |
+| Surface seen to support presentation | Validates that pCreateInfo->surface was seen by vkGetPhysicalDeviceSurfaceSupportKHR() to support presentation | CREATE_UNSUPPORTED_SURFACE | vkCreateSwapchainKHR | NA | None |
 | Queries occur before swapchain creation | Validates that vkGetPhysicalDeviceSurfaceCapabilitiesKHR(), vkGetPhysicalDeviceSurfaceFormatsKHR() and vkGetPhysicalDeviceSurfacePresentModesKHR() are called before vkCreateSwapchainKHR() | CREATE_SWAP_WITHOUT_QUERY | vkCreateSwapchainKHR | NA | None |
 | vkCreateSwapchainKHR(pCreateInfo->minImageCount) | Validates vkCreateSwapchainKHR(pCreateInfo->minImageCount) | CREATE_SWAP_BAD_MIN_IMG_COUNT | vkCreateSwapchainKHR | NA | None |
 | vkCreateSwapchainKHR(pCreateInfo->imageExtent) | Validates vkCreateSwapchainKHR(pCreateInfo->imageExtent) when window has no fixed size | CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS | vkCreateSwapchainKHR | NA | None |
@@ -373,8 +373,10 @@ This layer is a work in progress. VK_LAYER_LUNARG_swapchain layer is intended to
 | Valid sType | Validates that a struct has correct value for sType | WRONG_STYPE | vkCreateSwapchainKHR vkQueuePresentKHR | NA | None |
 | Valid pNext | Validates that a struct has NULL for the value of pNext | WRONG_NEXT | vkCreateSwapchainKHR vkQueuePresentKHR | NA | None |
 | Non-zero value | Validates that a required value should be non-zero | ZERO_VALUE | vkQueuePresentKHR | NA | None |
-| Valid queueFamilyIndex value | Validates that a queueFamilyIndex value is less-than  pQueueFamilyPropertyCount returned by vkGetPhysicalDeviceQueueFamilyProperties | ZERO_VALUE | vkGetPhysicalDeviceSurfaceSupportKHR | NA | None |
 | Compaitible Allocator | Validates that pAllocator is compatible (i.e. NULL or not) when an object is created and destroyed | INCOMPATIBLE_ALLOCATOR | vkDestroySurfaceKHR | NA | None |
+| Valid use of queueFamilyIndex | Validates that a queueFamilyIndex not used before vkGetPhysicalDeviceQueueFamilyProperties() was called | DID_NOT_QUERY_QUEUE_FAMILIES | vkGetPhysicalDeviceSurfaceSupportKHR | NA | None |
+| Valid queueFamilyIndex value | Validates that a queueFamilyIndex value is less-than pQueueFamilyPropertyCount returned by vkGetPhysicalDeviceQueueFamilyProperties | QUEUE_FAMILY_INDEX_TOO_LARGE | vkGetPhysicalDeviceSurfaceSupportKHR | NA | None |
+| Supported combination of queue and surface | Validates that the surface associated with a swapchain was seen to support the queueFamilyIndex of a given queue | SURFACE_NOT_SUPPORTED_WITH_QUEUE | vkQueuePresentKHR | NA | None |
 
 Note: The following platform-specific functions are not mentioned above, because they are protected by ifdefs, which cause test failures: