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@lunarg.com>
19 * Author: Ian Elliott <ianelliott@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
31using namespace std;
32
33// Swapchain ERROR codes
34enum 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_LAYERS, // Called vkCreateSwapchainKHR() with a non-supported imageArrayLayers
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_APP_ACQUIRES_TOO_MANY_IMAGES, // vkAcquireNextImageKHR() asked for more images than are available
58    SWAPCHAIN_BAD_BOOL,                 // VkBool32 that doesn't have value of VK_TRUE or VK_FALSE (e.g. is a non-zero form of true)
59    SWAPCHAIN_PRIOR_COUNT,              // Query must be called first to get value of pCount, then called second time
60    SWAPCHAIN_INVALID_COUNT,            // Second time a query called, the pCount value didn't match first time
61    SWAPCHAIN_WRONG_STYPE,              // The sType for a struct has the wrong value
62    SWAPCHAIN_WRONG_NEXT,               // The pNext for a struct is not NULL
63    SWAPCHAIN_ZERO_VALUE,               // A value should be non-zero
64    SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,     // A function using a queueFamilyIndex was called before
65                                                // vkGetPhysicalDeviceQueueFamilyProperties() was called
66    SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by
67                                                // vkGetPhysicalDeviceQueueFamilyProperties()
68    SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, // A surface is not supported by a given queueFamilyIndex, as seen by
69                                                // vkGetPhysicalDeviceSurfaceSupportKHR()
70    SWAPCHAIN_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY,     // vkGetDisplayPlaneSupportedDisplaysKHR should be called after querying
71                                                        // device display plane properties
72    SWAPCHAIN_PLANE_INDEX_TOO_LARGE,    // a planeIndex value is larger than what vkGetDisplayPlaneSupportedDisplaysKHR returns
73};
74
75// The following is for logging error messages:
76const char * swapchain_layer_name = "Swapchain";
77
78#define LAYER_NAME (char *) "Swapchain"
79
80// NOTE: The following struct's/typedef's are for keeping track of
81// info that is used for validating the WSI extensions.
82
83// Forward declarations:
84struct SwpInstance;
85struct SwpSurface;
86struct SwpPhysicalDevice;
87struct SwpDevice;
88struct SwpSwapchain;
89struct SwpImage;
90struct SwpQueue;
91
92// Create one of these for each VkInstance:
93struct SwpInstance {
94    // The actual handle for this VkInstance:
95    VkInstance instance;
96
97    // Remember the VkSurfaceKHR's that are created for this VkInstance:
98    unordered_map<VkSurfaceKHR, SwpSurface *> surfaces;
99
100    // When vkEnumeratePhysicalDevices is called, the VkPhysicalDevice's are
101    // remembered:
102    unordered_map<const void *, SwpPhysicalDevice *> physicalDevices;
103
104    // Set to true if VK_KHR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
105    bool surfaceExtensionEnabled;
106
107    // Set to true if VK_KHR_DISPLAY_EXTENSION_NAME was enabled for this VkInstance:
108    bool displayExtensionEnabled;
109
110// TODO: Add additional booleans for platform-specific extensions:
111#ifdef VK_USE_PLATFORM_ANDROID_KHR
112    // Set to true if VK_KHR_ANDROID_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
113    bool androidSurfaceExtensionEnabled;
114#endif // VK_USE_PLATFORM_ANDROID_KHR
115#ifdef VK_USE_PLATFORM_MIR_KHR
116    // Set to true if VK_KHR_MIR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
117    bool mirSurfaceExtensionEnabled;
118#endif // VK_USE_PLATFORM_MIR_KHR
119#ifdef VK_USE_PLATFORM_WAYLAND_KHR
120    // Set to true if VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
121    bool waylandSurfaceExtensionEnabled;
122#endif // VK_USE_PLATFORM_WAYLAND_KHR
123#ifdef VK_USE_PLATFORM_WIN32_KHR
124    // Set to true if VK_KHR_WIN32_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
125    bool win32SurfaceExtensionEnabled;
126#endif // VK_USE_PLATFORM_WIN32_KHR
127#ifdef VK_USE_PLATFORM_XCB_KHR
128    // Set to true if VK_KHR_XCB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
129    bool xcbSurfaceExtensionEnabled;
130#endif // VK_USE_PLATFORM_XCB_KHR
131#ifdef VK_USE_PLATFORM_XLIB_KHR
132    // Set to true if VK_KHR_XLIB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
133    bool xlibSurfaceExtensionEnabled;
134#endif // VK_USE_PLATFORM_XLIB_KHR
135};
136
137// Create one of these for each VkSurfaceKHR:
138struct SwpSurface {
139    // The actual handle for this VkSurfaceKHR:
140    VkSurfaceKHR surface;
141
142    // VkInstance that this VkSurfaceKHR is associated with:
143    SwpInstance *pInstance;
144
145    // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
146    // remembered:
147    unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
148
149    // Value of pQueueFamilyPropertyCount that was returned by the
150    // vkGetPhysicalDeviceQueueFamilyProperties() function:
151    uint32_t numQueueFamilyIndexSupport;
152    // Array of VkBool32's that is intialized by the
153    // vkGetPhysicalDeviceSurfaceSupportKHR() function.  First call for a given
154    // surface allocates and initializes this array to false for all
155    // queueFamilyIndex's (and sets numQueueFamilyIndexSupport to non-zero).
156    // All calls set the entry for a given queueFamilyIndex:
157    VkBool32 *pQueueFamilyIndexSupport;
158};
159
160// Create one of these for each VkPhysicalDevice within a VkInstance:
161struct SwpPhysicalDevice {
162    // The actual handle for this VkPhysicalDevice:
163    VkPhysicalDevice physicalDevice;
164
165    // Corresponding VkDevice (and info) to this VkPhysicalDevice:
166    SwpDevice *pDevice;
167
168    // VkInstance that this VkPhysicalDevice is associated with:
169    SwpInstance *pInstance;
170
171    // Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
172    // numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
173    bool gotQueueFamilyPropertyCount;
174    uint32_t numOfQueueFamilies;
175
176    // Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
177    // called for:
178    unordered_map<VkSurfaceKHR, SwpSurface *> supportedSurfaces;
179
180    // TODO: Record/use this info per-surface, not per-device, once a
181    // non-dispatchable surface object is added to WSI:
182    // Results of vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
183    bool gotSurfaceCapabilities;
184    VkSurfaceCapabilitiesKHR surfaceCapabilities;
185
186    // TODO: Record/use this info per-surface, not per-device, once a
187    // non-dispatchable surface object is added to WSI:
188    // Count and VkSurfaceFormatKHR's returned by vkGetPhysicalDeviceSurfaceFormatsKHR():
189    uint32_t surfaceFormatCount;
190    VkSurfaceFormatKHR *pSurfaceFormats;
191
192    // TODO: Record/use this info per-surface, not per-device, once a
193    // non-dispatchable surface object is added to WSI:
194    // Count and VkPresentModeKHR's returned by vkGetPhysicalDeviceSurfacePresentModesKHR():
195    uint32_t presentModeCount;
196    VkPresentModeKHR *pPresentModes;
197
198    // Count returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR():
199    uint32_t displayPlanePropertyCount;
200    bool gotDisplayPlanePropertyCount;
201};
202
203// Create one of these for each VkDevice within a VkInstance:
204struct SwpDevice {
205    // The actual handle for this VkDevice:
206    VkDevice device;
207
208    // Corresponding VkPhysicalDevice (and info) to this VkDevice:
209    SwpPhysicalDevice *pPhysicalDevice;
210
211    // Set to true if VK_KHR_SWAPCHAIN_EXTENSION_NAME was enabled:
212    bool swapchainExtensionEnabled;
213
214    // Set to true if VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME was enabled:
215    bool displaySwapchainExtensionEnabled;
216
217    // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
218    // remembered:
219    unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;
220
221    // When vkGetDeviceQueue is called, the VkQueue's are remembered:
222    unordered_map<VkQueue, SwpQueue *> queues;
223};
224
225// Create one of these for each VkImage within a VkSwapchainKHR:
226struct SwpImage {
227    // The actual handle for this VkImage:
228    VkImage image;
229
230    // Corresponding VkSwapchainKHR (and info) to this VkImage:
231    SwpSwapchain *pSwapchain;
232
233    // true if application acquired this image from vkAcquireNextImageKHR(),
234    // and hasn't yet called vkQueuePresentKHR() for it; otherwise false:
235    bool acquiredByApp;
236};
237
238// Create one of these for each VkSwapchainKHR within a VkDevice:
239struct SwpSwapchain {
240    // The actual handle for this VkSwapchainKHR:
241    VkSwapchainKHR swapchain;
242
243    // Corresponding VkDevice (and info) to this VkSwapchainKHR:
244    SwpDevice *pDevice;
245
246    // Corresponding VkSurfaceKHR to this VkSwapchainKHR:
247    SwpSurface *pSurface;
248
249    // When vkGetSwapchainImagesKHR is called, the VkImage's are
250    // remembered:
251    uint32_t imageCount;
252    unordered_map<int, SwpImage> images;
253};
254
255// Create one of these for each VkQueue within a VkDevice:
256struct SwpQueue {
257    // The actual handle for this VkQueue:
258    VkQueue queue;
259
260    // Corresponding VkDevice (and info) to this VkSwapchainKHR:
261    SwpDevice *pDevice;
262
263    // Which queueFamilyIndex this VkQueue is associated with:
264    uint32_t queueFamilyIndex;
265};
266
267struct layer_data {
268    VkInstance instance;
269
270    debug_report_data *report_data;
271    std::vector<VkDebugReportCallbackEXT> logging_callback;
272    VkLayerDispatchTable *device_dispatch_table;
273    VkLayerInstanceDispatchTable *instance_dispatch_table;
274
275    // The following are for keeping track of the temporary callbacks that can
276    // be used in vkCreateInstance and vkDestroyInstance:
277    uint32_t num_tmp_callbacks;
278    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
279    VkDebugReportCallbackEXT *tmp_callbacks;
280
281    // NOTE: The following are for keeping track of info that is used for
282    // validating the WSI extensions.
283    std::unordered_map<void *, SwpInstance> instanceMap;
284    std::unordered_map<VkSurfaceKHR, SwpSurface> surfaceMap;
285    std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
286    std::unordered_map<void *, SwpDevice> deviceMap;
287    std::unordered_map<VkSwapchainKHR, SwpSwapchain> swapchainMap;
288    std::unordered_map<void *, SwpQueue> queueMap;
289
290    layer_data()
291        : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), num_tmp_callbacks(0),
292          tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr){};
293};
294
295#endif // SWAPCHAIN_H
296