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  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and/or associated documentation files (the "Materials"), to
8  * deal in the Materials without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Materials, and to permit persons to whom the Materials
11  * are furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice(s) and this permission notice shall be included
14  * in all copies or substantial portions of the Materials.
15  *
16  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  *
20  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
22  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
23  * USE OR OTHER DEALINGS IN THE MATERIALS
24  *
25  * Author: Ian Elliott <ian@lunarg.com>
26  * Author: Ian Elliott <ianelliott@google.com>
27  */
28 
29 #ifndef SWAPCHAIN_H
30 #define SWAPCHAIN_H
31 
32 #include "vulkan/vk_layer.h"
33 #include "vk_layer_config.h"
34 #include "vk_layer_logging.h"
35 #include <vector>
36 #include <unordered_map>
37 
38 using namespace std;
39 
40 // Swapchain ERROR codes
41 typedef enum _SWAPCHAIN_ERROR {
42     SWAPCHAIN_INVALID_HANDLE,             // Handle used that isn't currently valid
43     SWAPCHAIN_NULL_POINTER,               // Pointer set to NULL, instead of being a valid pointer
44     SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,   // Did not enable WSI extension, but called WSI function
45     SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN, // Called vkDestroyDevice() before vkDestroySwapchainKHR()
46     SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE, // Called vkCreateSwapchainKHR() with a pCreateInfo->surface that wasn't seen as supported
47                                           // by vkGetPhysicalDeviceSurfaceSupportKHR for the device
48     SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,  // Called vkCreateSwapchainKHR() without calling a query (e.g.
49                                           // vkGetPhysicalDeviceSurfaceCapabilitiesKHR())
50     SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,     // Called vkCreateSwapchainKHR() with out-of-bounds minImageCount
51     SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS, // Called vkCreateSwapchainKHR() with out-of-bounds imageExtent
52     SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, // Called vkCreateSwapchainKHR() with imageExtent that doesn't match window's extent
53     SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,    // Called vkCreateSwapchainKHR() with a non-supported preTransform
54     SWAPCHAIN_CREATE_SWAP_BAD_COMPOSITE_ALPHA,  // Called vkCreateSwapchainKHR() with a non-supported compositeAlpha
55     SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,   // Called vkCreateSwapchainKHR() with a non-supported imageArraySize
56     SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,  // Called vkCreateSwapchainKHR() with a non-supported imageUsageFlags
57     SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,  // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
58     SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,       // Called vkCreateSwapchainKHR() with a non-supported imageFormat
59     SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,   // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
60     SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,     // Called vkCreateSwapchainKHR() with a non-supported presentMode
61     SWAPCHAIN_CREATE_SWAP_BAD_SHARING_MODE,     // Called vkCreateSwapchainKHR() with a non-supported imageSharingMode
62     SWAPCHAIN_CREATE_SWAP_BAD_SHARING_VALUES,   // Called vkCreateSwapchainKHR() with bad values when imageSharingMode is
63                                                 // VK_SHARING_MODE_CONCURRENT
64     SWAPCHAIN_CREATE_SWAP_DIFF_SURFACE, // Called vkCreateSwapchainKHR() with pCreateInfo->oldSwapchain that has a different surface
65                                         // than pCreateInfo->surface
66     SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE, // Called vkDestroySwapchainKHR() with a different VkDevice than vkCreateSwapchainKHR()
67     SWAPCHAIN_APP_OWNS_TOO_MANY_IMAGES, // vkAcquireNextImageKHR() asked for more images than are available
68     SWAPCHAIN_INDEX_TOO_LARGE,          // Index is too large for swapchain
69     SWAPCHAIN_INDEX_NOT_IN_USE,         // vkQueuePresentKHR() given index that is not owned by app
70     SWAPCHAIN_BAD_BOOL,                 // VkBool32 that doesn't have value of VK_TRUE or VK_FALSE (e.g. is a non-zero form of true)
71     SWAPCHAIN_INVALID_COUNT,            // Second time a query called, the pCount value didn't match first time
72     SWAPCHAIN_WRONG_STYPE,              // The sType for a struct has the wrong value
73     SWAPCHAIN_WRONG_NEXT,               // The pNext for a struct is not NULL
74     SWAPCHAIN_ZERO_VALUE,               // A value should be non-zero
75     SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,   // pAllocator must be compatible (i.e. NULL or not) when object is created and destroyed
76     SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,     // A function using a queueFamilyIndex was called before
77                                                 // vkGetPhysicalDeviceQueueFamilyProperties() was called
78     SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by
79                                                 // vkGetPhysicalDeviceQueueFamilyProperties()
80     SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, // A surface is not supported by a given queueFamilyIndex, as seen by
81                                                 // vkGetPhysicalDeviceSurfaceSupportKHR()
82     SWAPCHAIN_NO_SYNC_FOR_ACQUIRE,      // vkAcquireNextImageKHR should be called with a valid semaphore and/or fence
83 } SWAPCHAIN_ERROR;
84 
85 // The following is for logging error messages:
86 #define LAYER_NAME (char *) "Swapchain"
87 #define LOG_ERROR_NON_VALID_OBJ(objType, type, obj)                                                                                \
88     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__,                 \
89                         SWAPCHAIN_INVALID_HANDLE, LAYER_NAME, "%s() called with a non-valid %s.", __FUNCTION__, (obj))             \
90               : VK_FALSE
91 #define LOG_ERROR_NULL_POINTER(objType, type, obj)                                                                                 \
92     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
93                         SWAPCHAIN_NULL_POINTER, LAYER_NAME, "%s() called with NULL pointer %s.", __FUNCTION__, (obj))              \
94               : VK_FALSE
95 #define LOG_ERROR_INVALID_COUNT(objType, type, obj, obj2, val, val2)                                                               \
96     (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
97                         SWAPCHAIN_INVALID_COUNT, LAYER_NAME, "%s() called with non-NULL %s, and with %s set to a "                 \
98                                                              "value (%d) that is greater than the value (%d) that "                \
99                                                              "was returned when %s was NULL.",                                     \
100                         __FUNCTION__, (obj2), (obj), (val), (val2), (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 typedef _SwpInstance SwpInstance;
150 typedef _SwpSurface SwpSurface;
151 ;
152 typedef _SwpPhysicalDevice SwpPhysicalDevice;
153 typedef _SwpDevice SwpDevice;
154 typedef _SwpSwapchain SwpSwapchain;
155 typedef _SwpImage SwpImage;
156 typedef _SwpQueue SwpQueue;
157 
158 // Create one of these for each VkInstance:
159 struct _SwpInstance {
160     // The actual handle for this VkInstance:
161     VkInstance instance;
162 
163     // Remember the VkSurfaceKHR's that are created for this VkInstance:
164     unordered_map<VkSurfaceKHR, SwpSurface *> surfaces;
165 
166     // When vkEnumeratePhysicalDevices is called, the VkPhysicalDevice's are
167     // remembered:
168     unordered_map<const void *, SwpPhysicalDevice *> physicalDevices;
169 
170     // Set to true if VK_KHR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
171     bool surfaceExtensionEnabled;
172 
173 // TODO: Add additional booleans for platform-specific extensions:
174 #ifdef VK_USE_PLATFORM_ANDROID_KHR
175     // Set to true if VK_KHR_ANDROID_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
176     bool androidSurfaceExtensionEnabled;
177 #endif // VK_USE_PLATFORM_ANDROID_KHR
178 #ifdef VK_USE_PLATFORM_MIR_KHR
179     // Set to true if VK_KHR_MIR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
180     bool mirSurfaceExtensionEnabled;
181 #endif // VK_USE_PLATFORM_MIR_KHR
182 #ifdef VK_USE_PLATFORM_WAYLAND_KHR
183     // Set to true if VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
184     bool waylandSurfaceExtensionEnabled;
185 #endif // VK_USE_PLATFORM_WAYLAND_KHR
186 #ifdef VK_USE_PLATFORM_WIN32_KHR
187     // Set to true if VK_KHR_WIN32_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
188     bool win32SurfaceExtensionEnabled;
189 #endif // VK_USE_PLATFORM_WIN32_KHR
190 #ifdef VK_USE_PLATFORM_XCB_KHR
191     // Set to true if VK_KHR_XCB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
192     bool xcbSurfaceExtensionEnabled;
193 #endif // VK_USE_PLATFORM_XCB_KHR
194 #ifdef VK_USE_PLATFORM_XLIB_KHR
195     // Set to true if VK_KHR_XLIB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
196     bool xlibSurfaceExtensionEnabled;
197 #endif // VK_USE_PLATFORM_XLIB_KHR
198 };
199 
200 // Create one of these for each VkSurfaceKHR:
201 struct _SwpSurface {
202     // The actual handle for this VkSurfaceKHR:
203     VkSurfaceKHR surface;
204 
205     // VkInstance that this VkSurfaceKHR is associated with:
206     SwpInstance *pInstance;
207 
208     // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
209     // remembered:
210     unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
211 
212     // 'true' if pAllocator was non-NULL when vkCreate*SurfaceKHR was called:
213     bool usedAllocatorToCreate;
214 
215     // Value of pQueueFamilyPropertyCount that was returned by the
216     // vkGetPhysicalDeviceQueueFamilyProperties() function:
217     uint32_t numQueueFamilyIndexSupport;
218     // Array of VkBool32's that is intialized by the
219     // vkGetPhysicalDeviceSurfaceSupportKHR() function.  First call for a given
220     // surface allocates and initializes this array to false for all
221     // queueFamilyIndex's (and sets numQueueFamilyIndexSupport to non-zero).
222     // All calls set the entry for a given queueFamilyIndex:
223     VkBool32 *pQueueFamilyIndexSupport;
224 };
225 
226 // Create one of these for each VkPhysicalDevice within a VkInstance:
227 struct _SwpPhysicalDevice {
228     // The actual handle for this VkPhysicalDevice:
229     VkPhysicalDevice physicalDevice;
230 
231     // Corresponding VkDevice (and info) to this VkPhysicalDevice:
232     SwpDevice *pDevice;
233 
234     // VkInstance that this VkPhysicalDevice is associated with:
235     SwpInstance *pInstance;
236 
237     // Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
238     // numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
239     bool gotQueueFamilyPropertyCount;
240     uint32_t numOfQueueFamilies;
241 
242     // Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
243     // called for:
244     unordered_map<VkSurfaceKHR, SwpSurface *> supportedSurfaces;
245 
246     // TODO: Record/use this info per-surface, not per-device, once a
247     // non-dispatchable surface object is added to WSI:
248     // Results of vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
249     bool gotSurfaceCapabilities;
250     VkSurfaceCapabilitiesKHR surfaceCapabilities;
251 
252     // TODO: Record/use this info per-surface, not per-device, once a
253     // non-dispatchable surface object is added to WSI:
254     // Count and VkSurfaceFormatKHR's returned by vkGetPhysicalDeviceSurfaceFormatsKHR():
255     uint32_t surfaceFormatCount;
256     VkSurfaceFormatKHR *pSurfaceFormats;
257 
258     // TODO: Record/use this info per-surface, not per-device, once a
259     // non-dispatchable surface object is added to WSI:
260     // Count and VkPresentModeKHR's returned by vkGetPhysicalDeviceSurfacePresentModesKHR():
261     uint32_t presentModeCount;
262     VkPresentModeKHR *pPresentModes;
263 };
264 
265 // Create one of these for each VkDevice within a VkInstance:
266 struct _SwpDevice {
267     // The actual handle for this VkDevice:
268     VkDevice device;
269 
270     // Corresponding VkPhysicalDevice (and info) to this VkDevice:
271     SwpPhysicalDevice *pPhysicalDevice;
272 
273     // Set to true if VK_KHR_SWAPCHAIN_EXTENSION_NAME was enabled:
274     bool swapchainExtensionEnabled;
275 
276     // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
277     // remembered:
278     unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
279 
280     // When vkGetDeviceQueue is called, the VkQueue's are remembered:
281     unordered_map<VkQueue, SwpQueue *> queues;
282 };
283 
284 // Create one of these for each VkImage within a VkSwapchainKHR:
285 struct _SwpImage {
286     // The actual handle for this VkImage:
287     VkImage image;
288 
289     // Corresponding VkSwapchainKHR (and info) to this VkImage:
290     SwpSwapchain *pSwapchain;
291 
292     // true if application got this image from vkAcquireNextImageKHR(), and
293     // hasn't yet called vkQueuePresentKHR() for it; otherwise false:
294     bool ownedByApp;
295 };
296 
297 // Create one of these for each VkSwapchainKHR within a VkDevice:
298 struct _SwpSwapchain {
299     // The actual handle for this VkSwapchainKHR:
300     VkSwapchainKHR swapchain;
301 
302     // Corresponding VkDevice (and info) to this VkSwapchainKHR:
303     SwpDevice *pDevice;
304 
305     // Corresponding VkSurfaceKHR to this VkSwapchainKHR:
306     SwpSurface *pSurface;
307 
308     // When vkGetSwapchainImagesKHR is called, the VkImage's are
309     // remembered:
310     uint32_t imageCount;
311     unordered_map<int, SwpImage> images;
312 
313     // 'true' if pAllocator was non-NULL when vkCreateSwapchainKHR was called:
314     bool usedAllocatorToCreate;
315 };
316 
317 // Create one of these for each VkQueue within a VkDevice:
318 struct _SwpQueue {
319     // The actual handle for this VkQueue:
320     VkQueue queue;
321 
322     // Corresponding VkDevice (and info) to this VkSwapchainKHR:
323     SwpDevice *pDevice;
324 
325     // Which queueFamilyIndex this VkQueue is associated with:
326     uint32_t queueFamilyIndex;
327 };
328 
329 struct layer_data {
330     debug_report_data *report_data;
331     std::vector<VkDebugReportCallbackEXT> logging_callback;
332     VkLayerDispatchTable *device_dispatch_table;
333     VkLayerInstanceDispatchTable *instance_dispatch_table;
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 
layer_datalayer_data343     layer_data() : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr){};
344 };
345 
346 #endif // SWAPCHAIN_H
347