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