Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  * Copyright (C) 2015-2016 Google Inc.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *     http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  *
     18  * Author: Ian Elliott <ian (at) lunarg.com>
     19  * Author: Ian Elliott <ianelliott (at) google.com>
     20  */
     21 
     22 #ifndef SWAPCHAIN_H
     23 #define SWAPCHAIN_H
     24 
     25 #include "vulkan/vk_layer.h"
     26 #include "vk_layer_config.h"
     27 #include "vk_layer_logging.h"
     28 #include <vector>
     29 #include <unordered_map>
     30 
     31 using namespace std;
     32 
     33 // Swapchain ERROR codes
     34 enum SWAPCHAIN_ERROR {
     35     SWAPCHAIN_INVALID_HANDLE,             // Handle used that isn't currently valid
     36     SWAPCHAIN_NULL_POINTER,               // Pointer set to NULL, instead of being a valid pointer
     37     SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,   // Did not enable WSI extension, but called WSI function
     38     SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN, // Called vkDestroyDevice() before vkDestroySwapchainKHR()
     39     SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE, // Called vkCreateSwapchainKHR() with a pCreateInfo->surface that wasn't seen as supported
     40                                           // by vkGetPhysicalDeviceSurfaceSupportKHR for the device
     41     SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,  // Called vkCreateSwapchainKHR() without calling a query (e.g.
     42                                           // vkGetPhysicalDeviceSurfaceCapabilitiesKHR())
     43     SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,     // Called vkCreateSwapchainKHR() with out-of-bounds minImageCount
     44     SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS, // Called vkCreateSwapchainKHR() with out-of-bounds imageExtent
     45     SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, // Called vkCreateSwapchainKHR() with imageExtent that doesn't match window's extent
     46     SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,    // Called vkCreateSwapchainKHR() with a non-supported preTransform
     47     SWAPCHAIN_CREATE_SWAP_BAD_COMPOSITE_ALPHA,  // Called vkCreateSwapchainKHR() with a non-supported compositeAlpha
     48     SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,   // Called vkCreateSwapchainKHR() with a non-supported imageArraySize
     49     SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,  // Called vkCreateSwapchainKHR() with a non-supported imageUsageFlags
     50     SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,  // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
     51     SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,       // Called vkCreateSwapchainKHR() with a non-supported imageFormat
     52     SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,   // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
     53     SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,     // Called vkCreateSwapchainKHR() with a non-supported presentMode
     54     SWAPCHAIN_CREATE_SWAP_BAD_SHARING_MODE,     // Called vkCreateSwapchainKHR() with a non-supported imageSharingMode
     55     SWAPCHAIN_CREATE_SWAP_BAD_SHARING_VALUES,   // Called vkCreateSwapchainKHR() with bad values when imageSharingMode is
     56                                                 // VK_SHARING_MODE_CONCURRENT
     57     SWAPCHAIN_CREATE_SWAP_DIFF_SURFACE, // Called vkCreateSwapchainKHR() with pCreateInfo->oldSwapchain that has a different surface
     58                                         // than pCreateInfo->surface
     59     SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE, // Called vkDestroySwapchainKHR() with a different VkDevice than vkCreateSwapchainKHR()
     60     SWAPCHAIN_APP_ACQUIRES_TOO_MANY_IMAGES, // vkAcquireNextImageKHR() asked for more images than are available
     61     SWAPCHAIN_INDEX_TOO_LARGE,          // Index is too large for swapchain
     62     SWAPCHAIN_INDEX_NOT_IN_USE,         // vkQueuePresentKHR() given index that is not acquired by app
     63     SWAPCHAIN_BAD_BOOL,                 // VkBool32 that doesn't have value of VK_TRUE or VK_FALSE (e.g. is a non-zero form of true)
     64     SWAPCHAIN_PRIOR_COUNT,              // Query must be called first to get value of pCount, then called second time
     65     SWAPCHAIN_INVALID_COUNT,            // Second time a query called, the pCount value didn't match first time
     66     SWAPCHAIN_WRONG_STYPE,              // The sType for a struct has the wrong value
     67     SWAPCHAIN_WRONG_NEXT,               // The pNext for a struct is not NULL
     68     SWAPCHAIN_ZERO_VALUE,               // A value should be non-zero
     69     SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,   // pAllocator must be compatible (i.e. NULL or not) when object is created and destroyed
     70     SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,     // A function using a queueFamilyIndex was called before
     71                                                 // vkGetPhysicalDeviceQueueFamilyProperties() was called
     72     SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by
     73                                                 // vkGetPhysicalDeviceQueueFamilyProperties()
     74     SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, // A surface is not supported by a given queueFamilyIndex, as seen by
     75                                                 // vkGetPhysicalDeviceSurfaceSupportKHR()
     76     SWAPCHAIN_NO_SYNC_FOR_ACQUIRE,      // vkAcquireNextImageKHR should be called with a valid semaphore and/or fence
     77 };
     78 
     79 // The following is for logging error messages:
     80 #define LAYER_NAME (char *) "Swapchain"
     81 #define LOG_ERROR_NON_VALID_OBJ(objType, type, obj)                                                                                \
     82     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__,                 \
     83                         SWAPCHAIN_INVALID_HANDLE, LAYER_NAME, "%s() called with a non-valid %s.", __FUNCTION__, (obj))             \
     84               : VK_FALSE
     85 #define LOG_ERROR_NULL_POINTER(objType, type, obj)                                                                                 \
     86     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
     87                         SWAPCHAIN_NULL_POINTER, LAYER_NAME, "%s() called with NULL pointer %s.", __FUNCTION__, (obj))              \
     88               : VK_FALSE
     89 #define LOG_ERROR_INVALID_COUNT(objType, type, obj, obj2, val, val2)                                                               \
     90     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
     91                         SWAPCHAIN_INVALID_COUNT, LAYER_NAME, "%s() called with non-NULL %s, and with %s set to a "                 \
     92                                                              "value (%d) that is greater than the value (%d) that "                \
     93                                                              "was returned when %s was NULL.",                                     \
     94                         __FUNCTION__, (obj2), (obj), (val), (val2), (obj2))                                                        \
     95               : VK_FALSE
     96 #define LOG_ERROR_ZERO_PRIOR_COUNT(objType, type, obj, obj2)                                                                       \
     97     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
     98                         SWAPCHAIN_PRIOR_COUNT, LAYER_NAME, "%s() called with non-NULL %s; but no prior "                           \
     99                         "positive value has been seen for %s.",                                                                    \
    100                         __FUNCTION__, (obj), (obj2))                                                                               \
    101               : VK_FALSE
    102 #define LOG_ERROR_WRONG_STYPE(objType, type, obj, val)                                                                             \
    103     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_WRONG_STYPE, \
    104                         LAYER_NAME, "%s() called with the wrong value for %s->sType "                                              \
    105                                     "(expected %s).",                                                                              \
    106                         __FUNCTION__, (obj), (val))                                                                                \
    107               : VK_FALSE
    108 #define LOG_ERROR_ZERO_VALUE(objType, type, obj)                                                                                   \
    109     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_ZERO_VALUE,  \
    110                         LAYER_NAME, "%s() called with a zero value for %s.", __FUNCTION__, (obj))                                  \
    111               : VK_FALSE
    112 #define LOG_ERROR(objType, type, obj, enm, fmt, ...)                                                                               \
    113     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm),          \
    114                         LAYER_NAME, (fmt), __VA_ARGS__)                                                                            \
    115               : VK_FALSE
    116 #define LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(objType, type, obj, val1, val2)                                                     \
    117     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
    118                         SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE, LAYER_NAME, "%s() called with a queueFamilyIndex that is too "     \
    119                                                                             "large (i.e. %d).  The maximum value (returned "       \
    120                                                                             "by vkGetPhysicalDeviceQueueFamilyProperties) is "     \
    121                                                                             "only %d.\n",                                          \
    122                         __FUNCTION__, (val1), (val2))                                                                              \
    123               : VK_FALSE
    124 #define LOG_PERF_WARNING(objType, type, obj, enm, fmt, ...)                                                                        \
    125     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__,   \
    126                         (enm), LAYER_NAME, (fmt), __VA_ARGS__)                                                                     \
    127               : VK_FALSE
    128 #define LOG_WARNING(objType, type, obj, enm, fmt, ...)                                                                             \
    129     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm),        \
    130                         LAYER_NAME, (fmt), __VA_ARGS__)                                                                            \
    131               : VK_FALSE
    132 #define LOG_INFO_WRONG_NEXT(objType, type, obj)                                                                                    \
    133     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (objType), (uint64_t)(obj), 0,                  \
    134                         SWAPCHAIN_WRONG_NEXT, LAYER_NAME, "%s() called with non-NULL value for %s->pNext.", __FUNCTION__, (obj))   \
    135               : VK_FALSE
    136 
    137 // NOTE: The following struct's/typedef's are for keeping track of
    138 // info that is used for validating the WSI extensions.
    139 
    140 // Forward declarations:
    141 struct SwpInstance;
    142 struct SwpSurface;
    143 struct SwpPhysicalDevice;
    144 struct SwpDevice;
    145 struct SwpSwapchain;
    146 struct SwpImage;
    147 struct SwpQueue;
    148 
    149 // Create one of these for each VkInstance:
    150 struct SwpInstance {
    151     // The actual handle for this VkInstance:
    152     VkInstance instance;
    153 
    154     // Remember the VkSurfaceKHR's that are created for this VkInstance:
    155     unordered_map<VkSurfaceKHR, SwpSurface *> surfaces;
    156 
    157     // When vkEnumeratePhysicalDevices is called, the VkPhysicalDevice's are
    158     // remembered:
    159     unordered_map<const void *, SwpPhysicalDevice *> physicalDevices;
    160 
    161     // Set to true if VK_KHR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    162     bool surfaceExtensionEnabled;
    163 
    164 // TODO: Add additional booleans for platform-specific extensions:
    165 #ifdef VK_USE_PLATFORM_ANDROID_KHR
    166     // Set to true if VK_KHR_ANDROID_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    167     bool androidSurfaceExtensionEnabled;
    168 #endif // VK_USE_PLATFORM_ANDROID_KHR
    169 #ifdef VK_USE_PLATFORM_MIR_KHR
    170     // Set to true if VK_KHR_MIR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    171     bool mirSurfaceExtensionEnabled;
    172 #endif // VK_USE_PLATFORM_MIR_KHR
    173 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
    174     // Set to true if VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    175     bool waylandSurfaceExtensionEnabled;
    176 #endif // VK_USE_PLATFORM_WAYLAND_KHR
    177 #ifdef VK_USE_PLATFORM_WIN32_KHR
    178     // Set to true if VK_KHR_WIN32_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    179     bool win32SurfaceExtensionEnabled;
    180 #endif // VK_USE_PLATFORM_WIN32_KHR
    181 #ifdef VK_USE_PLATFORM_XCB_KHR
    182     // Set to true if VK_KHR_XCB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    183     bool xcbSurfaceExtensionEnabled;
    184 #endif // VK_USE_PLATFORM_XCB_KHR
    185 #ifdef VK_USE_PLATFORM_XLIB_KHR
    186     // Set to true if VK_KHR_XLIB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    187     bool xlibSurfaceExtensionEnabled;
    188 #endif // VK_USE_PLATFORM_XLIB_KHR
    189 };
    190 
    191 // Create one of these for each VkSurfaceKHR:
    192 struct SwpSurface {
    193     // The actual handle for this VkSurfaceKHR:
    194     VkSurfaceKHR surface;
    195 
    196     // VkInstance that this VkSurfaceKHR is associated with:
    197     SwpInstance *pInstance;
    198 
    199     // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
    200     // remembered:
    201     unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
    202 
    203     // 'true' if pAllocator was non-NULL when vkCreate*SurfaceKHR was called:
    204     bool usedAllocatorToCreate;
    205 
    206     // Value of pQueueFamilyPropertyCount that was returned by the
    207     // vkGetPhysicalDeviceQueueFamilyProperties() function:
    208     uint32_t numQueueFamilyIndexSupport;
    209     // Array of VkBool32's that is intialized by the
    210     // vkGetPhysicalDeviceSurfaceSupportKHR() function.  First call for a given
    211     // surface allocates and initializes this array to false for all
    212     // queueFamilyIndex's (and sets numQueueFamilyIndexSupport to non-zero).
    213     // All calls set the entry for a given queueFamilyIndex:
    214     VkBool32 *pQueueFamilyIndexSupport;
    215 };
    216 
    217 // Create one of these for each VkPhysicalDevice within a VkInstance:
    218 struct SwpPhysicalDevice {
    219     // The actual handle for this VkPhysicalDevice:
    220     VkPhysicalDevice physicalDevice;
    221 
    222     // Corresponding VkDevice (and info) to this VkPhysicalDevice:
    223     SwpDevice *pDevice;
    224 
    225     // VkInstance that this VkPhysicalDevice is associated with:
    226     SwpInstance *pInstance;
    227 
    228     // Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
    229     // numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
    230     bool gotQueueFamilyPropertyCount;
    231     uint32_t numOfQueueFamilies;
    232 
    233     // Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
    234     // called for:
    235     unordered_map<VkSurfaceKHR, SwpSurface *> supportedSurfaces;
    236 
    237     // TODO: Record/use this info per-surface, not per-device, once a
    238     // non-dispatchable surface object is added to WSI:
    239     // Results of vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
    240     bool gotSurfaceCapabilities;
    241     VkSurfaceCapabilitiesKHR surfaceCapabilities;
    242 
    243     // TODO: Record/use this info per-surface, not per-device, once a
    244     // non-dispatchable surface object is added to WSI:
    245     // Count and VkSurfaceFormatKHR's returned by vkGetPhysicalDeviceSurfaceFormatsKHR():
    246     uint32_t surfaceFormatCount;
    247     VkSurfaceFormatKHR *pSurfaceFormats;
    248 
    249     // TODO: Record/use this info per-surface, not per-device, once a
    250     // non-dispatchable surface object is added to WSI:
    251     // Count and VkPresentModeKHR's returned by vkGetPhysicalDeviceSurfacePresentModesKHR():
    252     uint32_t presentModeCount;
    253     VkPresentModeKHR *pPresentModes;
    254 };
    255 
    256 // Create one of these for each VkDevice within a VkInstance:
    257 struct SwpDevice {
    258     // The actual handle for this VkDevice:
    259     VkDevice device;
    260 
    261     // Corresponding VkPhysicalDevice (and info) to this VkDevice:
    262     SwpPhysicalDevice *pPhysicalDevice;
    263 
    264     // Set to true if VK_KHR_SWAPCHAIN_EXTENSION_NAME was enabled:
    265     bool swapchainExtensionEnabled;
    266 
    267     // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
    268     // remembered:
    269     unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
    270 
    271     // When vkGetDeviceQueue is called, the VkQueue's are remembered:
    272     unordered_map<VkQueue, SwpQueue *> queues;
    273 };
    274 
    275 // Create one of these for each VkImage within a VkSwapchainKHR:
    276 struct SwpImage {
    277     // The actual handle for this VkImage:
    278     VkImage image;
    279 
    280     // Corresponding VkSwapchainKHR (and info) to this VkImage:
    281     SwpSwapchain *pSwapchain;
    282 
    283     // true if application acquired this image from vkAcquireNextImageKHR(),
    284     // and hasn't yet called vkQueuePresentKHR() for it; otherwise false:
    285     bool acquiredByApp;
    286 };
    287 
    288 // Create one of these for each VkSwapchainKHR within a VkDevice:
    289 struct SwpSwapchain {
    290     // The actual handle for this VkSwapchainKHR:
    291     VkSwapchainKHR swapchain;
    292 
    293     // Corresponding VkDevice (and info) to this VkSwapchainKHR:
    294     SwpDevice *pDevice;
    295 
    296     // Corresponding VkSurfaceKHR to this VkSwapchainKHR:
    297     SwpSurface *pSurface;
    298 
    299     // When vkGetSwapchainImagesKHR is called, the VkImage's are
    300     // remembered:
    301     uint32_t imageCount;
    302     unordered_map<int, SwpImage> images;
    303 
    304     // 'true' if pAllocator was non-NULL when vkCreateSwapchainKHR was called:
    305     bool usedAllocatorToCreate;
    306 };
    307 
    308 // Create one of these for each VkQueue within a VkDevice:
    309 struct SwpQueue {
    310     // The actual handle for this VkQueue:
    311     VkQueue queue;
    312 
    313     // Corresponding VkDevice (and info) to this VkSwapchainKHR:
    314     SwpDevice *pDevice;
    315 
    316     // Which queueFamilyIndex this VkQueue is associated with:
    317     uint32_t queueFamilyIndex;
    318 };
    319 
    320 struct layer_data {
    321     VkInstance instance;
    322 
    323     debug_report_data *report_data;
    324     std::vector<VkDebugReportCallbackEXT> logging_callback;
    325     VkLayerDispatchTable *device_dispatch_table;
    326     VkLayerInstanceDispatchTable *instance_dispatch_table;
    327 
    328     // The following are for keeping track of the temporary callbacks that can
    329     // be used in vkCreateInstance and vkDestroyInstance:
    330     uint32_t num_tmp_callbacks;
    331     VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
    332     VkDebugReportCallbackEXT *tmp_callbacks;
    333 
    334     // NOTE: The following are for keeping track of info that is used for
    335     // validating the WSI extensions.
    336     std::unordered_map<void *, SwpInstance> instanceMap;
    337     std::unordered_map<VkSurfaceKHR, SwpSurface> surfaceMap;
    338     std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
    339     std::unordered_map<void *, SwpDevice> deviceMap;
    340     std::unordered_map<VkSwapchainKHR, SwpSwapchain> swapchainMap;
    341     std::unordered_map<void *, SwpQueue> queueMap;
    342 
    343     layer_data()
    344         : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), num_tmp_callbacks(0),
    345           tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr){};
    346 };
    347 
    348 #endif // SWAPCHAIN_H
    349