blob: b45007fc21cf9f33e056d2df4c32a77c5c30191f [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
39// FIXME/TODO: Make sure this layer is thread-safe!
40
41// The following is for logging error messages:
42static layer_data mydata;
43
44
Ian Elliott329da012015-09-22 10:51:24 -060045static LOADER_PLATFORM_THREAD_ONCE_DECLARATION(initOnce);
46
47// NOTE: The following are for keeping track of info that is used for
48// validating the WSI extensions.
49static std::unordered_map<void *, SwpInstance> instanceMap;
50static std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
51static std::unordered_map<void *, SwpDevice> deviceMap;
52static std::unordered_map<uint64_t, SwpSwapchain> swapchainMap;
53
54
55static void createDeviceRegisterExtensions(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice device)
56{
57 uint32_t i;
58 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
59 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
60 pDisp->GetSurfacePropertiesKHR = (PFN_vkGetSurfacePropertiesKHR) gpa(device, "vkGetSurfacePropertiesKHR");
61 pDisp->GetSurfaceFormatsKHR = (PFN_vkGetSurfaceFormatsKHR) gpa(device, "vkGetSurfaceFormatsKHR");
62 pDisp->GetSurfacePresentModesKHR = (PFN_vkGetSurfacePresentModesKHR) gpa(device, "vkGetSurfacePresentModesKHR");
63 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) gpa(device, "vkCreateSwapchainKHR");
64 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) gpa(device, "vkDestroySwapchainKHR");
65 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) gpa(device, "vkGetSwapchainImagesKHR");
66 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) gpa(device, "vkAcquireNextImageKHR");
67 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR) gpa(device, "vkQueuePresentKHR");
68
69 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
70 if (pPhysicalDevice) {
71 deviceMap[device].pPhysicalDevice = pPhysicalDevice;
72 pPhysicalDevice->pDevice = &deviceMap[device];
73 } else {
74 LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
75 physicalDevice,
76 "VkPhysicalDevice");
77 }
78 deviceMap[device].device = device;
79 deviceMap[device].deviceSwapchainExtensionEnabled = false;
80 deviceMap[device].gotSurfaceProperties = false;
81 deviceMap[device].surfaceFormatCount = 0;
82 deviceMap[device].pSurfaceFormats = NULL;
83 deviceMap[device].presentModeCount = 0;
84 deviceMap[device].pPresentModes = NULL;
85
86 // Record whether the WSI device extension was enabled for this VkDevice.
87 // No need to check if the extension was advertised by
88 // vkEnumerateDeviceExtensionProperties(), since the loader handles that.
89 for (i = 0; i < pCreateInfo->extensionCount; i++) {
90 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME) == 0) {
91
92 deviceMap[device].deviceSwapchainExtensionEnabled = true;
93 }
94 }
95}
96
97static void createInstanceRegisterExtensions(const VkInstanceCreateInfo* pCreateInfo, VkInstance instance)
98{
99 uint32_t i;
100 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
101 PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
102 pDisp->GetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
103
104 // Remember this instance, and whether the VK_EXT_KHR_swapchain extension
105 // was enabled for it:
106 instanceMap[instance].instance = instance;
107 instanceMap[instance].swapchainExtensionEnabled = false;
108
109 // Record whether the WSI instance extension was enabled for this
110 // VkInstance. No need to check if the extension was advertised by
111 // vkEnumerateInstanceExtensionProperties(), since the loader handles that.
112 for (i = 0; i < pCreateInfo->extensionCount; i++) {
113 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
114
115 instanceMap[instance].swapchainExtensionEnabled = true;
116 }
117 }
118}
119
120
121#include "vk_dispatch_table_helper.h"
122static void initSwapchain(void)
123{
124 uint32_t report_flags = 0;
125 uint32_t debug_action = 0;
126 FILE *log_output = NULL;
127 const char *option_str;
128
129 // Initialize Swapchain options:
130 report_flags = getLayerOptionFlags("SwapchainReportFlags", 0);
131 getLayerOptionEnum("SwapchainDebugAction", (uint32_t *) &debug_action);
132
133 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
134 {
135 // Turn on logging, since it was requested:
136 option_str = getLayerOption("SwapchainLogFilename");
137 log_output = getLayerLogOutput(option_str, "Swapchain");
Cody Northrop73bb6572015-09-28 15:09:32 -0600138 layer_create_msg_callback(mydata.report_data, report_flags,
Ian Elliott329da012015-09-22 10:51:24 -0600139 log_callback, (void *) log_output,
140 &mydata.logging_callback);
141 }
142}
143
144static const char *surfaceTransformStr(VkSurfaceTransformKHR value)
145{
146 static std::string surfaceTransformStrings[] = {
147 "VK_SURFACE_TRANSFORM_NONE_KHR",
148 "VK_SURFACE_TRANSFORM_ROT90_KHR",
149 "VK_SURFACE_TRANSFORM_ROT180_KHR",
150 "VK_SURFACE_TRANSFORM_ROT270_KHR",
151 "VK_SURFACE_TRANSFORM_HMIRROR_KHR",
152 "VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR",
153 "VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR",
154 "VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR",
155 "Out-of-Range Value"};
156
157 // Deal with a out-of-range value:
158 switch (value) {
159 case VK_SURFACE_TRANSFORM_NONE_KHR:
160 case VK_SURFACE_TRANSFORM_ROT90_KHR:
161 case VK_SURFACE_TRANSFORM_ROT180_KHR:
162 case VK_SURFACE_TRANSFORM_ROT270_KHR:
163 case VK_SURFACE_TRANSFORM_HMIRROR_KHR:
164 case VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR:
165 case VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR:
166 case VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR:
167 break;
168 default:
169 value =
170 (VkSurfaceTransformKHR) (VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR + 1);
171 break;
172 }
173
174 // Return a string corresponding to the value:
175 return surfaceTransformStrings[value].c_str();
176}
177
178static const char *presentModeStr(VkPresentModeKHR value)
179{
180 static std::string presentModeStrings[] = {
181 "VK_PRESENT_MODE_IMMEDIATE_KHR",
182 "VK_PRESENT_MODE_MAILBOX_KHR",
183 "VK_PRESENT_MODE_FIFO_KHR",
184 "Out-of-Range Value"};
185
186 // Deal with a out-of-range value:
187 switch (value) {
188 case VK_PRESENT_MODE_IMMEDIATE_KHR:
189 case VK_PRESENT_MODE_MAILBOX_KHR:
190 case VK_PRESENT_MODE_FIFO_KHR:
191 break;
192 default:
193 value = (VkPresentModeKHR) (VK_PRESENT_MODE_FIFO_KHR + 1);
194 break;
195 }
196
197 // Return a string corresponding to the value:
198 return presentModeStrings[value].c_str();
199}
200
201
202VK_LAYER_EXPORT VkResult VKAPI vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance)
203{
204 // Call down the call chain:
205 VkResult result = instance_dispatch_table(*pInstance)->CreateInstance(pCreateInfo, pInstance);
206 if (result == VK_SUCCESS) {
207 // Since it succeeded, do layer-specific work:
208 createInstanceRegisterExtensions(pCreateInfo, *pInstance);
209 }
210 return result;
211}
212
213VK_LAYER_EXPORT void VKAPI vkDestroyInstance(VkInstance instance)
214{
215 VkBool32 skipCall = VK_FALSE;
216
217 // Validate that a valid VkInstance was used:
218 SwpInstance *pInstance = &instanceMap[instance];
219 if (!pInstance) {
220 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
221 instance,
222 "VkInstance");
223 }
224
225 if (VK_FALSE == skipCall) {
226 // Call down the call chain:
227 dispatch_key key = get_dispatch_key(instance);
228 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
229 pDisp->DestroyInstance(instance);
230 destroy_instance_dispatch_table(key);
231 }
232
233 // Regardless of skipCall value, do some internal cleanup:
234 if (pInstance) {
235 // Delete all of the SwpPhysicalDevice's and the SwpInstance associated
236 // with this instance:
237 for (auto it = pInstance->physicalDevices.begin() ;
238 it != pInstance->physicalDevices.end() ; it++) {
239 // Erase the SwpPhysicalDevice's from the physicalDeviceMap (which
240 // are simply pointed to by the SwpInstance):
241 physicalDeviceMap.erase(it->second->physicalDevice);
242 }
243 instanceMap.erase(instance);
244 }
245}
246
247VK_LAYER_EXPORT VkResult VKAPI vkEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices)
248{
249 VkResult result = VK_SUCCESS;
250 VkBool32 skipCall = VK_FALSE;
251
252 // Validate that a valid VkInstance was used:
253 SwpInstance *pInstance = &instanceMap[instance];
254 if (!pInstance) {
255 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
256 instance,
257 "VkInstance");
258 }
259
260 if (VK_FALSE == skipCall) {
261 // Call down the call chain:
262 result = instance_dispatch_table(instance)->EnumeratePhysicalDevices(
263 instance, pPhysicalDeviceCount, pPhysicalDevices);
264
265 if ((result == VK_SUCCESS) && pInstance && pPhysicalDevices &&
266 (*pPhysicalDeviceCount > 0)) {
267 // Record the VkPhysicalDevices returned by the ICD:
268 SwpInstance *pInstance = &instanceMap[instance];
269 for (int i = 0; i < *pPhysicalDeviceCount; i++) {
270 physicalDeviceMap[pPhysicalDevices[i]].physicalDevice =
271 pPhysicalDevices[i];
272 physicalDeviceMap[pPhysicalDevices[i]].pInstance = pInstance;
273 physicalDeviceMap[pPhysicalDevices[i]].pDevice = NULL;
274 // Point to the associated SwpInstance:
275 pInstance->physicalDevices[pPhysicalDevices[i]] =
276 &physicalDeviceMap[pPhysicalDevices[i]];
277 }
278 }
279
280 return result;
281 }
282 return VK_ERROR_VALIDATION_FAILED;
283}
284
285VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
286{
287 VkResult result = VK_SUCCESS;
288 VkBool32 skipCall = VK_FALSE;
289
290 // Validate that a valid VkPhysicalDevice was used:
291 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
292 if (!pPhysicalDevice) {
293 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
294 physicalDevice,
295 "VkPhysicalDevice");
296 }
297
298 if (VK_FALSE == skipCall) {
299 // Call down the call chain:
300 result = device_dispatch_table(*pDevice)->CreateDevice(
301 physicalDevice, pCreateInfo, pDevice);
302 if (result == VK_SUCCESS) {
303 // Since it succeeded, do layer-specific work:
304 createDeviceRegisterExtensions(physicalDevice, pCreateInfo,
305 *pDevice);
306 }
307 return result;
308 }
309 return VK_ERROR_VALIDATION_FAILED;
310}
311
312VK_LAYER_EXPORT void VKAPI vkDestroyDevice(VkDevice device)
313{
314 VkBool32 skipCall = VK_FALSE;
315
316 // Validate that a valid VkDevice was used:
317 SwpDevice *pDevice = &deviceMap[device];
318 if (!pDevice) {
319 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
320 device,
321 "VkDevice");
322 }
323
324 if (VK_FALSE == skipCall) {
325 // Call down the call chain:
326 dispatch_key key = get_dispatch_key(device);
327 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
328 pDisp->DestroyDevice(device);
329 destroy_device_dispatch_table(key);
330 }
331
332 // Regardless of skipCall value, do some internal cleanup:
333 if (pDevice) {
334 // Delete the SwpDevice associated with this device:
335 if (pDevice->pPhysicalDevice) {
336 pDevice->pPhysicalDevice->pDevice = NULL;
337 }
338 if (deviceMap[device].pSurfaceFormats) {
339 free(deviceMap[device].pSurfaceFormats);
340 }
341 if (deviceMap[device].pPresentModes) {
342 free(deviceMap[device].pPresentModes);
343 }
Ian Elliott329da012015-09-22 10:51:24 -0600344 if (!pDevice->swapchains.empty()) {
345 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600346 SWAPCHAIN_DEL_DEVICE_BEFORE_SWAPCHAINS,
Ian Elliott329da012015-09-22 10:51:24 -0600347 "%s() called before all of its associated "
348 "VkSwapchainKHRs were destroyed.",
349 __FUNCTION__);
350 // Empty and then delete all SwpSwapchain's
351 for (auto it = pDevice->swapchains.begin() ;
352 it != pDevice->swapchains.end() ; it++) {
353 // Delete all SwpImage's
354 it->second->images.clear();
355 }
356 pDevice->swapchains.clear();
357 }
Cody Northrop73bb6572015-09-28 15:09:32 -0600358 deviceMap.erase(device);
Ian Elliott329da012015-09-22 10:51:24 -0600359 }
360}
361
362VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported)
363{
364 VkResult result = VK_SUCCESS;
365 VkBool32 skipCall = VK_FALSE;
366
367 // Validate that a valid VkPhysicalDevice was used, and that the instance
368 // extension was enabled:
369 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
370 if (!pPhysicalDevice || !pPhysicalDevice->pInstance) {
371 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
372 physicalDevice,
373 "VkPhysicalDevice");
374 } else if (!pPhysicalDevice->pInstance->swapchainExtensionEnabled) {
375 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_INSTANCE,
376 pPhysicalDevice->pInstance,
377 "VkInstance",
Ian Elliottf81c2562015-09-25 15:50:55 -0600378 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600379 "%s() called even though the "
380 VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME,
381 "extension was not enabled for this VkInstance.",
382 __FUNCTION__);
383 }
384
385 if (VK_FALSE == skipCall) {
386 // Call down the call chain:
387 result = instance_dispatch_table(physicalDevice)->GetPhysicalDeviceSurfaceSupportKHR(
388 physicalDevice, queueFamilyIndex, pSurfaceDescription,
389 pSupported);
390
391 if ((result == VK_SUCCESS) && pSupported && pPhysicalDevice) {
392 // Record the result of this query:
393 pPhysicalDevice->queueFamilyIndexSupport[queueFamilyIndex] =
394 *pSupported;
395 // TODO: We need to compare this with the actual queue used for
396 // presentation, to ensure it was advertised to the application as
397 // supported for presentation.
398 }
399
400 return result;
401 }
402 return VK_ERROR_VALIDATION_FAILED;
403}
404
405VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePropertiesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties)
406{
407 VkResult result = VK_SUCCESS;
408 VkBool32 skipCall = VK_FALSE;
409
410 // Validate that a valid VkDevice was used, and that the device
411 // extension was enabled:
412 SwpDevice *pDevice = &deviceMap[device];
413 if (!pDevice) {
414 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
415 device,
416 "VkDevice");
417 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
418 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600419 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600420 "%s() called even though the "
421 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
422 "extension was not enabled for this VkDevice.",
423 __FUNCTION__);
424 }
425
426 if (VK_FALSE == skipCall) {
427 // Call down the call chain:
428 result = device_dispatch_table(device)->GetSurfacePropertiesKHR(
429 device, pSurfaceDescription, pSurfaceProperties);
430
431 if ((result == VK_SUCCESS) && pDevice) {
432 pDevice->gotSurfaceProperties = true;
433 pDevice->surfaceProperties = *pSurfaceProperties;
434 }
435
436 return result;
437 }
438 return VK_ERROR_VALIDATION_FAILED;
439}
440
441VK_LAYER_EXPORT VkResult VKAPI vkGetSurfaceFormatsKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats)
442{
443 VkResult result = VK_SUCCESS;
444 VkBool32 skipCall = VK_FALSE;
445
446 // Validate that a valid VkDevice was used, and that the device
447 // extension was enabled:
448 SwpDevice *pDevice = &deviceMap[device];
449 if (!pDevice) {
450 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
451 device,
452 "VkDevice");
453 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
454 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600455 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600456 "%s() called even though the "
457 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
458 "extension was not enabled for this VkDevice.",
459 __FUNCTION__);
460 }
461
462 if (VK_FALSE == skipCall) {
463 // Call down the call chain:
464 result = device_dispatch_table(device)->GetSurfaceFormatsKHR(
465 device, pSurfaceDescription, pCount, pSurfaceFormats);
466
467 if ((result == VK_SUCCESS) && pDevice && pSurfaceFormats && pCount &&
468 (*pCount > 0)) {
469 pDevice->surfaceFormatCount = *pCount;
470 pDevice->pSurfaceFormats = (VkSurfaceFormatKHR *)
471 malloc(*pCount * sizeof(VkSurfaceFormatKHR));
472 if (pDevice->pSurfaceFormats) {
473 for (int i = 0 ; i < *pCount ; i++) {
474 pDevice->pSurfaceFormats[i] = pSurfaceFormats[i];
475 }
476 } else {
477 pDevice->surfaceFormatCount = 0;
478 }
479 }
480
481 return result;
482 }
483 return VK_ERROR_VALIDATION_FAILED;
484}
485
486VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePresentModesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes)
487{
488 VkResult result = VK_SUCCESS;
489 VkBool32 skipCall = VK_FALSE;
490
491 // Validate that a valid VkDevice was used, and that the device
492 // extension was enabled:
493 SwpDevice *pDevice = &deviceMap[device];
494 if (!pDevice) {
495 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
496 device,
497 "VkDevice");
498 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
499 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600500 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600501 "%s() called even though the "
502 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
503 "extension was not enabled for this VkDevice.",
504 __FUNCTION__);
505 }
506
507 if (VK_FALSE == skipCall) {
508 // Call down the call chain:
509 result = device_dispatch_table(device)->GetSurfacePresentModesKHR(
510 device, pSurfaceDescription, pCount, pPresentModes);
511
512 if ((result == VK_SUCCESS) && pDevice && pPresentModes && pCount &&
513 (*pCount > 0)) {
514 pDevice->presentModeCount = *pCount;
515 pDevice->pPresentModes = (VkPresentModeKHR *)
516 malloc(*pCount * sizeof(VkPresentModeKHR));
517 if (pDevice->pSurfaceFormats) {
518 for (int i = 0 ; i < *pCount ; i++) {
519 pDevice->pPresentModes[i] = pPresentModes[i];
520 }
521 } else {
522 pDevice->presentModeCount = 0;
523 }
524 }
525
526 return result;
527 }
528 return VK_ERROR_VALIDATION_FAILED;
529}
530
531// This function does the up-front validation work for vkCreateSwapchainKHR(),
532// and returns VK_TRUE if a logging callback indicates that the call down the
533// chain should be skipped:
534static VkBool32 validateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
535{
536// TODO: Validate cases of re-creating a swapchain (the current code
537// assumes a new swapchain is being created).
538 VkResult result = VK_SUCCESS;
539 VkBool32 skipCall = VK_FALSE;
540 char fn[] = "vkCreateSwapchainKHR";
541
542 // Validate that a valid VkDevice was used, and that the device
543 // extension was enabled:
544 SwpDevice *pDevice = &deviceMap[device];
545 if (!pDevice) {
546 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600547 SWAPCHAIN_INVALID_HANDLE,
Ian Elliott329da012015-09-22 10:51:24 -0600548 "%s() called with a non-valid %s.",
549 fn, "VkDevice");
550
551 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
552 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600553 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600554 "%s() called even though the "
555 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
556 "extension was not enabled for this VkDevice.",
557 fn);
558 }
559
560 // Validate pCreateInfo with the results for previous queries:
561 if (!pDevice->gotSurfaceProperties) {
562 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600563 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600564 "%s() called before calling "
565 "vkGetSurfacePropertiesKHR().",
566 fn);
567 } else {
568 // Validate pCreateInfo->minImageCount against
569 // VkSurfacePropertiesKHR::{min|max}ImageCount:
570 VkSurfacePropertiesKHR *pProps = &pDevice->surfaceProperties;
571 if ((pCreateInfo->minImageCount < pProps->minImageCount) ||
572 ((pProps->maxImageCount > 0) &&
573 (pCreateInfo->minImageCount > pProps->maxImageCount))) {
574 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600575 SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,
Ian Elliott329da012015-09-22 10:51:24 -0600576 "%s() called with pCreateInfo->minImageCount "
577 "= %d, which is outside the bounds returned "
578 "by vkGetSurfacePropertiesKHR() (i.e. "
579 "minImageCount = %d, maxImageCount = %d).",
580 fn,
581 pCreateInfo->minImageCount,
582 pProps->minImageCount,
583 pProps->maxImageCount);
584 }
585 // Validate pCreateInfo->imageExtent against
586 // VkSurfacePropertiesKHR::{current|min|max}ImageExtent:
587 if ((pProps->currentExtent.width == -1) &&
588 ((pCreateInfo->imageExtent.width < pProps->minImageExtent.width) ||
589 (pCreateInfo->imageExtent.width > pProps->maxImageExtent.width) ||
590 (pCreateInfo->imageExtent.height < pProps->minImageExtent.height) ||
591 (pCreateInfo->imageExtent.height > pProps->maxImageExtent.height))) {
592 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600593 SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS,
Ian Elliott329da012015-09-22 10:51:24 -0600594 "%s() called with pCreateInfo->imageExtent = "
595 "(%d,%d), which is outside the bounds "
596 "returned by vkGetSurfacePropertiesKHR(): "
597 "currentExtent = (%d,%d), minImageExtent = "
598 "(%d,%d), maxImageExtent = (%d,%d).",
599 fn,
600 pCreateInfo->imageExtent.width,
601 pCreateInfo->imageExtent.height,
602 pProps->currentExtent.width,
603 pProps->currentExtent.height,
604 pProps->minImageExtent.width,
605 pProps->minImageExtent.height,
606 pProps->maxImageExtent.width,
607 pProps->maxImageExtent.height);
608 }
609 if ((pProps->currentExtent.width != -1) &&
610 ((pCreateInfo->imageExtent.width != pProps->currentExtent.width) ||
611 (pCreateInfo->imageExtent.height != pProps->currentExtent.height))) {
612 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600613 SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN,
Ian Elliott329da012015-09-22 10:51:24 -0600614 "%s() called with pCreateInfo->imageExtent = "
615 "(%d,%d), which is not equal to the "
616 "currentExtent = (%d,%d) returned by "
617 "vkGetSurfacePropertiesKHR().",
618 fn,
619 pCreateInfo->imageExtent.width,
620 pCreateInfo->imageExtent.height,
621 pProps->currentExtent.width,
622 pProps->currentExtent.height);
623 }
624 // Validate pCreateInfo->preTransform against
625 // VkSurfacePropertiesKHR::supportedTransforms:
626 if (!((1 << pCreateInfo->preTransform) & pProps->supportedTransforms)) {
627 // This is an error situation; one for which we'd like to give
628 // the developer a helpful, multi-line error message. Build it
629 // up a little at a time, and then log it:
630 std::string errorString = "";
631 char str[1024];
632 // Here's the first part of the message:
633 sprintf(str, "%s() called with a non-supported "
634 "pCreateInfo->preTransform (i.e. %s). "
635 "Supported values are:\n",
636 fn,
637 surfaceTransformStr(pCreateInfo->preTransform));
638 errorString += str;
639 for (int i = VK_SURFACE_TRANSFORM_NONE_KHR ;
640 i < VK_SURFACE_TRANSFORM_INHERIT_KHR ; i++) {
641 // Build up the rest of the message:
642 if ((1 << i) & pProps->supportedTransforms) {
643 const char *newStr =
644 surfaceTransformStr((VkSurfaceTransformKHR) (1 << i));
645 sprintf(str, " %s\n", newStr);
646 errorString += str;
647 }
648 }
649 // Log the message that we've built up:
Cody Northrop73bb6572015-09-28 15:09:32 -0600650 skipCall |= debug_report_log_msg(mydata.report_data,
Ian Elliott329da012015-09-22 10:51:24 -0600651 VK_DBG_REPORT_ERROR_BIT,
652 VK_OBJECT_TYPE_DEVICE,
Ian Elliottf81c2562015-09-25 15:50:55 -0600653 (uint64_t) device, 0,
654 SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,
655 LAYER_NAME,
Ian Elliott329da012015-09-22 10:51:24 -0600656 errorString.c_str());
657 }
658 // Validate pCreateInfo->imageArraySize against
659 // VkSurfacePropertiesKHR::maxImageArraySize:
660 if (pCreateInfo->imageArraySize <= pProps->maxImageArraySize) {
661 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600662 SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,
Ian Elliott329da012015-09-22 10:51:24 -0600663 "%s() called with a non-supported "
664 "pCreateInfo->imageArraySize (i.e. %d). "
665 "Maximum value is %d.",
666 fn,
667 pCreateInfo->imageArraySize,
668 pProps->maxImageArraySize);
669 }
670 // Validate pCreateInfo->imageUsageFlags against
671 // VkSurfacePropertiesKHR::supportedUsageFlags:
672 if (pCreateInfo->imageUsageFlags &&
673 (pCreateInfo->imageUsageFlags !=
674 (pCreateInfo->imageUsageFlags & pProps->supportedUsageFlags))) {
675 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600676 SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,
Ian Elliott329da012015-09-22 10:51:24 -0600677 "%s() called with a non-supported "
678 "pCreateInfo->imageUsageFlags (i.e. 0x%08x)."
679 " Supported flag bits are 0x%08x.",
680 fn,
681 pCreateInfo->imageUsageFlags,
682 pProps->supportedUsageFlags);
683 }
684 }
685 if (!pDevice->surfaceFormatCount) {
686 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600687 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600688 "%s() called before calling "
689 "vkGetSurfaceFormatsKHR().",
690 fn);
691 } else {
692 // Validate pCreateInfo->imageFormat against
693 // VkSurfaceFormatKHR::format:
694 bool foundFormat = false;
695 bool foundColorSpace = false;
696 bool foundMatch = false;
697 for (int i = 0 ; i < pDevice->surfaceFormatCount ; i++) {
698 if (pCreateInfo->imageFormat == pDevice->pSurfaceFormats[i].format) {
699 // Validate pCreateInfo->imageColorSpace against
700 // VkSurfaceFormatKHR::colorSpace:
701 foundFormat = true;
702 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
703 foundMatch = true;
704 break;
705 }
706 } else {
707 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
708 foundColorSpace = true;
709 }
710 }
711 }
712 if (!foundMatch) {
713 if (!foundFormat) {
714 if (!foundColorSpace) {
715 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
716 "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600717 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,
Ian Elliott329da012015-09-22 10:51:24 -0600718 "%s() called with neither a "
719 "supported pCreateInfo->imageFormat "
720 "(i.e. %d) nor a supported "
721 "pCreateInfo->imageColorSpace "
722 "(i.e. %d).",
723 fn,
724 pCreateInfo->imageFormat,
725 pCreateInfo->imageColorSpace);
726 } else {
727 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
Ian Elliottf81c2562015-09-25 15:50:55 -0600728 "VkDevice",
729 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,
Ian Elliott329da012015-09-22 10:51:24 -0600730 "%s() called with a non-supported "
731 "pCreateInfo->imageFormat (i.e. %d).",
732 fn, pCreateInfo->imageFormat);
733 }
734 } else if (!foundColorSpace) {
735 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600736 SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,
Ian Elliott329da012015-09-22 10:51:24 -0600737 "%s() called with a non-supported "
738 "pCreateInfo->imageColorSpace (i.e. %d).",
739 fn, pCreateInfo->imageColorSpace);
740 }
741 }
742 }
743 if (!pDevice->presentModeCount) {
744 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600745 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600746 "%s() called before calling "
747 "vkGetSurfacePresentModesKHR().",
748 fn);
749 } else {
750 // Validate pCreateInfo->presentMode against
751 // vkGetSurfacePresentModesKHR():
752 bool foundMatch = false;
753 for (int i = 0 ; i < pDevice->presentModeCount ; i++) {
754 if (pDevice->pPresentModes[i] == pCreateInfo->presentMode) {
755 foundMatch = true;
756 break;
757 }
758 }
759 if (!foundMatch) {
760 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600761 SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,
Ian Elliott329da012015-09-22 10:51:24 -0600762 "%s() called with a non-supported "
763 "pCreateInfo->presentMode (i.e. %s).",
764 fn,
765 presentModeStr(pCreateInfo->presentMode));
766 }
767 }
768
769 // TODO: Validate the following values:
770 // - pCreateInfo->sharingMode
771 // - pCreateInfo->queueFamilyCount
772 // - pCreateInfo->pQueueFamilyIndices
773 // - pCreateInfo->oldSwapchain
774
775 return skipCall;
776}
777
778VK_LAYER_EXPORT VkResult VKAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
779{
780 VkResult result = VK_SUCCESS;
781 VkBool32 skipCall = validateCreateSwapchainKHR(device, pCreateInfo,
782 pSwapchain);
783
784 if (VK_FALSE == skipCall) {
785 // Call down the call chain:
786 result = device_dispatch_table(device)->CreateSwapchainKHR(
787 device, pCreateInfo, pSwapchain);
788
789 if (result == VK_SUCCESS) {
790 // Remember the swapchain's handle, and link it to the device:
791 SwpDevice *pDevice = &deviceMap[device];
792
793 swapchainMap[pSwapchain->handle].swapchain = *pSwapchain;
794 pDevice->swapchains[pSwapchain->handle] =
795 &swapchainMap[pSwapchain->handle];
796 swapchainMap[pSwapchain->handle].pDevice = pDevice;
797 swapchainMap[pSwapchain->handle].imageCount = 0;
798 }
799
800 return result;
801 }
802 return VK_ERROR_VALIDATION_FAILED;
803}
804
805VK_LAYER_EXPORT VkResult VKAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain)
806{
807 VkBool32 skipCall = VK_FALSE;
808
809 // Validate that a valid VkDevice was used, and that the device
810 // extension was enabled:
811 SwpDevice *pDevice = &deviceMap[device];
812 if (!pDevice) {
813 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
814 device,
815 "VkDevice");
816 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
817 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600818 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600819 "%s() called even though the "
820 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
821 "extension was not enabled for this VkDevice.",
822 __FUNCTION__);
823 }
824
825 // Regardless of skipCall value, do some internal cleanup:
826 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
827 if (pSwapchain) {
828 // Delete the SwpSwapchain associated with this swapchain:
829 if (pSwapchain->pDevice) {
830 pSwapchain->pDevice->swapchains.erase(swapchain.handle);
831 if (device != pSwapchain->pDevice->device) {
832 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600833 SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE,
Ian Elliott329da012015-09-22 10:51:24 -0600834 "%s() called with a different VkDevice than the "
835 "VkSwapchainKHR was created with.",
836 __FUNCTION__);
837 }
838 }
839 if (pSwapchain->imageCount) {
840 pSwapchain->images.clear();
841 }
842 swapchainMap.erase(swapchain.handle);
843 } else {
844 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
845 swapchain.handle,
846 "VkSwapchainKHR");
847 }
848
849 if (VK_FALSE == skipCall) {
850 // Call down the call chain:
851 VkResult result = device_dispatch_table(device)->DestroySwapchainKHR(device, swapchain);
852 return result;
853 }
854 return VK_ERROR_VALIDATION_FAILED;
855}
856
857VK_LAYER_EXPORT VkResult VKAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages)
858{
859 VkResult result = VK_SUCCESS;
860 VkBool32 skipCall = VK_FALSE;
861
862 // Validate that a valid VkDevice was used, and that the device
863 // extension was enabled:
864 SwpDevice *pDevice = &deviceMap[device];
865 if (!pDevice) {
866 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
867 device,
868 "VkDevice");
869 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
870 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600871 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600872 "%s() called even though the "
873 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
874 "extension was not enabled for this VkDevice.",
875 __FUNCTION__);
876 }
877 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
878 if (!pSwapchain) {
879 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
880 swapchain.handle,
881 "VkSwapchainKHR");
882 }
883
884 if (VK_FALSE == skipCall) {
885 // Call down the call chain:
886 result = device_dispatch_table(device)->GetSwapchainImagesKHR(
887 device, swapchain, pCount, pSwapchainImages);
888
Ian Elliott7b7b61c2015-09-28 11:24:53 -0600889// TBD: Should we validate that this function was called once with
890// pSwapchainImages set to NULL (and record pCount at that time), and then
891// called again with a non-NULL pSwapchainImages?
Ian Elliott329da012015-09-22 10:51:24 -0600892 if ((result == VK_SUCCESS) && pSwapchain &&pSwapchainImages &&
893 pCount && (*pCount > 0)) {
894 // Record the images and their state:
895 if (pSwapchain) {
896 pSwapchain->imageCount = *pCount;
897 for (int i = 0 ; i < *pCount ; i++) {
898 pSwapchain->images[i].image = pSwapchainImages[i];
899 pSwapchain->images[i].pSwapchain = pSwapchain;
900 pSwapchain->images[i].ownedByApp = false;
901 }
902 }
903 }
904
905 return result;
906 }
907 return VK_ERROR_VALIDATION_FAILED;
908}
909
910VK_LAYER_EXPORT VkResult VKAPI vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex)
911{
912// TODO: Record/update the state of the swapchain, in case an error occurs
913// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
914 VkResult result = VK_SUCCESS;
915 VkBool32 skipCall = VK_FALSE;
916
917 // Validate that a valid VkDevice was used, and that the device
918 // extension was enabled:
919 SwpDevice *pDevice = &deviceMap[device];
920 if (!pDevice) {
921 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
922 device,
923 "VkDevice");
924 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
925 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600926 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600927 "%s() called even though the "
928 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
929 "extension was not enabled for this VkDevice.",
930 __FUNCTION__);
931 }
932 // Validate that a valid VkSwapchainKHR was used:
933 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
934 if (!pSwapchain) {
935 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
936 swapchain.handle,
937 "VkSwapchainKHR");
938 } else {
939 // Look to see if the application is trying to own too many images at
940 // the same time (i.e. not leave any to display):
941 int imagesOwnedByApp = 0;
942 for (int i = 0 ; i < pSwapchain->imageCount ; i++) {
943 if (pSwapchain->images[i].ownedByApp) {
944 imagesOwnedByApp++;
945 }
946 }
947 if (imagesOwnedByApp >= (pSwapchain->imageCount - 1)) {
Ian Elliotte38ed292015-09-24 18:33:16 -0600948 skipCall |= LOG_PERF_WARNING(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
949 swapchain,
950 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -0600951 SWAPCHAIN_APP_OWNS_TOO_MANY_IMAGES,
Ian Elliotte38ed292015-09-24 18:33:16 -0600952 "%s() called when the application "
953 "already owns all presentable images "
954 "in this swapchain except for the "
955 "image currently being displayed. "
956 "This call to %s() cannot succeed "
957 "unless another thread calls the "
958 "vkQueuePresentKHR() function in "
959 "order to release ownership of one of "
960 "the presentable images of this "
961 "swapchain.",
962 __FUNCTION__, __FUNCTION__);
Ian Elliott329da012015-09-22 10:51:24 -0600963 }
964 }
965
966 if (VK_FALSE == skipCall) {
967 // Call down the call chain:
968 result = device_dispatch_table(device)->AcquireNextImageKHR(
969 device, swapchain, timeout, semaphore, pImageIndex);
970
971 if (((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) &&
972 pSwapchain) {
Ian Elliott329da012015-09-22 10:51:24 -0600973 // Change the state of the image (now owned by the application):
974 pSwapchain->images[*pImageIndex].ownedByApp = true;
975 }
976
977 return result;
978 }
979 return VK_ERROR_VALIDATION_FAILED;
980}
981
982VK_LAYER_EXPORT VkResult VKAPI vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo)
983{
984// TODOs:
985//
986// - Ensure that the queue is active, and is one of the queueFamilyIndex's
987// that was returned by a previuos query.
988// - Record/update the state of the swapchain, in case an error occurs
989// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
990 VkResult result = VK_SUCCESS;
991 VkBool32 skipCall = VK_FALSE;
992
993 for (int i = 0; i < pPresentInfo->swapchainCount ; i++) {
994 int index = pPresentInfo->imageIndices[i];
995 SwpSwapchain *pSwapchain =
996 &swapchainMap[pPresentInfo->swapchains[i].handle];
997 if (pSwapchain) {
998 if (!pSwapchain->pDevice->deviceSwapchainExtensionEnabled) {
999 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE,
1000 pSwapchain->pDevice, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -06001001 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -06001002 "%s() called even though the "
1003 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
1004 "extension was not enabled for this "
1005 "VkDevice.",
1006 __FUNCTION__);
1007 }
1008 if (index >= pSwapchain->imageCount) {
1009 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1010 pPresentInfo->swapchains[i].handle,
1011 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001012 SWAPCHAIN_INDEX_TOO_LARGE,
Ian Elliott329da012015-09-22 10:51:24 -06001013 "%s() called for an index that is too "
1014 "large (i.e. %d). There are only %d "
1015 "images in this VkSwapchainKHR.\n",
1016 __FUNCTION__, index,
1017 pSwapchain->imageCount);
1018 } else {
1019 if (!pSwapchain->images[index].ownedByApp) {
1020 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1021 pPresentInfo->swapchains[i].handle,
1022 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001023 SWAPCHAIN_INDEX_NOT_IN_USE,
Ian Elliott329da012015-09-22 10:51:24 -06001024 "%s() returned an index (i.e. %d) "
1025 "for an image that is not owned by "
1026 "the application.",
1027 __FUNCTION__, index);
1028 }
1029 }
1030 } else {
1031 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1032 pPresentInfo->swapchains[i].handle,
1033 "VkSwapchainKHR");
1034 }
1035 }
1036
1037 if (VK_FALSE == skipCall) {
1038 // Call down the call chain:
1039 result = device_dispatch_table(queue)->QueuePresentKHR(queue,
1040 pPresentInfo);
1041
1042 if ((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) {
1043 for (int i = 0; i < pPresentInfo->swapchainCount ; i++) {
1044 int index = pPresentInfo->imageIndices[i];
1045 SwpSwapchain *pSwapchain =
1046 &swapchainMap[pPresentInfo->swapchains[i].handle];
1047 if (pSwapchain) {
1048 // Change the state of the image (no longer owned by the
1049 // application):
1050 pSwapchain->images[index].ownedByApp = false;
1051 }
1052 }
1053 }
1054
1055 return result;
1056 }
1057 return VK_ERROR_VALIDATION_FAILED;
1058}
1059
1060static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)
1061{
1062 if (!name || name[0] != 'v' || name[1] != 'k')
1063 return NULL;
1064
1065 name += 2;
1066 if (!strcmp(name, "CreateInstance"))
1067 return (PFN_vkVoidFunction) vkCreateInstance;
1068 if (!strcmp(name, "DestroyInstance"))
1069 return (PFN_vkVoidFunction) vkDestroyInstance;
1070 if (!strcmp(name, "EnumeratePhysicalDevices"))
1071 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1072 if (!strcmp(name, "CreateDevice"))
1073 return (PFN_vkVoidFunction) vkCreateDevice;
1074 if (!strcmp(name, "DestroyDevice"))
1075 return (PFN_vkVoidFunction) vkDestroyDevice;
1076
1077 return NULL;
1078}
1079static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)
1080{
1081 if (!name || name[0] != 'v' || name[1] != 'k')
1082 return NULL;
1083
1084 name += 2;
1085 if (!strcmp(name, "CreateInstance"))
1086 return (PFN_vkVoidFunction) vkCreateInstance;
1087 if (!strcmp(name, "DestroyInstance"))
1088 return (PFN_vkVoidFunction) vkDestroyInstance;
1089 if (!strcmp(name, "EnumeratePhysicalDevices"))
1090 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1091
1092 return NULL;
1093}
1094
1095VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(VkInstance instance, VkFlags msgFlags, const PFN_vkDbgMsgCallback pfnMsgCallback, void* pUserData, VkDbgMsgCallback* pMsgCallback)
1096{
Cody Northrop73bb6572015-09-28 15:09:32 -06001097 return layer_create_msg_callback(mydata.report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
Ian Elliott329da012015-09-22 10:51:24 -06001098}
1099
1100VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(VkInstance instance, VkDbgMsgCallback msgCallback)
1101{
Cody Northrop73bb6572015-09-28 15:09:32 -06001102 layer_destroy_msg_callback(mydata.report_data, msgCallback);
Ian Elliott329da012015-09-22 10:51:24 -06001103 return VK_SUCCESS;
1104}
1105
1106VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
1107{
1108 PFN_vkVoidFunction addr;
1109 if (device == VK_NULL_HANDLE) {
1110 return NULL;
1111 }
1112 loader_platform_thread_once(&initOnce, initSwapchain);
1113
1114 /* loader uses this to force layer initialization; device object is wrapped */
1115 if (!strcmp("vkGetDeviceProcAddr", funcName)) {
1116 initDeviceTable((const VkBaseLayerObject *) device);
1117 return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
1118 }
1119
1120 addr = layer_intercept_proc(funcName);
1121 if (addr)
1122 return addr;
1123
1124 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
1125 if (deviceMap.size() != 0 &&
1126 deviceMap[pDisp].deviceSwapchainExtensionEnabled)
1127 {
1128 if (!strcmp("vkGetSurfacePropertiesKHR", funcName))
1129 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePropertiesKHR);
1130 if (!strcmp("vkGetSurfaceFormatsKHR", funcName))
1131 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfaceFormatsKHR);
1132 if (!strcmp("vkGetSurfacePresentModesKHR", funcName))
1133 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePresentModesKHR);
1134 if (!strcmp("vkCreateSwapchainKHR", funcName))
1135 return reinterpret_cast<PFN_vkVoidFunction>(vkCreateSwapchainKHR);
1136 if (!strcmp("vkDestroySwapchainKHR", funcName))
1137 return reinterpret_cast<PFN_vkVoidFunction>(vkDestroySwapchainKHR);
1138 if (!strcmp("vkGetSwapchainImagesKHR", funcName))
1139 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSwapchainImagesKHR);
1140 if (!strcmp("vkAcquireNextImageKHR", funcName))
1141 return reinterpret_cast<PFN_vkVoidFunction>(vkAcquireNextImageKHR);
1142 if (!strcmp("vkQueuePresentKHR", funcName))
1143 return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
1144 }
1145 {
1146 if (pDisp->GetDeviceProcAddr == NULL)
1147 return NULL;
1148 return pDisp->GetDeviceProcAddr(device, funcName);
1149 }
1150}
1151
1152VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
1153{
1154 PFN_vkVoidFunction addr;
1155 if (instance == VK_NULL_HANDLE) {
1156 return NULL;
1157 }
1158 loader_platform_thread_once(&initOnce, initSwapchain);
1159
1160 /* loader uses this to force layer initialization; instance object is wrapped */
1161 if (!strcmp("vkGetInstanceProcAddr", funcName)) {
1162 initInstanceTable((const VkBaseLayerObject *) instance);
1163 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
1164 }
1165
1166 addr = layer_intercept_instance_proc(funcName);
1167 if (addr)
1168 return addr;
1169
1170 VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);
1171 if (instanceMap.size() != 0 &&
1172 instanceMap[instance].swapchainExtensionEnabled)
1173 {
1174 if (!strcmp("vkGetPhysicalDeviceSurfaceSupportKHR", funcName))
1175 return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceSurfaceSupportKHR);
1176 }
1177
1178 if (pTable->GetInstanceProcAddr == NULL)
1179 return NULL;
1180 return pTable->GetInstanceProcAddr(instance, funcName);
1181}
1182