/* Copyright (c) 2015-2016 The Khronos Group Inc.
* Copyright (c) 2015-2016 Valve Corporation
* Copyright (c) 2015-2016 LunarG, Inc.
* Copyright (C) 2015-2016 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Author: Ian Elliott <ian@lunarg.com>
* Author: Ian Elliott <ianelliott@google.com>
*/
#ifndef SWAPCHAIN_H
#define SWAPCHAIN_H
#include "vulkan/vk_layer.h"
#include "vk_layer_config.h"
#include "vk_layer_logging.h"
#include <vector>
#include <unordered_map>
using namespace std;
// Swapchain ERROR codes
enum SWAPCHAIN_ERROR {
SWAPCHAIN_INVALID_HANDLE, // Handle used that isn't currently valid
SWAPCHAIN_NULL_POINTER, // Pointer set to NULL, instead of being a valid pointer
SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED, // Did not enable WSI extension, but called WSI function
SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN, // Called vkDestroyDevice() before vkDestroySwapchainKHR()
SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE, // Called vkCreateSwapchainKHR() with a pCreateInfo->surface that wasn't seen as supported
// by vkGetPhysicalDeviceSurfaceSupportKHR for the device
SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY, // Called vkCreateSwapchainKHR() without calling a query (e.g.
// vkGetPhysicalDeviceSurfaceCapabilitiesKHR())
SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT, // Called vkCreateSwapchainKHR() with out-of-bounds minImageCount
SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS, // Called vkCreateSwapchainKHR() with out-of-bounds imageExtent
SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, // Called vkCreateSwapchainKHR() with imageExtent that doesn't match window's extent
SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM, // Called vkCreateSwapchainKHR() with a non-supported preTransform
SWAPCHAIN_CREATE_SWAP_BAD_COMPOSITE_ALPHA, // Called vkCreateSwapchainKHR() with a non-supported compositeAlpha
SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE, // Called vkCreateSwapchainKHR() with a non-supported imageArraySize
SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS, // Called vkCreateSwapchainKHR() with a non-supported imageUsageFlags
SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE, // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT, // Called vkCreateSwapchainKHR() with a non-supported imageFormat
SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP, // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE, // Called vkCreateSwapchainKHR() with a non-supported presentMode
SWAPCHAIN_CREATE_SWAP_BAD_SHARING_MODE, // Called vkCreateSwapchainKHR() with a non-supported imageSharingMode
SWAPCHAIN_CREATE_SWAP_BAD_SHARING_VALUES, // Called vkCreateSwapchainKHR() with bad values when imageSharingMode is
// VK_SHARING_MODE_CONCURRENT
SWAPCHAIN_CREATE_SWAP_DIFF_SURFACE, // Called vkCreateSwapchainKHR() with pCreateInfo->oldSwapchain that has a different surface
// than pCreateInfo->surface
SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE, // Called vkDestroySwapchainKHR() with a different VkDevice than vkCreateSwapchainKHR()
SWAPCHAIN_APP_ACQUIRES_TOO_MANY_IMAGES, // vkAcquireNextImageKHR() asked for more images than are available
SWAPCHAIN_INDEX_TOO_LARGE, // Index is too large for swapchain
SWAPCHAIN_INDEX_NOT_IN_USE, // vkQueuePresentKHR() given index that is not acquired by app
SWAPCHAIN_BAD_BOOL, // VkBool32 that doesn't have value of VK_TRUE or VK_FALSE (e.g. is a non-zero form of true)
SWAPCHAIN_PRIOR_COUNT, // Query must be called first to get value of pCount, then called second time
SWAPCHAIN_INVALID_COUNT, // Second time a query called, the pCount value didn't match first time
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_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_NO_SYNC_FOR_ACQUIRE, // vkAcquireNextImageKHR should be called with a valid semaphore and/or fence
};
// The following is for logging error messages:
#define LAYER_NAME (char *) "Swapchain"
#define LOG_ERROR_NON_VALID_OBJ(objType, type, obj) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, \
SWAPCHAIN_INVALID_HANDLE, LAYER_NAME, "%s() called with a non-valid %s.", __FUNCTION__, (obj)) \
: VK_FALSE
#define LOG_ERROR_NULL_POINTER(objType, type, obj) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, \
SWAPCHAIN_NULL_POINTER, LAYER_NAME, "%s() called with NULL pointer %s.", __FUNCTION__, (obj)) \
: VK_FALSE
#define LOG_ERROR_INVALID_COUNT(objType, type, obj, obj2, val, val2) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, \
SWAPCHAIN_INVALID_COUNT, LAYER_NAME, "%s() called with non-NULL %s, and with %s set to a " \
"value (%d) that is greater than the value (%d) that " \
"was returned when %s was NULL.", \
__FUNCTION__, (obj2), (obj), (val), (val2), (obj2)) \
: VK_FALSE
#define LOG_ERROR_ZERO_PRIOR_COUNT(objType, type, obj, obj2) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, \
SWAPCHAIN_PRIOR_COUNT, LAYER_NAME, "%s() called with non-NULL %s; but no prior " \
"positive value has been seen for %s.", \
__FUNCTION__, (obj), (obj2)) \
: VK_FALSE
#define LOG_ERROR_WRONG_STYPE(objType, type, obj, val) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_WRONG_STYPE, \
LAYER_NAME, "%s() called with the wrong value for %s->sType " \
"(expected %s).", \
__FUNCTION__, (obj), (val)) \
: VK_FALSE
#define LOG_ERROR_ZERO_VALUE(objType, type, obj) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_ZERO_VALUE, \
LAYER_NAME, "%s() called with a zero value for %s.", __FUNCTION__, (obj)) \
: VK_FALSE
#define LOG_ERROR(objType, type, obj, enm, fmt, ...) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm), \
LAYER_NAME, (fmt), __VA_ARGS__) \
: VK_FALSE
#define LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(objType, type, obj, val1, val2) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, \
SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE, LAYER_NAME, "%s() called with a queueFamilyIndex that is too " \
"large (i.e. %d). The maximum value (returned " \
"by vkGetPhysicalDeviceQueueFamilyProperties) is " \
"only %d.\n", \
__FUNCTION__, (val1), (val2)) \
: VK_FALSE
#define LOG_PERF_WARNING(objType, type, obj, enm, fmt, ...) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, \
(enm), LAYER_NAME, (fmt), __VA_ARGS__) \
: VK_FALSE
#define LOG_WARNING(objType, type, obj, enm, fmt, ...) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm), \
LAYER_NAME, (fmt), __VA_ARGS__) \
: VK_FALSE
#define LOG_INFO_WRONG_NEXT(objType, type, obj) \
(my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (objType), (uint64_t)(obj), 0, \
SWAPCHAIN_WRONG_NEXT, LAYER_NAME, "%s() called with non-NULL value for %s->pNext.", __FUNCTION__, (obj)) \
: VK_FALSE
// NOTE: The following struct's/typedef's are for keeping track of
// info that is used for validating the WSI extensions.
// Forward declarations:
struct SwpInstance;
struct SwpSurface;
struct SwpPhysicalDevice;
struct SwpDevice;
struct SwpSwapchain;
struct SwpImage;
struct SwpQueue;
// Create one of these for each VkInstance:
struct SwpInstance {
// The actual handle for this VkInstance:
VkInstance instance;
// Remember the VkSurfaceKHR's that are created for this VkInstance:
unordered_map<VkSurfaceKHR, SwpSurface *> surfaces;
// When vkEnumeratePhysicalDevices is called, the VkPhysicalDevice's are
// remembered:
unordered_map<const void *, SwpPhysicalDevice *> physicalDevices;
// Set to true if VK_KHR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool surfaceExtensionEnabled;
// TODO: Add additional booleans for platform-specific extensions:
#ifdef VK_USE_PLATFORM_ANDROID_KHR
// Set to true if VK_KHR_ANDROID_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool androidSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_USE_PLATFORM_MIR_KHR
// Set to true if VK_KHR_MIR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool mirSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_MIR_KHR
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
// Set to true if VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool waylandSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_USE_PLATFORM_WIN32_KHR
// Set to true if VK_KHR_WIN32_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool win32SurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_USE_PLATFORM_XCB_KHR
// Set to true if VK_KHR_XCB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool xcbSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_XCB_KHR
#ifdef VK_USE_PLATFORM_XLIB_KHR
// Set to true if VK_KHR_XLIB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
bool xlibSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_XLIB_KHR
};
// Create one of these for each VkSurfaceKHR:
struct SwpSurface {
// The actual handle for this VkSurfaceKHR:
VkSurfaceKHR surface;
// VkInstance that this VkSurfaceKHR is associated with:
SwpInstance *pInstance;
// When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
// remembered:
unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
// '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:
struct SwpPhysicalDevice {
// The actual handle for this VkPhysicalDevice:
VkPhysicalDevice physicalDevice;
// Corresponding VkDevice (and info) to this VkPhysicalDevice:
SwpDevice *pDevice;
// VkInstance that this VkPhysicalDevice is associated with:
SwpInstance *pInstance;
// Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
// numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
bool gotQueueFamilyPropertyCount;
uint32_t numOfQueueFamilies;
// Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
// called for:
unordered_map<VkSurfaceKHR, SwpSurface *> supportedSurfaces;
// TODO: Record/use this info per-surface, not per-device, once a
// non-dispatchable surface object is added to WSI:
// Results of vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
bool gotSurfaceCapabilities;
VkSurfaceCapabilitiesKHR surfaceCapabilities;
// TODO: Record/use this info per-surface, not per-device, once a
// non-dispatchable surface object is added to WSI:
// Count and VkSurfaceFormatKHR's returned by vkGetPhysicalDeviceSurfaceFormatsKHR():
uint32_t surfaceFormatCount;
VkSurfaceFormatKHR *pSurfaceFormats;
// TODO: Record/use this info per-surface, not per-device, once a
// non-dispatchable surface object is added to WSI:
// Count and VkPresentModeKHR's returned by vkGetPhysicalDeviceSurfacePresentModesKHR():
uint32_t presentModeCount;
VkPresentModeKHR *pPresentModes;
};
// Create one of these for each VkDevice within a VkInstance:
struct SwpDevice {
// The actual handle for this VkDevice:
VkDevice device;
// Corresponding VkPhysicalDevice (and info) to this VkDevice:
SwpPhysicalDevice *pPhysicalDevice;
// Set to true if VK_KHR_SWAPCHAIN_EXTENSION_NAME was enabled:
bool swapchainExtensionEnabled;
// 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:
struct SwpImage {
// The actual handle for this VkImage:
VkImage image;
// Corresponding VkSwapchainKHR (and info) to this VkImage:
SwpSwapchain *pSwapchain;
// true if application acquired this image from vkAcquireNextImageKHR(),
// and hasn't yet called vkQueuePresentKHR() for it; otherwise false:
bool acquiredByApp;
};
// Create one of these for each VkSwapchainKHR within a VkDevice:
struct SwpSwapchain {
// The actual handle for this VkSwapchainKHR:
VkSwapchainKHR swapchain;
// Corresponding VkDevice (and info) to this VkSwapchainKHR:
SwpDevice *pDevice;
// Corresponding VkSurfaceKHR to this VkSwapchainKHR:
SwpSurface *pSurface;
// When vkGetSwapchainImagesKHR is called, the VkImage's are
// remembered:
uint32_t imageCount;
unordered_map<int, SwpImage> images;
// 'true' if pAllocator was non-NULL when vkCreateSwapchainKHR was called:
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 {
VkInstance instance;
debug_report_data *report_data;
std::vector<VkDebugReportCallbackEXT> logging_callback;
VkLayerDispatchTable *device_dispatch_table;
VkLayerInstanceDispatchTable *instance_dispatch_table;
// The following are for keeping track of the temporary callbacks that can
// be used in vkCreateInstance and vkDestroyInstance:
uint32_t num_tmp_callbacks;
VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
VkDebugReportCallbackEXT *tmp_callbacks;
// NOTE: The following are for keeping track of info that is used for
// validating the WSI extensions.
std::unordered_map<void *, SwpInstance> instanceMap;
std::unordered_map<VkSurfaceKHR, SwpSurface> surfaceMap;
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), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), num_tmp_callbacks(0),
tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr){};
};
#endif // SWAPCHAIN_H