blob: 38d8e948a3da6329dadf5038408aa5fb4ab2cc54 [file] [log] [blame]
Ian Elliott329da012015-09-22 10:51:24 -06001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS 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. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Ian Elliott <ian@lunarg.com>
26 */
27
Ian Elliotte75a4b52015-10-07 11:32:31 -060028#include <stdio.h>
29#include <string.h>
30#include <unordered_map>
31#include "vk_loader_platform.h"
32#include "vk_layer.h"
33#include "vk_layer_config.h"
34#include "vk_layer_logging.h"
35#include "vk_layer_extension_utils.h"
36
Ian Elliott329da012015-09-22 10:51:24 -060037#include "swapchain.h"
38
Ian Elliott960df282015-10-07 16:18:35 -060039
Ian Elliott329da012015-09-22 10:51:24 -060040// FIXME/TODO: Make sure this layer is thread-safe!
41
Ian Elliott960df282015-10-07 16:18:35 -060042
Ian Elliott329da012015-09-22 10:51:24 -060043// The following is for logging error messages:
Ian Elliott960df282015-10-07 16:18:35 -060044static std::unordered_map<void *, layer_data *> layer_data_map;
Ian Elliott329da012015-09-22 10:51:24 -060045
Ian Elliott960df282015-10-07 16:18:35 -060046template layer_data *get_my_data_ptr<layer_data>(
47 void *data_key,
48 std::unordered_map<void *, layer_data *> &data_map);
Ian Elliott329da012015-09-22 10:51:24 -060049
Ian Elliott329da012015-09-22 10:51:24 -060050
51// NOTE: The following are for keeping track of info that is used for
52// validating the WSI extensions.
53static std::unordered_map<void *, SwpInstance> instanceMap;
54static std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
55static std::unordered_map<void *, SwpDevice> deviceMap;
56static std::unordered_map<uint64_t, SwpSwapchain> swapchainMap;
57
58
59static void createDeviceRegisterExtensions(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice device)
60{
61 uint32_t i;
62 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
63 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
64 pDisp->GetSurfacePropertiesKHR = (PFN_vkGetSurfacePropertiesKHR) gpa(device, "vkGetSurfacePropertiesKHR");
65 pDisp->GetSurfaceFormatsKHR = (PFN_vkGetSurfaceFormatsKHR) gpa(device, "vkGetSurfaceFormatsKHR");
66 pDisp->GetSurfacePresentModesKHR = (PFN_vkGetSurfacePresentModesKHR) gpa(device, "vkGetSurfacePresentModesKHR");
67 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) gpa(device, "vkCreateSwapchainKHR");
68 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) gpa(device, "vkDestroySwapchainKHR");
69 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) gpa(device, "vkGetSwapchainImagesKHR");
70 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) gpa(device, "vkAcquireNextImageKHR");
71 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR) gpa(device, "vkQueuePresentKHR");
72
73 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
74 if (pPhysicalDevice) {
75 deviceMap[device].pPhysicalDevice = pPhysicalDevice;
76 pPhysicalDevice->pDevice = &deviceMap[device];
77 } else {
Ian Elliott960df282015-10-07 16:18:35 -060078 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -060079 LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
80 physicalDevice,
81 "VkPhysicalDevice");
82 }
83 deviceMap[device].device = device;
84 deviceMap[device].deviceSwapchainExtensionEnabled = false;
85 deviceMap[device].gotSurfaceProperties = false;
86 deviceMap[device].surfaceFormatCount = 0;
87 deviceMap[device].pSurfaceFormats = NULL;
88 deviceMap[device].presentModeCount = 0;
89 deviceMap[device].pPresentModes = NULL;
90
91 // Record whether the WSI device extension was enabled for this VkDevice.
92 // No need to check if the extension was advertised by
93 // vkEnumerateDeviceExtensionProperties(), since the loader handles that.
94 for (i = 0; i < pCreateInfo->extensionCount; i++) {
95 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME) == 0) {
96
97 deviceMap[device].deviceSwapchainExtensionEnabled = true;
98 }
99 }
100}
101
102static void createInstanceRegisterExtensions(const VkInstanceCreateInfo* pCreateInfo, VkInstance instance)
103{
104 uint32_t i;
105 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
106 PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
107 pDisp->GetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
108
109 // Remember this instance, and whether the VK_EXT_KHR_swapchain extension
110 // was enabled for it:
111 instanceMap[instance].instance = instance;
112 instanceMap[instance].swapchainExtensionEnabled = false;
113
114 // Record whether the WSI instance extension was enabled for this
115 // VkInstance. No need to check if the extension was advertised by
116 // vkEnumerateInstanceExtensionProperties(), since the loader handles that.
117 for (i = 0; i < pCreateInfo->extensionCount; i++) {
118 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
119
120 instanceMap[instance].swapchainExtensionEnabled = true;
121 }
122 }
123}
124
125
126#include "vk_dispatch_table_helper.h"
Ian Elliott960df282015-10-07 16:18:35 -0600127static void initSwapchain(layer_data *my_data)
Ian Elliott329da012015-09-22 10:51:24 -0600128{
129 uint32_t report_flags = 0;
130 uint32_t debug_action = 0;
131 FILE *log_output = NULL;
132 const char *option_str;
Courtney Goeltzenleuchter7aa50602015-10-08 17:07:25 -0600133 VkDbgMsgCallback callback;
Ian Elliott329da012015-09-22 10:51:24 -0600134
135 // Initialize Swapchain options:
136 report_flags = getLayerOptionFlags("SwapchainReportFlags", 0);
137 getLayerOptionEnum("SwapchainDebugAction", (uint32_t *) &debug_action);
138
139 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
140 {
141 // Turn on logging, since it was requested:
142 option_str = getLayerOption("SwapchainLogFilename");
143 log_output = getLayerLogOutput(option_str, "Swapchain");
Ian Elliott960df282015-10-07 16:18:35 -0600144 layer_create_msg_callback(my_data->report_data, report_flags,
Ian Elliott329da012015-09-22 10:51:24 -0600145 log_callback, (void *) log_output,
Courtney Goeltzenleuchter7aa50602015-10-08 17:07:25 -0600146 &callback);
147 my_data->logging_callback.push_back(callback);
148 }
149 if (debug_action & VK_DBG_LAYER_ACTION_DEBUG_OUTPUT) {
150 layer_create_msg_callback(my_data->report_data, report_flags, win32_debug_output_msg, NULL, &callback);
151 my_data->logging_callback.push_back(callback);
Ian Elliott329da012015-09-22 10:51:24 -0600152 }
153}
154
155static const char *surfaceTransformStr(VkSurfaceTransformKHR value)
156{
157 static std::string surfaceTransformStrings[] = {
158 "VK_SURFACE_TRANSFORM_NONE_KHR",
159 "VK_SURFACE_TRANSFORM_ROT90_KHR",
160 "VK_SURFACE_TRANSFORM_ROT180_KHR",
161 "VK_SURFACE_TRANSFORM_ROT270_KHR",
162 "VK_SURFACE_TRANSFORM_HMIRROR_KHR",
163 "VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR",
164 "VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR",
165 "VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR",
166 "Out-of-Range Value"};
167
168 // Deal with a out-of-range value:
169 switch (value) {
170 case VK_SURFACE_TRANSFORM_NONE_KHR:
171 case VK_SURFACE_TRANSFORM_ROT90_KHR:
172 case VK_SURFACE_TRANSFORM_ROT180_KHR:
173 case VK_SURFACE_TRANSFORM_ROT270_KHR:
174 case VK_SURFACE_TRANSFORM_HMIRROR_KHR:
175 case VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR:
176 case VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR:
177 case VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR:
178 break;
179 default:
180 value =
181 (VkSurfaceTransformKHR) (VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR + 1);
182 break;
183 }
184
185 // Return a string corresponding to the value:
186 return surfaceTransformStrings[value].c_str();
187}
188
189static const char *presentModeStr(VkPresentModeKHR value)
190{
191 static std::string presentModeStrings[] = {
192 "VK_PRESENT_MODE_IMMEDIATE_KHR",
193 "VK_PRESENT_MODE_MAILBOX_KHR",
194 "VK_PRESENT_MODE_FIFO_KHR",
195 "Out-of-Range Value"};
196
197 // Deal with a out-of-range value:
198 switch (value) {
199 case VK_PRESENT_MODE_IMMEDIATE_KHR:
200 case VK_PRESENT_MODE_MAILBOX_KHR:
201 case VK_PRESENT_MODE_FIFO_KHR:
202 break;
203 default:
204 value = (VkPresentModeKHR) (VK_PRESENT_MODE_FIFO_KHR + 1);
205 break;
206 }
207
208 // Return a string corresponding to the value:
209 return presentModeStrings[value].c_str();
210}
211
212
213VK_LAYER_EXPORT VkResult VKAPI vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance)
214{
215 // Call down the call chain:
216 VkResult result = instance_dispatch_table(*pInstance)->CreateInstance(pCreateInfo, pInstance);
217 if (result == VK_SUCCESS) {
218 // Since it succeeded, do layer-specific work:
Ian Elliott960df282015-10-07 16:18:35 -0600219 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
220 my_data->report_data = debug_report_create_instance(
221 instance_dispatch_table(*pInstance),
222 *pInstance,
223 pCreateInfo->extensionCount,
224 pCreateInfo->ppEnabledExtensionNames);
225 // Call the following function after my_data is initialized:
Ian Elliott329da012015-09-22 10:51:24 -0600226 createInstanceRegisterExtensions(pCreateInfo, *pInstance);
Ian Elliott960df282015-10-07 16:18:35 -0600227 initSwapchain(my_data);
Ian Elliott329da012015-09-22 10:51:24 -0600228 }
229 return result;
230}
231
232VK_LAYER_EXPORT void VKAPI vkDestroyInstance(VkInstance instance)
233{
234 VkBool32 skipCall = VK_FALSE;
235
236 // Validate that a valid VkInstance was used:
237 SwpInstance *pInstance = &instanceMap[instance];
238 if (!pInstance) {
Ian Elliott960df282015-10-07 16:18:35 -0600239 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600240 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
241 instance,
242 "VkInstance");
243 }
244
245 if (VK_FALSE == skipCall) {
246 // Call down the call chain:
247 dispatch_key key = get_dispatch_key(instance);
248 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
249 pDisp->DestroyInstance(instance);
Ian Elliott960df282015-10-07 16:18:35 -0600250
251 // Clean up logging callback, if any
252 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
Courtney Goeltzenleuchter7aa50602015-10-08 17:07:25 -0600253 while (my_data->logging_callback.size() > 0) {
254 VkDbgMsgCallback callback = my_data->logging_callback.back();
255 layer_destroy_msg_callback(my_data->report_data, callback);
256 my_data->logging_callback.pop_back();
Ian Elliott960df282015-10-07 16:18:35 -0600257 }
258 layer_debug_report_destroy_instance(my_data->report_data);
259 layer_data_map.erase(key);
260
Ian Elliott329da012015-09-22 10:51:24 -0600261 destroy_instance_dispatch_table(key);
262 }
263
264 // Regardless of skipCall value, do some internal cleanup:
265 if (pInstance) {
266 // Delete all of the SwpPhysicalDevice's and the SwpInstance associated
267 // with this instance:
268 for (auto it = pInstance->physicalDevices.begin() ;
269 it != pInstance->physicalDevices.end() ; it++) {
270 // Erase the SwpPhysicalDevice's from the physicalDeviceMap (which
271 // are simply pointed to by the SwpInstance):
272 physicalDeviceMap.erase(it->second->physicalDevice);
273 }
274 instanceMap.erase(instance);
275 }
276}
277
278VK_LAYER_EXPORT VkResult VKAPI vkEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices)
279{
280 VkResult result = VK_SUCCESS;
281 VkBool32 skipCall = VK_FALSE;
282
283 // Validate that a valid VkInstance was used:
284 SwpInstance *pInstance = &instanceMap[instance];
285 if (!pInstance) {
Ian Elliott960df282015-10-07 16:18:35 -0600286 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600287 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
288 instance,
289 "VkInstance");
290 }
291
292 if (VK_FALSE == skipCall) {
293 // Call down the call chain:
294 result = instance_dispatch_table(instance)->EnumeratePhysicalDevices(
295 instance, pPhysicalDeviceCount, pPhysicalDevices);
296
297 if ((result == VK_SUCCESS) && pInstance && pPhysicalDevices &&
298 (*pPhysicalDeviceCount > 0)) {
299 // Record the VkPhysicalDevices returned by the ICD:
300 SwpInstance *pInstance = &instanceMap[instance];
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600301 for (uint32_t i = 0; i < *pPhysicalDeviceCount; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600302 physicalDeviceMap[pPhysicalDevices[i]].physicalDevice =
303 pPhysicalDevices[i];
304 physicalDeviceMap[pPhysicalDevices[i]].pInstance = pInstance;
305 physicalDeviceMap[pPhysicalDevices[i]].pDevice = NULL;
306 // Point to the associated SwpInstance:
307 pInstance->physicalDevices[pPhysicalDevices[i]] =
308 &physicalDeviceMap[pPhysicalDevices[i]];
309 }
310 }
311
312 return result;
313 }
314 return VK_ERROR_VALIDATION_FAILED;
315}
316
317VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
318{
319 VkResult result = VK_SUCCESS;
320 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600321 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600322
323 // Validate that a valid VkPhysicalDevice was used:
324 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
325 if (!pPhysicalDevice) {
326 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
327 physicalDevice,
328 "VkPhysicalDevice");
329 }
330
331 if (VK_FALSE == skipCall) {
332 // Call down the call chain:
333 result = device_dispatch_table(*pDevice)->CreateDevice(
334 physicalDevice, pCreateInfo, pDevice);
335 if (result == VK_SUCCESS) {
336 // Since it succeeded, do layer-specific work:
Ian Elliott960df282015-10-07 16:18:35 -0600337 my_data->report_data = layer_debug_report_create_device(my_data->report_data, *pDevice);
Ian Elliott329da012015-09-22 10:51:24 -0600338 createDeviceRegisterExtensions(physicalDevice, pCreateInfo,
339 *pDevice);
340 }
341 return result;
342 }
343 return VK_ERROR_VALIDATION_FAILED;
344}
345
346VK_LAYER_EXPORT void VKAPI vkDestroyDevice(VkDevice device)
347{
348 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600349 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600350
351 // Validate that a valid VkDevice was used:
352 SwpDevice *pDevice = &deviceMap[device];
353 if (!pDevice) {
354 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
355 device,
356 "VkDevice");
357 }
358
359 if (VK_FALSE == skipCall) {
360 // Call down the call chain:
361 dispatch_key key = get_dispatch_key(device);
362 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
363 pDisp->DestroyDevice(device);
364 destroy_device_dispatch_table(key);
365 }
366
367 // Regardless of skipCall value, do some internal cleanup:
368 if (pDevice) {
369 // Delete the SwpDevice associated with this device:
370 if (pDevice->pPhysicalDevice) {
371 pDevice->pPhysicalDevice->pDevice = NULL;
372 }
373 if (deviceMap[device].pSurfaceFormats) {
374 free(deviceMap[device].pSurfaceFormats);
375 }
376 if (deviceMap[device].pPresentModes) {
377 free(deviceMap[device].pPresentModes);
378 }
Ian Elliott329da012015-09-22 10:51:24 -0600379 if (!pDevice->swapchains.empty()) {
380 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600381 SWAPCHAIN_DEL_DEVICE_BEFORE_SWAPCHAINS,
Ian Elliott329da012015-09-22 10:51:24 -0600382 "%s() called before all of its associated "
383 "VkSwapchainKHRs were destroyed.",
384 __FUNCTION__);
385 // Empty and then delete all SwpSwapchain's
386 for (auto it = pDevice->swapchains.begin() ;
387 it != pDevice->swapchains.end() ; it++) {
388 // Delete all SwpImage's
389 it->second->images.clear();
390 }
391 pDevice->swapchains.clear();
392 }
Cody Northrop73bb6572015-09-28 15:09:32 -0600393 deviceMap.erase(device);
Ian Elliott329da012015-09-22 10:51:24 -0600394 }
395}
396
397VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported)
398{
399 VkResult result = VK_SUCCESS;
400 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600401 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600402
403 // Validate that a valid VkPhysicalDevice was used, and that the instance
404 // extension was enabled:
405 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
406 if (!pPhysicalDevice || !pPhysicalDevice->pInstance) {
407 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
408 physicalDevice,
409 "VkPhysicalDevice");
410 } else if (!pPhysicalDevice->pInstance->swapchainExtensionEnabled) {
411 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_INSTANCE,
412 pPhysicalDevice->pInstance,
413 "VkInstance",
Ian Elliottf81c2562015-09-25 15:50:55 -0600414 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600415 "%s() called even though the "
416 VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME,
417 "extension was not enabled for this VkInstance.",
418 __FUNCTION__);
419 }
420
421 if (VK_FALSE == skipCall) {
422 // Call down the call chain:
423 result = instance_dispatch_table(physicalDevice)->GetPhysicalDeviceSurfaceSupportKHR(
424 physicalDevice, queueFamilyIndex, pSurfaceDescription,
425 pSupported);
426
427 if ((result == VK_SUCCESS) && pSupported && pPhysicalDevice) {
428 // Record the result of this query:
429 pPhysicalDevice->queueFamilyIndexSupport[queueFamilyIndex] =
430 *pSupported;
431 // TODO: We need to compare this with the actual queue used for
432 // presentation, to ensure it was advertised to the application as
433 // supported for presentation.
434 }
435
436 return result;
437 }
438 return VK_ERROR_VALIDATION_FAILED;
439}
440
441VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePropertiesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties)
442{
443 VkResult result = VK_SUCCESS;
444 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600445 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600446
447 // Validate that a valid VkDevice was used, and that the device
448 // extension was enabled:
449 SwpDevice *pDevice = &deviceMap[device];
450 if (!pDevice) {
451 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
452 device,
453 "VkDevice");
454 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
455 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600456 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600457 "%s() called even though the "
458 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
459 "extension was not enabled for this VkDevice.",
460 __FUNCTION__);
461 }
462
463 if (VK_FALSE == skipCall) {
464 // Call down the call chain:
465 result = device_dispatch_table(device)->GetSurfacePropertiesKHR(
466 device, pSurfaceDescription, pSurfaceProperties);
467
468 if ((result == VK_SUCCESS) && pDevice) {
469 pDevice->gotSurfaceProperties = true;
470 pDevice->surfaceProperties = *pSurfaceProperties;
471 }
472
473 return result;
474 }
475 return VK_ERROR_VALIDATION_FAILED;
476}
477
478VK_LAYER_EXPORT VkResult VKAPI vkGetSurfaceFormatsKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats)
479{
480 VkResult result = VK_SUCCESS;
481 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600482 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600483
484 // Validate that a valid VkDevice was used, and that the device
485 // extension was enabled:
486 SwpDevice *pDevice = &deviceMap[device];
487 if (!pDevice) {
488 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
489 device,
490 "VkDevice");
491 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
492 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600493 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600494 "%s() called even though the "
495 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
496 "extension was not enabled for this VkDevice.",
497 __FUNCTION__);
498 }
499
500 if (VK_FALSE == skipCall) {
501 // Call down the call chain:
502 result = device_dispatch_table(device)->GetSurfaceFormatsKHR(
503 device, pSurfaceDescription, pCount, pSurfaceFormats);
504
505 if ((result == VK_SUCCESS) && pDevice && pSurfaceFormats && pCount &&
506 (*pCount > 0)) {
507 pDevice->surfaceFormatCount = *pCount;
508 pDevice->pSurfaceFormats = (VkSurfaceFormatKHR *)
509 malloc(*pCount * sizeof(VkSurfaceFormatKHR));
510 if (pDevice->pSurfaceFormats) {
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600511 for (uint32_t i = 0 ; i < *pCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600512 pDevice->pSurfaceFormats[i] = pSurfaceFormats[i];
513 }
514 } else {
515 pDevice->surfaceFormatCount = 0;
516 }
517 }
518
519 return result;
520 }
521 return VK_ERROR_VALIDATION_FAILED;
522}
523
524VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePresentModesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes)
525{
526 VkResult result = VK_SUCCESS;
527 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600528 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600529
530 // Validate that a valid VkDevice was used, and that the device
531 // extension was enabled:
532 SwpDevice *pDevice = &deviceMap[device];
533 if (!pDevice) {
534 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
535 device,
536 "VkDevice");
537 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
538 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600539 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600540 "%s() called even though the "
541 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
542 "extension was not enabled for this VkDevice.",
543 __FUNCTION__);
544 }
545
546 if (VK_FALSE == skipCall) {
547 // Call down the call chain:
548 result = device_dispatch_table(device)->GetSurfacePresentModesKHR(
549 device, pSurfaceDescription, pCount, pPresentModes);
550
551 if ((result == VK_SUCCESS) && pDevice && pPresentModes && pCount &&
552 (*pCount > 0)) {
553 pDevice->presentModeCount = *pCount;
554 pDevice->pPresentModes = (VkPresentModeKHR *)
555 malloc(*pCount * sizeof(VkPresentModeKHR));
556 if (pDevice->pSurfaceFormats) {
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600557 for (uint32_t i = 0 ; i < *pCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600558 pDevice->pPresentModes[i] = pPresentModes[i];
559 }
560 } else {
561 pDevice->presentModeCount = 0;
562 }
563 }
564
565 return result;
566 }
567 return VK_ERROR_VALIDATION_FAILED;
568}
569
570// This function does the up-front validation work for vkCreateSwapchainKHR(),
571// and returns VK_TRUE if a logging callback indicates that the call down the
572// chain should be skipped:
573static VkBool32 validateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
574{
575// TODO: Validate cases of re-creating a swapchain (the current code
576// assumes a new swapchain is being created).
577 VkResult result = VK_SUCCESS;
578 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600579 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600580 char fn[] = "vkCreateSwapchainKHR";
581
582 // Validate that a valid VkDevice was used, and that the device
583 // extension was enabled:
584 SwpDevice *pDevice = &deviceMap[device];
585 if (!pDevice) {
586 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600587 SWAPCHAIN_INVALID_HANDLE,
Ian Elliott329da012015-09-22 10:51:24 -0600588 "%s() called with a non-valid %s.",
589 fn, "VkDevice");
590
591 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
592 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600593 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600594 "%s() called even though the "
595 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
596 "extension was not enabled for this VkDevice.",
597 fn);
598 }
599
600 // Validate pCreateInfo with the results for previous queries:
601 if (!pDevice->gotSurfaceProperties) {
602 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600603 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600604 "%s() called before calling "
605 "vkGetSurfacePropertiesKHR().",
606 fn);
607 } else {
608 // Validate pCreateInfo->minImageCount against
609 // VkSurfacePropertiesKHR::{min|max}ImageCount:
610 VkSurfacePropertiesKHR *pProps = &pDevice->surfaceProperties;
611 if ((pCreateInfo->minImageCount < pProps->minImageCount) ||
612 ((pProps->maxImageCount > 0) &&
613 (pCreateInfo->minImageCount > pProps->maxImageCount))) {
614 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600615 SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,
Ian Elliott329da012015-09-22 10:51:24 -0600616 "%s() called with pCreateInfo->minImageCount "
617 "= %d, which is outside the bounds returned "
618 "by vkGetSurfacePropertiesKHR() (i.e. "
619 "minImageCount = %d, maxImageCount = %d).",
620 fn,
621 pCreateInfo->minImageCount,
622 pProps->minImageCount,
623 pProps->maxImageCount);
624 }
625 // Validate pCreateInfo->imageExtent against
626 // VkSurfacePropertiesKHR::{current|min|max}ImageExtent:
627 if ((pProps->currentExtent.width == -1) &&
628 ((pCreateInfo->imageExtent.width < pProps->minImageExtent.width) ||
629 (pCreateInfo->imageExtent.width > pProps->maxImageExtent.width) ||
630 (pCreateInfo->imageExtent.height < pProps->minImageExtent.height) ||
631 (pCreateInfo->imageExtent.height > pProps->maxImageExtent.height))) {
632 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600633 SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS,
Ian Elliott329da012015-09-22 10:51:24 -0600634 "%s() called with pCreateInfo->imageExtent = "
635 "(%d,%d), which is outside the bounds "
636 "returned by vkGetSurfacePropertiesKHR(): "
637 "currentExtent = (%d,%d), minImageExtent = "
638 "(%d,%d), maxImageExtent = (%d,%d).",
639 fn,
640 pCreateInfo->imageExtent.width,
641 pCreateInfo->imageExtent.height,
642 pProps->currentExtent.width,
643 pProps->currentExtent.height,
644 pProps->minImageExtent.width,
645 pProps->minImageExtent.height,
646 pProps->maxImageExtent.width,
647 pProps->maxImageExtent.height);
648 }
649 if ((pProps->currentExtent.width != -1) &&
650 ((pCreateInfo->imageExtent.width != pProps->currentExtent.width) ||
651 (pCreateInfo->imageExtent.height != pProps->currentExtent.height))) {
652 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600653 SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN,
Ian Elliott329da012015-09-22 10:51:24 -0600654 "%s() called with pCreateInfo->imageExtent = "
655 "(%d,%d), which is not equal to the "
656 "currentExtent = (%d,%d) returned by "
657 "vkGetSurfacePropertiesKHR().",
658 fn,
659 pCreateInfo->imageExtent.width,
660 pCreateInfo->imageExtent.height,
661 pProps->currentExtent.width,
662 pProps->currentExtent.height);
663 }
664 // Validate pCreateInfo->preTransform against
665 // VkSurfacePropertiesKHR::supportedTransforms:
666 if (!((1 << pCreateInfo->preTransform) & pProps->supportedTransforms)) {
667 // This is an error situation; one for which we'd like to give
668 // the developer a helpful, multi-line error message. Build it
669 // up a little at a time, and then log it:
670 std::string errorString = "";
671 char str[1024];
672 // Here's the first part of the message:
673 sprintf(str, "%s() called with a non-supported "
674 "pCreateInfo->preTransform (i.e. %s). "
675 "Supported values are:\n",
676 fn,
677 surfaceTransformStr(pCreateInfo->preTransform));
678 errorString += str;
679 for (int i = VK_SURFACE_TRANSFORM_NONE_KHR ;
680 i < VK_SURFACE_TRANSFORM_INHERIT_KHR ; i++) {
681 // Build up the rest of the message:
682 if ((1 << i) & pProps->supportedTransforms) {
683 const char *newStr =
684 surfaceTransformStr((VkSurfaceTransformKHR) (1 << i));
685 sprintf(str, " %s\n", newStr);
686 errorString += str;
687 }
688 }
689 // Log the message that we've built up:
Ian Elliott960df282015-10-07 16:18:35 -0600690 skipCall |= debug_report_log_msg(my_data->report_data,
Ian Elliott329da012015-09-22 10:51:24 -0600691 VK_DBG_REPORT_ERROR_BIT,
692 VK_OBJECT_TYPE_DEVICE,
Ian Elliottf81c2562015-09-25 15:50:55 -0600693 (uint64_t) device, 0,
694 SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,
695 LAYER_NAME,
Ian Elliott329da012015-09-22 10:51:24 -0600696 errorString.c_str());
697 }
698 // Validate pCreateInfo->imageArraySize against
699 // VkSurfacePropertiesKHR::maxImageArraySize:
700 if (pCreateInfo->imageArraySize <= pProps->maxImageArraySize) {
701 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600702 SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,
Ian Elliott329da012015-09-22 10:51:24 -0600703 "%s() called with a non-supported "
704 "pCreateInfo->imageArraySize (i.e. %d). "
705 "Maximum value is %d.",
706 fn,
707 pCreateInfo->imageArraySize,
708 pProps->maxImageArraySize);
709 }
710 // Validate pCreateInfo->imageUsageFlags against
711 // VkSurfacePropertiesKHR::supportedUsageFlags:
712 if (pCreateInfo->imageUsageFlags &&
713 (pCreateInfo->imageUsageFlags !=
714 (pCreateInfo->imageUsageFlags & pProps->supportedUsageFlags))) {
715 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600716 SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,
Ian Elliott329da012015-09-22 10:51:24 -0600717 "%s() called with a non-supported "
718 "pCreateInfo->imageUsageFlags (i.e. 0x%08x)."
719 " Supported flag bits are 0x%08x.",
720 fn,
721 pCreateInfo->imageUsageFlags,
722 pProps->supportedUsageFlags);
723 }
724 }
725 if (!pDevice->surfaceFormatCount) {
726 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600727 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600728 "%s() called before calling "
729 "vkGetSurfaceFormatsKHR().",
730 fn);
731 } else {
732 // Validate pCreateInfo->imageFormat against
733 // VkSurfaceFormatKHR::format:
734 bool foundFormat = false;
735 bool foundColorSpace = false;
736 bool foundMatch = false;
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600737 for (uint32_t i = 0 ; i < pDevice->surfaceFormatCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600738 if (pCreateInfo->imageFormat == pDevice->pSurfaceFormats[i].format) {
739 // Validate pCreateInfo->imageColorSpace against
740 // VkSurfaceFormatKHR::colorSpace:
741 foundFormat = true;
742 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
743 foundMatch = true;
744 break;
745 }
746 } else {
747 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
748 foundColorSpace = true;
749 }
750 }
751 }
752 if (!foundMatch) {
753 if (!foundFormat) {
754 if (!foundColorSpace) {
755 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
756 "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600757 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,
Ian Elliott329da012015-09-22 10:51:24 -0600758 "%s() called with neither a "
759 "supported pCreateInfo->imageFormat "
760 "(i.e. %d) nor a supported "
761 "pCreateInfo->imageColorSpace "
762 "(i.e. %d).",
763 fn,
764 pCreateInfo->imageFormat,
765 pCreateInfo->imageColorSpace);
766 } else {
767 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
Ian Elliottf81c2562015-09-25 15:50:55 -0600768 "VkDevice",
769 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,
Ian Elliott329da012015-09-22 10:51:24 -0600770 "%s() called with a non-supported "
771 "pCreateInfo->imageFormat (i.e. %d).",
772 fn, pCreateInfo->imageFormat);
773 }
774 } else if (!foundColorSpace) {
775 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600776 SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,
Ian Elliott329da012015-09-22 10:51:24 -0600777 "%s() called with a non-supported "
778 "pCreateInfo->imageColorSpace (i.e. %d).",
779 fn, pCreateInfo->imageColorSpace);
780 }
781 }
782 }
783 if (!pDevice->presentModeCount) {
784 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600785 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600786 "%s() called before calling "
787 "vkGetSurfacePresentModesKHR().",
788 fn);
789 } else {
790 // Validate pCreateInfo->presentMode against
791 // vkGetSurfacePresentModesKHR():
792 bool foundMatch = false;
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600793 for (uint32_t i = 0 ; i < pDevice->presentModeCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600794 if (pDevice->pPresentModes[i] == pCreateInfo->presentMode) {
795 foundMatch = true;
796 break;
797 }
798 }
799 if (!foundMatch) {
800 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600801 SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,
Ian Elliott329da012015-09-22 10:51:24 -0600802 "%s() called with a non-supported "
803 "pCreateInfo->presentMode (i.e. %s).",
804 fn,
805 presentModeStr(pCreateInfo->presentMode));
806 }
807 }
808
809 // TODO: Validate the following values:
810 // - pCreateInfo->sharingMode
811 // - pCreateInfo->queueFamilyCount
812 // - pCreateInfo->pQueueFamilyIndices
813 // - pCreateInfo->oldSwapchain
814
815 return skipCall;
816}
817
818VK_LAYER_EXPORT VkResult VKAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
819{
820 VkResult result = VK_SUCCESS;
821 VkBool32 skipCall = validateCreateSwapchainKHR(device, pCreateInfo,
822 pSwapchain);
823
824 if (VK_FALSE == skipCall) {
825 // Call down the call chain:
826 result = device_dispatch_table(device)->CreateSwapchainKHR(
827 device, pCreateInfo, pSwapchain);
828
829 if (result == VK_SUCCESS) {
830 // Remember the swapchain's handle, and link it to the device:
831 SwpDevice *pDevice = &deviceMap[device];
832
833 swapchainMap[pSwapchain->handle].swapchain = *pSwapchain;
834 pDevice->swapchains[pSwapchain->handle] =
835 &swapchainMap[pSwapchain->handle];
836 swapchainMap[pSwapchain->handle].pDevice = pDevice;
837 swapchainMap[pSwapchain->handle].imageCount = 0;
838 }
839
840 return result;
841 }
842 return VK_ERROR_VALIDATION_FAILED;
843}
844
845VK_LAYER_EXPORT VkResult VKAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain)
846{
847 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600848 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600849
850 // Validate that a valid VkDevice was used, and that the device
851 // extension was enabled:
852 SwpDevice *pDevice = &deviceMap[device];
853 if (!pDevice) {
854 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
855 device,
856 "VkDevice");
857 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
858 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600859 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600860 "%s() called even though the "
861 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
862 "extension was not enabled for this VkDevice.",
863 __FUNCTION__);
864 }
865
866 // Regardless of skipCall value, do some internal cleanup:
867 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
868 if (pSwapchain) {
869 // Delete the SwpSwapchain associated with this swapchain:
870 if (pSwapchain->pDevice) {
871 pSwapchain->pDevice->swapchains.erase(swapchain.handle);
872 if (device != pSwapchain->pDevice->device) {
873 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600874 SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE,
Ian Elliott329da012015-09-22 10:51:24 -0600875 "%s() called with a different VkDevice than the "
876 "VkSwapchainKHR was created with.",
877 __FUNCTION__);
878 }
879 }
880 if (pSwapchain->imageCount) {
881 pSwapchain->images.clear();
882 }
883 swapchainMap.erase(swapchain.handle);
884 } else {
885 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
886 swapchain.handle,
887 "VkSwapchainKHR");
888 }
889
890 if (VK_FALSE == skipCall) {
891 // Call down the call chain:
892 VkResult result = device_dispatch_table(device)->DestroySwapchainKHR(device, swapchain);
893 return result;
894 }
895 return VK_ERROR_VALIDATION_FAILED;
896}
897
898VK_LAYER_EXPORT VkResult VKAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages)
899{
900 VkResult result = VK_SUCCESS;
901 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600902 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600903
904 // Validate that a valid VkDevice was used, and that the device
905 // extension was enabled:
906 SwpDevice *pDevice = &deviceMap[device];
907 if (!pDevice) {
908 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
909 device,
910 "VkDevice");
911 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
912 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600913 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600914 "%s() called even though the "
915 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
916 "extension was not enabled for this VkDevice.",
917 __FUNCTION__);
918 }
919 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
920 if (!pSwapchain) {
921 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
922 swapchain.handle,
923 "VkSwapchainKHR");
924 }
925
926 if (VK_FALSE == skipCall) {
927 // Call down the call chain:
928 result = device_dispatch_table(device)->GetSwapchainImagesKHR(
929 device, swapchain, pCount, pSwapchainImages);
930
Ian Elliott7b7b61c2015-09-28 11:24:53 -0600931// TBD: Should we validate that this function was called once with
932// pSwapchainImages set to NULL (and record pCount at that time), and then
933// called again with a non-NULL pSwapchainImages?
Ian Elliott329da012015-09-22 10:51:24 -0600934 if ((result == VK_SUCCESS) && pSwapchain &&pSwapchainImages &&
935 pCount && (*pCount > 0)) {
936 // Record the images and their state:
937 if (pSwapchain) {
938 pSwapchain->imageCount = *pCount;
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600939 for (uint32_t i = 0 ; i < *pCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600940 pSwapchain->images[i].image = pSwapchainImages[i];
941 pSwapchain->images[i].pSwapchain = pSwapchain;
942 pSwapchain->images[i].ownedByApp = false;
943 }
944 }
945 }
946
947 return result;
948 }
949 return VK_ERROR_VALIDATION_FAILED;
950}
951
952VK_LAYER_EXPORT VkResult VKAPI vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex)
953{
954// TODO: Record/update the state of the swapchain, in case an error occurs
955// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
956 VkResult result = VK_SUCCESS;
957 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600958 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600959
960 // Validate that a valid VkDevice was used, and that the device
961 // extension was enabled:
962 SwpDevice *pDevice = &deviceMap[device];
963 if (!pDevice) {
964 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
965 device,
966 "VkDevice");
967 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
968 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600969 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600970 "%s() called even though the "
971 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
972 "extension was not enabled for this VkDevice.",
973 __FUNCTION__);
974 }
975 // Validate that a valid VkSwapchainKHR was used:
976 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
977 if (!pSwapchain) {
978 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
979 swapchain.handle,
980 "VkSwapchainKHR");
981 } else {
982 // Look to see if the application is trying to own too many images at
983 // the same time (i.e. not leave any to display):
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -0600984 uint32_t imagesOwnedByApp = 0;
985 for (uint32_t i = 0 ; i < pSwapchain->imageCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -0600986 if (pSwapchain->images[i].ownedByApp) {
987 imagesOwnedByApp++;
988 }
989 }
990 if (imagesOwnedByApp >= (pSwapchain->imageCount - 1)) {
Ian Elliotte38ed292015-09-24 18:33:16 -0600991 skipCall |= LOG_PERF_WARNING(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
992 swapchain,
993 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -0600994 SWAPCHAIN_APP_OWNS_TOO_MANY_IMAGES,
Ian Elliotte38ed292015-09-24 18:33:16 -0600995 "%s() called when the application "
996 "already owns all presentable images "
997 "in this swapchain except for the "
998 "image currently being displayed. "
999 "This call to %s() cannot succeed "
1000 "unless another thread calls the "
1001 "vkQueuePresentKHR() function in "
1002 "order to release ownership of one of "
1003 "the presentable images of this "
1004 "swapchain.",
1005 __FUNCTION__, __FUNCTION__);
Ian Elliott329da012015-09-22 10:51:24 -06001006 }
1007 }
1008
1009 if (VK_FALSE == skipCall) {
1010 // Call down the call chain:
1011 result = device_dispatch_table(device)->AcquireNextImageKHR(
1012 device, swapchain, timeout, semaphore, pImageIndex);
1013
1014 if (((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) &&
1015 pSwapchain) {
Ian Elliott329da012015-09-22 10:51:24 -06001016 // Change the state of the image (now owned by the application):
1017 pSwapchain->images[*pImageIndex].ownedByApp = true;
1018 }
1019
1020 return result;
1021 }
1022 return VK_ERROR_VALIDATION_FAILED;
1023}
1024
1025VK_LAYER_EXPORT VkResult VKAPI vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo)
1026{
1027// TODOs:
1028//
1029// - Ensure that the queue is active, and is one of the queueFamilyIndex's
1030// that was returned by a previuos query.
1031// - Record/update the state of the swapchain, in case an error occurs
1032// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
1033 VkResult result = VK_SUCCESS;
1034 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -06001035 layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -06001036
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -06001037 for (uint32_t i = 0; i < pPresentInfo->swapchainCount ; i++) {
1038 uint32_t index = pPresentInfo->imageIndices[i];
Ian Elliott329da012015-09-22 10:51:24 -06001039 SwpSwapchain *pSwapchain =
1040 &swapchainMap[pPresentInfo->swapchains[i].handle];
1041 if (pSwapchain) {
1042 if (!pSwapchain->pDevice->deviceSwapchainExtensionEnabled) {
1043 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE,
1044 pSwapchain->pDevice, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -06001045 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -06001046 "%s() called even though the "
1047 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
1048 "extension was not enabled for this "
1049 "VkDevice.",
1050 __FUNCTION__);
1051 }
1052 if (index >= pSwapchain->imageCount) {
1053 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1054 pPresentInfo->swapchains[i].handle,
1055 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001056 SWAPCHAIN_INDEX_TOO_LARGE,
Ian Elliott329da012015-09-22 10:51:24 -06001057 "%s() called for an index that is too "
1058 "large (i.e. %d). There are only %d "
1059 "images in this VkSwapchainKHR.\n",
1060 __FUNCTION__, index,
1061 pSwapchain->imageCount);
1062 } else {
1063 if (!pSwapchain->images[index].ownedByApp) {
1064 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1065 pPresentInfo->swapchains[i].handle,
1066 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001067 SWAPCHAIN_INDEX_NOT_IN_USE,
Ian Elliott329da012015-09-22 10:51:24 -06001068 "%s() returned an index (i.e. %d) "
1069 "for an image that is not owned by "
1070 "the application.",
1071 __FUNCTION__, index);
1072 }
1073 }
1074 } else {
1075 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1076 pPresentInfo->swapchains[i].handle,
1077 "VkSwapchainKHR");
1078 }
1079 }
1080
1081 if (VK_FALSE == skipCall) {
1082 // Call down the call chain:
1083 result = device_dispatch_table(queue)->QueuePresentKHR(queue,
1084 pPresentInfo);
1085
1086 if ((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) {
Courtney Goeltzenleuchtera2f21d02015-10-07 09:00:34 -06001087 for (uint32_t i = 0; i < pPresentInfo->swapchainCount ; i++) {
Ian Elliott329da012015-09-22 10:51:24 -06001088 int index = pPresentInfo->imageIndices[i];
1089 SwpSwapchain *pSwapchain =
1090 &swapchainMap[pPresentInfo->swapchains[i].handle];
1091 if (pSwapchain) {
1092 // Change the state of the image (no longer owned by the
1093 // application):
1094 pSwapchain->images[index].ownedByApp = false;
1095 }
1096 }
1097 }
1098
1099 return result;
1100 }
1101 return VK_ERROR_VALIDATION_FAILED;
1102}
1103
1104static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)
1105{
1106 if (!name || name[0] != 'v' || name[1] != 'k')
1107 return NULL;
1108
1109 name += 2;
1110 if (!strcmp(name, "CreateInstance"))
1111 return (PFN_vkVoidFunction) vkCreateInstance;
1112 if (!strcmp(name, "DestroyInstance"))
1113 return (PFN_vkVoidFunction) vkDestroyInstance;
1114 if (!strcmp(name, "EnumeratePhysicalDevices"))
1115 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1116 if (!strcmp(name, "CreateDevice"))
1117 return (PFN_vkVoidFunction) vkCreateDevice;
1118 if (!strcmp(name, "DestroyDevice"))
1119 return (PFN_vkVoidFunction) vkDestroyDevice;
1120
1121 return NULL;
1122}
1123static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)
1124{
1125 if (!name || name[0] != 'v' || name[1] != 'k')
1126 return NULL;
1127
1128 name += 2;
1129 if (!strcmp(name, "CreateInstance"))
1130 return (PFN_vkVoidFunction) vkCreateInstance;
1131 if (!strcmp(name, "DestroyInstance"))
1132 return (PFN_vkVoidFunction) vkDestroyInstance;
1133 if (!strcmp(name, "EnumeratePhysicalDevices"))
1134 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1135
1136 return NULL;
1137}
1138
1139VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(VkInstance instance, VkFlags msgFlags, const PFN_vkDbgMsgCallback pfnMsgCallback, void* pUserData, VkDbgMsgCallback* pMsgCallback)
1140{
Ian Elliott960df282015-10-07 16:18:35 -06001141 VkResult result = instance_dispatch_table(instance)->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1142 if (VK_SUCCESS == result) {
1143 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1144 result = layer_create_msg_callback(my_data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1145 }
1146 return result;
Ian Elliott329da012015-09-22 10:51:24 -06001147}
1148
1149VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(VkInstance instance, VkDbgMsgCallback msgCallback)
1150{
Ian Elliott960df282015-10-07 16:18:35 -06001151 VkResult result = instance_dispatch_table(instance)->DbgDestroyMsgCallback(instance, msgCallback);
1152 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1153 layer_destroy_msg_callback(my_data->report_data, msgCallback);
1154 return result;
Ian Elliott329da012015-09-22 10:51:24 -06001155}
1156
1157VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
1158{
1159 PFN_vkVoidFunction addr;
1160 if (device == VK_NULL_HANDLE) {
1161 return NULL;
1162 }
Ian Elliott329da012015-09-22 10:51:24 -06001163
1164 /* loader uses this to force layer initialization; device object is wrapped */
1165 if (!strcmp("vkGetDeviceProcAddr", funcName)) {
1166 initDeviceTable((const VkBaseLayerObject *) device);
1167 return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
1168 }
1169
1170 addr = layer_intercept_proc(funcName);
1171 if (addr)
1172 return addr;
1173
1174 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
1175 if (deviceMap.size() != 0 &&
1176 deviceMap[pDisp].deviceSwapchainExtensionEnabled)
1177 {
1178 if (!strcmp("vkGetSurfacePropertiesKHR", funcName))
1179 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePropertiesKHR);
1180 if (!strcmp("vkGetSurfaceFormatsKHR", funcName))
1181 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfaceFormatsKHR);
1182 if (!strcmp("vkGetSurfacePresentModesKHR", funcName))
1183 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePresentModesKHR);
1184 if (!strcmp("vkCreateSwapchainKHR", funcName))
1185 return reinterpret_cast<PFN_vkVoidFunction>(vkCreateSwapchainKHR);
1186 if (!strcmp("vkDestroySwapchainKHR", funcName))
1187 return reinterpret_cast<PFN_vkVoidFunction>(vkDestroySwapchainKHR);
1188 if (!strcmp("vkGetSwapchainImagesKHR", funcName))
1189 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSwapchainImagesKHR);
1190 if (!strcmp("vkAcquireNextImageKHR", funcName))
1191 return reinterpret_cast<PFN_vkVoidFunction>(vkAcquireNextImageKHR);
1192 if (!strcmp("vkQueuePresentKHR", funcName))
1193 return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
1194 }
1195 {
1196 if (pDisp->GetDeviceProcAddr == NULL)
1197 return NULL;
1198 return pDisp->GetDeviceProcAddr(device, funcName);
1199 }
1200}
1201
1202VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
1203{
1204 PFN_vkVoidFunction addr;
1205 if (instance == VK_NULL_HANDLE) {
1206 return NULL;
1207 }
Ian Elliott329da012015-09-22 10:51:24 -06001208
1209 /* loader uses this to force layer initialization; instance object is wrapped */
1210 if (!strcmp("vkGetInstanceProcAddr", funcName)) {
1211 initInstanceTable((const VkBaseLayerObject *) instance);
1212 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
1213 }
1214
1215 addr = layer_intercept_instance_proc(funcName);
1216 if (addr)
1217 return addr;
1218
1219 VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);
Ian Elliott960df282015-10-07 16:18:35 -06001220 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1221 addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
1222 if (addr) {
1223 return addr;
1224 }
1225
Ian Elliott329da012015-09-22 10:51:24 -06001226 if (instanceMap.size() != 0 &&
1227 instanceMap[instance].swapchainExtensionEnabled)
1228 {
1229 if (!strcmp("vkGetPhysicalDeviceSurfaceSupportKHR", funcName))
1230 return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceSurfaceSupportKHR);
1231 }
1232
1233 if (pTable->GetInstanceProcAddr == NULL)
1234 return NULL;
1235 return pTable->GetInstanceProcAddr(instance, funcName);
1236}
1237