blob: 3143741bd7d4c460c318439b6e9ea2515ec65da0 [file] [log] [blame]
Ian Elliott329da012015-09-22 10:51:24 -06001/*
2 * Vulkan
3 *
4 * Copyright (C) 2015 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Ian Elliott <ian@lunarg.com>
26 */
27
Ian Elliotte75a4b52015-10-07 11:32:31 -060028#include <stdio.h>
29#include <string.h>
30#include <unordered_map>
31#include "vk_loader_platform.h"
32#include "vk_layer.h"
33#include "vk_layer_config.h"
34#include "vk_layer_logging.h"
35#include "vk_layer_extension_utils.h"
36
Ian Elliott329da012015-09-22 10:51:24 -060037#include "swapchain.h"
38
Ian Elliott960df282015-10-07 16:18:35 -060039
Ian Elliott329da012015-09-22 10:51:24 -060040// FIXME/TODO: Make sure this layer is thread-safe!
41
Ian Elliott960df282015-10-07 16:18:35 -060042
Ian Elliott329da012015-09-22 10:51:24 -060043// The following is for logging error messages:
Ian Elliott960df282015-10-07 16:18:35 -060044static std::unordered_map<void *, layer_data *> layer_data_map;
Ian Elliott329da012015-09-22 10:51:24 -060045
Ian Elliott960df282015-10-07 16:18:35 -060046template layer_data *get_my_data_ptr<layer_data>(
47 void *data_key,
48 std::unordered_map<void *, layer_data *> &data_map);
Ian Elliott329da012015-09-22 10:51:24 -060049
Ian Elliott329da012015-09-22 10:51:24 -060050
51// NOTE: The following are for keeping track of info that is used for
52// validating the WSI extensions.
53static std::unordered_map<void *, SwpInstance> instanceMap;
54static std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
55static std::unordered_map<void *, SwpDevice> deviceMap;
56static std::unordered_map<uint64_t, SwpSwapchain> swapchainMap;
57
58
59static void createDeviceRegisterExtensions(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice device)
60{
61 uint32_t i;
62 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
63 PFN_vkGetDeviceProcAddr gpa = pDisp->GetDeviceProcAddr;
64 pDisp->GetSurfacePropertiesKHR = (PFN_vkGetSurfacePropertiesKHR) gpa(device, "vkGetSurfacePropertiesKHR");
65 pDisp->GetSurfaceFormatsKHR = (PFN_vkGetSurfaceFormatsKHR) gpa(device, "vkGetSurfaceFormatsKHR");
66 pDisp->GetSurfacePresentModesKHR = (PFN_vkGetSurfacePresentModesKHR) gpa(device, "vkGetSurfacePresentModesKHR");
67 pDisp->CreateSwapchainKHR = (PFN_vkCreateSwapchainKHR) gpa(device, "vkCreateSwapchainKHR");
68 pDisp->DestroySwapchainKHR = (PFN_vkDestroySwapchainKHR) gpa(device, "vkDestroySwapchainKHR");
69 pDisp->GetSwapchainImagesKHR = (PFN_vkGetSwapchainImagesKHR) gpa(device, "vkGetSwapchainImagesKHR");
70 pDisp->AcquireNextImageKHR = (PFN_vkAcquireNextImageKHR) gpa(device, "vkAcquireNextImageKHR");
71 pDisp->QueuePresentKHR = (PFN_vkQueuePresentKHR) gpa(device, "vkQueuePresentKHR");
72
73 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
74 if (pPhysicalDevice) {
75 deviceMap[device].pPhysicalDevice = pPhysicalDevice;
76 pPhysicalDevice->pDevice = &deviceMap[device];
77 } else {
Ian Elliott960df282015-10-07 16:18:35 -060078 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -060079 LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
80 physicalDevice,
81 "VkPhysicalDevice");
82 }
83 deviceMap[device].device = device;
84 deviceMap[device].deviceSwapchainExtensionEnabled = false;
85 deviceMap[device].gotSurfaceProperties = false;
86 deviceMap[device].surfaceFormatCount = 0;
87 deviceMap[device].pSurfaceFormats = NULL;
88 deviceMap[device].presentModeCount = 0;
89 deviceMap[device].pPresentModes = NULL;
90
91 // Record whether the WSI device extension was enabled for this VkDevice.
92 // No need to check if the extension was advertised by
93 // vkEnumerateDeviceExtensionProperties(), since the loader handles that.
94 for (i = 0; i < pCreateInfo->extensionCount; i++) {
95 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME) == 0) {
96
97 deviceMap[device].deviceSwapchainExtensionEnabled = true;
98 }
99 }
100}
101
102static void createInstanceRegisterExtensions(const VkInstanceCreateInfo* pCreateInfo, VkInstance instance)
103{
104 uint32_t i;
105 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
106 PFN_vkGetInstanceProcAddr gpa = pDisp->GetInstanceProcAddr;
107 pDisp->GetPhysicalDeviceSurfaceSupportKHR = (PFN_vkGetPhysicalDeviceSurfaceSupportKHR) gpa(instance, "vkGetPhysicalDeviceSurfaceSupportKHR");
108
109 // Remember this instance, and whether the VK_EXT_KHR_swapchain extension
110 // was enabled for it:
111 instanceMap[instance].instance = instance;
112 instanceMap[instance].swapchainExtensionEnabled = false;
113
114 // Record whether the WSI instance extension was enabled for this
115 // VkInstance. No need to check if the extension was advertised by
116 // vkEnumerateInstanceExtensionProperties(), since the loader handles that.
117 for (i = 0; i < pCreateInfo->extensionCount; i++) {
118 if (strcmp(pCreateInfo->ppEnabledExtensionNames[i], VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) {
119
120 instanceMap[instance].swapchainExtensionEnabled = true;
121 }
122 }
123}
124
125
126#include "vk_dispatch_table_helper.h"
Ian Elliott960df282015-10-07 16:18:35 -0600127static void initSwapchain(layer_data *my_data)
Ian Elliott329da012015-09-22 10:51:24 -0600128{
129 uint32_t report_flags = 0;
130 uint32_t debug_action = 0;
131 FILE *log_output = NULL;
132 const char *option_str;
133
134 // Initialize Swapchain options:
135 report_flags = getLayerOptionFlags("SwapchainReportFlags", 0);
136 getLayerOptionEnum("SwapchainDebugAction", (uint32_t *) &debug_action);
137
138 if (debug_action & VK_DBG_LAYER_ACTION_LOG_MSG)
139 {
140 // Turn on logging, since it was requested:
141 option_str = getLayerOption("SwapchainLogFilename");
142 log_output = getLayerLogOutput(option_str, "Swapchain");
Ian Elliott960df282015-10-07 16:18:35 -0600143 layer_create_msg_callback(my_data->report_data, report_flags,
Ian Elliott329da012015-09-22 10:51:24 -0600144 log_callback, (void *) log_output,
Ian Elliott960df282015-10-07 16:18:35 -0600145 &my_data->logging_callback);
Ian Elliott329da012015-09-22 10:51:24 -0600146 }
147}
148
149static const char *surfaceTransformStr(VkSurfaceTransformKHR value)
150{
151 static std::string surfaceTransformStrings[] = {
152 "VK_SURFACE_TRANSFORM_NONE_KHR",
153 "VK_SURFACE_TRANSFORM_ROT90_KHR",
154 "VK_SURFACE_TRANSFORM_ROT180_KHR",
155 "VK_SURFACE_TRANSFORM_ROT270_KHR",
156 "VK_SURFACE_TRANSFORM_HMIRROR_KHR",
157 "VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR",
158 "VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR",
159 "VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR",
160 "Out-of-Range Value"};
161
162 // Deal with a out-of-range value:
163 switch (value) {
164 case VK_SURFACE_TRANSFORM_NONE_KHR:
165 case VK_SURFACE_TRANSFORM_ROT90_KHR:
166 case VK_SURFACE_TRANSFORM_ROT180_KHR:
167 case VK_SURFACE_TRANSFORM_ROT270_KHR:
168 case VK_SURFACE_TRANSFORM_HMIRROR_KHR:
169 case VK_SURFACE_TRANSFORM_HMIRROR_ROT90_KHR:
170 case VK_SURFACE_TRANSFORM_HMIRROR_ROT180_KHR:
171 case VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR:
172 break;
173 default:
174 value =
175 (VkSurfaceTransformKHR) (VK_SURFACE_TRANSFORM_HMIRROR_ROT270_KHR + 1);
176 break;
177 }
178
179 // Return a string corresponding to the value:
180 return surfaceTransformStrings[value].c_str();
181}
182
183static const char *presentModeStr(VkPresentModeKHR value)
184{
185 static std::string presentModeStrings[] = {
186 "VK_PRESENT_MODE_IMMEDIATE_KHR",
187 "VK_PRESENT_MODE_MAILBOX_KHR",
188 "VK_PRESENT_MODE_FIFO_KHR",
189 "Out-of-Range Value"};
190
191 // Deal with a out-of-range value:
192 switch (value) {
193 case VK_PRESENT_MODE_IMMEDIATE_KHR:
194 case VK_PRESENT_MODE_MAILBOX_KHR:
195 case VK_PRESENT_MODE_FIFO_KHR:
196 break;
197 default:
198 value = (VkPresentModeKHR) (VK_PRESENT_MODE_FIFO_KHR + 1);
199 break;
200 }
201
202 // Return a string corresponding to the value:
203 return presentModeStrings[value].c_str();
204}
205
206
207VK_LAYER_EXPORT VkResult VKAPI vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, VkInstance* pInstance)
208{
209 // Call down the call chain:
210 VkResult result = instance_dispatch_table(*pInstance)->CreateInstance(pCreateInfo, pInstance);
211 if (result == VK_SUCCESS) {
212 // Since it succeeded, do layer-specific work:
Ian Elliott960df282015-10-07 16:18:35 -0600213 layer_data *my_data = get_my_data_ptr(get_dispatch_key(*pInstance), layer_data_map);
214 my_data->report_data = debug_report_create_instance(
215 instance_dispatch_table(*pInstance),
216 *pInstance,
217 pCreateInfo->extensionCount,
218 pCreateInfo->ppEnabledExtensionNames);
219 // Call the following function after my_data is initialized:
Ian Elliott329da012015-09-22 10:51:24 -0600220 createInstanceRegisterExtensions(pCreateInfo, *pInstance);
Ian Elliott960df282015-10-07 16:18:35 -0600221 initSwapchain(my_data);
Ian Elliott329da012015-09-22 10:51:24 -0600222 }
223 return result;
224}
225
226VK_LAYER_EXPORT void VKAPI vkDestroyInstance(VkInstance instance)
227{
228 VkBool32 skipCall = VK_FALSE;
229
230 // Validate that a valid VkInstance was used:
231 SwpInstance *pInstance = &instanceMap[instance];
232 if (!pInstance) {
Ian Elliott960df282015-10-07 16:18:35 -0600233 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600234 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
235 instance,
236 "VkInstance");
237 }
238
239 if (VK_FALSE == skipCall) {
240 // Call down the call chain:
241 dispatch_key key = get_dispatch_key(instance);
242 VkLayerInstanceDispatchTable *pDisp = instance_dispatch_table(instance);
243 pDisp->DestroyInstance(instance);
Ian Elliott960df282015-10-07 16:18:35 -0600244
245 // Clean up logging callback, if any
246 layer_data *my_data = get_my_data_ptr(key, layer_data_map);
247 if (my_data->logging_callback) {
248 layer_destroy_msg_callback(my_data->report_data, my_data->logging_callback);
249 }
250 layer_debug_report_destroy_instance(my_data->report_data);
251 layer_data_map.erase(key);
252
Ian Elliott329da012015-09-22 10:51:24 -0600253 destroy_instance_dispatch_table(key);
254 }
255
256 // Regardless of skipCall value, do some internal cleanup:
257 if (pInstance) {
258 // Delete all of the SwpPhysicalDevice's and the SwpInstance associated
259 // with this instance:
260 for (auto it = pInstance->physicalDevices.begin() ;
261 it != pInstance->physicalDevices.end() ; it++) {
262 // Erase the SwpPhysicalDevice's from the physicalDeviceMap (which
263 // are simply pointed to by the SwpInstance):
264 physicalDeviceMap.erase(it->second->physicalDevice);
265 }
266 instanceMap.erase(instance);
267 }
268}
269
270VK_LAYER_EXPORT VkResult VKAPI vkEnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices)
271{
272 VkResult result = VK_SUCCESS;
273 VkBool32 skipCall = VK_FALSE;
274
275 // Validate that a valid VkInstance was used:
276 SwpInstance *pInstance = &instanceMap[instance];
277 if (!pInstance) {
Ian Elliott960df282015-10-07 16:18:35 -0600278 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600279 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_INSTANCE,
280 instance,
281 "VkInstance");
282 }
283
284 if (VK_FALSE == skipCall) {
285 // Call down the call chain:
286 result = instance_dispatch_table(instance)->EnumeratePhysicalDevices(
287 instance, pPhysicalDeviceCount, pPhysicalDevices);
288
289 if ((result == VK_SUCCESS) && pInstance && pPhysicalDevices &&
290 (*pPhysicalDeviceCount > 0)) {
291 // Record the VkPhysicalDevices returned by the ICD:
292 SwpInstance *pInstance = &instanceMap[instance];
293 for (int i = 0; i < *pPhysicalDeviceCount; i++) {
294 physicalDeviceMap[pPhysicalDevices[i]].physicalDevice =
295 pPhysicalDevices[i];
296 physicalDeviceMap[pPhysicalDevices[i]].pInstance = pInstance;
297 physicalDeviceMap[pPhysicalDevices[i]].pDevice = NULL;
298 // Point to the associated SwpInstance:
299 pInstance->physicalDevices[pPhysicalDevices[i]] =
300 &physicalDeviceMap[pPhysicalDevices[i]];
301 }
302 }
303
304 return result;
305 }
306 return VK_ERROR_VALIDATION_FAILED;
307}
308
309VK_LAYER_EXPORT VkResult VKAPI vkCreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, VkDevice* pDevice)
310{
311 VkResult result = VK_SUCCESS;
312 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600313 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600314
315 // Validate that a valid VkPhysicalDevice was used:
316 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
317 if (!pPhysicalDevice) {
318 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
319 physicalDevice,
320 "VkPhysicalDevice");
321 }
322
323 if (VK_FALSE == skipCall) {
324 // Call down the call chain:
325 result = device_dispatch_table(*pDevice)->CreateDevice(
326 physicalDevice, pCreateInfo, pDevice);
327 if (result == VK_SUCCESS) {
328 // Since it succeeded, do layer-specific work:
Ian Elliott960df282015-10-07 16:18:35 -0600329 my_data->report_data = layer_debug_report_create_device(my_data->report_data, *pDevice);
Ian Elliott329da012015-09-22 10:51:24 -0600330 createDeviceRegisterExtensions(physicalDevice, pCreateInfo,
331 *pDevice);
332 }
333 return result;
334 }
335 return VK_ERROR_VALIDATION_FAILED;
336}
337
338VK_LAYER_EXPORT void VKAPI vkDestroyDevice(VkDevice device)
339{
340 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600341 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600342
343 // Validate that a valid VkDevice was used:
344 SwpDevice *pDevice = &deviceMap[device];
345 if (!pDevice) {
346 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
347 device,
348 "VkDevice");
349 }
350
351 if (VK_FALSE == skipCall) {
352 // Call down the call chain:
353 dispatch_key key = get_dispatch_key(device);
354 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
355 pDisp->DestroyDevice(device);
356 destroy_device_dispatch_table(key);
357 }
358
359 // Regardless of skipCall value, do some internal cleanup:
360 if (pDevice) {
361 // Delete the SwpDevice associated with this device:
362 if (pDevice->pPhysicalDevice) {
363 pDevice->pPhysicalDevice->pDevice = NULL;
364 }
365 if (deviceMap[device].pSurfaceFormats) {
366 free(deviceMap[device].pSurfaceFormats);
367 }
368 if (deviceMap[device].pPresentModes) {
369 free(deviceMap[device].pPresentModes);
370 }
Ian Elliott329da012015-09-22 10:51:24 -0600371 if (!pDevice->swapchains.empty()) {
372 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600373 SWAPCHAIN_DEL_DEVICE_BEFORE_SWAPCHAINS,
Ian Elliott329da012015-09-22 10:51:24 -0600374 "%s() called before all of its associated "
375 "VkSwapchainKHRs were destroyed.",
376 __FUNCTION__);
377 // Empty and then delete all SwpSwapchain's
378 for (auto it = pDevice->swapchains.begin() ;
379 it != pDevice->swapchains.end() ; it++) {
380 // Delete all SwpImage's
381 it->second->images.clear();
382 }
383 pDevice->swapchains.clear();
384 }
Cody Northrop73bb6572015-09-28 15:09:32 -0600385 deviceMap.erase(device);
Ian Elliott329da012015-09-22 10:51:24 -0600386 }
387}
388
389VK_LAYER_EXPORT VkResult VKAPI vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkBool32* pSupported)
390{
391 VkResult result = VK_SUCCESS;
392 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600393 layer_data *my_data = get_my_data_ptr(get_dispatch_key(physicalDevice), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600394
395 // Validate that a valid VkPhysicalDevice was used, and that the instance
396 // extension was enabled:
397 SwpPhysicalDevice *pPhysicalDevice = &physicalDeviceMap[physicalDevice];
398 if (!pPhysicalDevice || !pPhysicalDevice->pInstance) {
399 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_PHYSICAL_DEVICE,
400 physicalDevice,
401 "VkPhysicalDevice");
402 } else if (!pPhysicalDevice->pInstance->swapchainExtensionEnabled) {
403 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_INSTANCE,
404 pPhysicalDevice->pInstance,
405 "VkInstance",
Ian Elliottf81c2562015-09-25 15:50:55 -0600406 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600407 "%s() called even though the "
408 VK_EXT_KHR_SWAPCHAIN_EXTENSION_NAME,
409 "extension was not enabled for this VkInstance.",
410 __FUNCTION__);
411 }
412
413 if (VK_FALSE == skipCall) {
414 // Call down the call chain:
415 result = instance_dispatch_table(physicalDevice)->GetPhysicalDeviceSurfaceSupportKHR(
416 physicalDevice, queueFamilyIndex, pSurfaceDescription,
417 pSupported);
418
419 if ((result == VK_SUCCESS) && pSupported && pPhysicalDevice) {
420 // Record the result of this query:
421 pPhysicalDevice->queueFamilyIndexSupport[queueFamilyIndex] =
422 *pSupported;
423 // TODO: We need to compare this with the actual queue used for
424 // presentation, to ensure it was advertised to the application as
425 // supported for presentation.
426 }
427
428 return result;
429 }
430 return VK_ERROR_VALIDATION_FAILED;
431}
432
433VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePropertiesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, VkSurfacePropertiesKHR* pSurfaceProperties)
434{
435 VkResult result = VK_SUCCESS;
436 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600437 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600438
439 // Validate that a valid VkDevice was used, and that the device
440 // extension was enabled:
441 SwpDevice *pDevice = &deviceMap[device];
442 if (!pDevice) {
443 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
444 device,
445 "VkDevice");
446 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
447 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600448 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600449 "%s() called even though the "
450 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
451 "extension was not enabled for this VkDevice.",
452 __FUNCTION__);
453 }
454
455 if (VK_FALSE == skipCall) {
456 // Call down the call chain:
457 result = device_dispatch_table(device)->GetSurfacePropertiesKHR(
458 device, pSurfaceDescription, pSurfaceProperties);
459
460 if ((result == VK_SUCCESS) && pDevice) {
461 pDevice->gotSurfaceProperties = true;
462 pDevice->surfaceProperties = *pSurfaceProperties;
463 }
464
465 return result;
466 }
467 return VK_ERROR_VALIDATION_FAILED;
468}
469
470VK_LAYER_EXPORT VkResult VKAPI vkGetSurfaceFormatsKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkSurfaceFormatKHR* pSurfaceFormats)
471{
472 VkResult result = VK_SUCCESS;
473 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600474 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600475
476 // Validate that a valid VkDevice was used, and that the device
477 // extension was enabled:
478 SwpDevice *pDevice = &deviceMap[device];
479 if (!pDevice) {
480 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
481 device,
482 "VkDevice");
483 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
484 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600485 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600486 "%s() called even though the "
487 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
488 "extension was not enabled for this VkDevice.",
489 __FUNCTION__);
490 }
491
492 if (VK_FALSE == skipCall) {
493 // Call down the call chain:
494 result = device_dispatch_table(device)->GetSurfaceFormatsKHR(
495 device, pSurfaceDescription, pCount, pSurfaceFormats);
496
497 if ((result == VK_SUCCESS) && pDevice && pSurfaceFormats && pCount &&
498 (*pCount > 0)) {
499 pDevice->surfaceFormatCount = *pCount;
500 pDevice->pSurfaceFormats = (VkSurfaceFormatKHR *)
501 malloc(*pCount * sizeof(VkSurfaceFormatKHR));
502 if (pDevice->pSurfaceFormats) {
503 for (int i = 0 ; i < *pCount ; i++) {
504 pDevice->pSurfaceFormats[i] = pSurfaceFormats[i];
505 }
506 } else {
507 pDevice->surfaceFormatCount = 0;
508 }
509 }
510
511 return result;
512 }
513 return VK_ERROR_VALIDATION_FAILED;
514}
515
516VK_LAYER_EXPORT VkResult VKAPI vkGetSurfacePresentModesKHR(VkDevice device, const VkSurfaceDescriptionKHR* pSurfaceDescription, uint32_t* pCount, VkPresentModeKHR* pPresentModes)
517{
518 VkResult result = VK_SUCCESS;
519 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600520 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600521
522 // Validate that a valid VkDevice was used, and that the device
523 // extension was enabled:
524 SwpDevice *pDevice = &deviceMap[device];
525 if (!pDevice) {
526 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
527 device,
528 "VkDevice");
529 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
530 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600531 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600532 "%s() called even though the "
533 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
534 "extension was not enabled for this VkDevice.",
535 __FUNCTION__);
536 }
537
538 if (VK_FALSE == skipCall) {
539 // Call down the call chain:
540 result = device_dispatch_table(device)->GetSurfacePresentModesKHR(
541 device, pSurfaceDescription, pCount, pPresentModes);
542
543 if ((result == VK_SUCCESS) && pDevice && pPresentModes && pCount &&
544 (*pCount > 0)) {
545 pDevice->presentModeCount = *pCount;
546 pDevice->pPresentModes = (VkPresentModeKHR *)
547 malloc(*pCount * sizeof(VkPresentModeKHR));
548 if (pDevice->pSurfaceFormats) {
549 for (int i = 0 ; i < *pCount ; i++) {
550 pDevice->pPresentModes[i] = pPresentModes[i];
551 }
552 } else {
553 pDevice->presentModeCount = 0;
554 }
555 }
556
557 return result;
558 }
559 return VK_ERROR_VALIDATION_FAILED;
560}
561
562// This function does the up-front validation work for vkCreateSwapchainKHR(),
563// and returns VK_TRUE if a logging callback indicates that the call down the
564// chain should be skipped:
565static VkBool32 validateCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
566{
567// TODO: Validate cases of re-creating a swapchain (the current code
568// assumes a new swapchain is being created).
569 VkResult result = VK_SUCCESS;
570 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600571 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600572 char fn[] = "vkCreateSwapchainKHR";
573
574 // Validate that a valid VkDevice was used, and that the device
575 // extension was enabled:
576 SwpDevice *pDevice = &deviceMap[device];
577 if (!pDevice) {
578 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600579 SWAPCHAIN_INVALID_HANDLE,
Ian Elliott329da012015-09-22 10:51:24 -0600580 "%s() called with a non-valid %s.",
581 fn, "VkDevice");
582
583 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
584 return LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600585 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600586 "%s() called even though the "
587 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
588 "extension was not enabled for this VkDevice.",
589 fn);
590 }
591
592 // Validate pCreateInfo with the results for previous queries:
593 if (!pDevice->gotSurfaceProperties) {
594 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600595 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600596 "%s() called before calling "
597 "vkGetSurfacePropertiesKHR().",
598 fn);
599 } else {
600 // Validate pCreateInfo->minImageCount against
601 // VkSurfacePropertiesKHR::{min|max}ImageCount:
602 VkSurfacePropertiesKHR *pProps = &pDevice->surfaceProperties;
603 if ((pCreateInfo->minImageCount < pProps->minImageCount) ||
604 ((pProps->maxImageCount > 0) &&
605 (pCreateInfo->minImageCount > pProps->maxImageCount))) {
606 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600607 SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,
Ian Elliott329da012015-09-22 10:51:24 -0600608 "%s() called with pCreateInfo->minImageCount "
609 "= %d, which is outside the bounds returned "
610 "by vkGetSurfacePropertiesKHR() (i.e. "
611 "minImageCount = %d, maxImageCount = %d).",
612 fn,
613 pCreateInfo->minImageCount,
614 pProps->minImageCount,
615 pProps->maxImageCount);
616 }
617 // Validate pCreateInfo->imageExtent against
618 // VkSurfacePropertiesKHR::{current|min|max}ImageExtent:
619 if ((pProps->currentExtent.width == -1) &&
620 ((pCreateInfo->imageExtent.width < pProps->minImageExtent.width) ||
621 (pCreateInfo->imageExtent.width > pProps->maxImageExtent.width) ||
622 (pCreateInfo->imageExtent.height < pProps->minImageExtent.height) ||
623 (pCreateInfo->imageExtent.height > pProps->maxImageExtent.height))) {
624 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600625 SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS,
Ian Elliott329da012015-09-22 10:51:24 -0600626 "%s() called with pCreateInfo->imageExtent = "
627 "(%d,%d), which is outside the bounds "
628 "returned by vkGetSurfacePropertiesKHR(): "
629 "currentExtent = (%d,%d), minImageExtent = "
630 "(%d,%d), maxImageExtent = (%d,%d).",
631 fn,
632 pCreateInfo->imageExtent.width,
633 pCreateInfo->imageExtent.height,
634 pProps->currentExtent.width,
635 pProps->currentExtent.height,
636 pProps->minImageExtent.width,
637 pProps->minImageExtent.height,
638 pProps->maxImageExtent.width,
639 pProps->maxImageExtent.height);
640 }
641 if ((pProps->currentExtent.width != -1) &&
642 ((pCreateInfo->imageExtent.width != pProps->currentExtent.width) ||
643 (pCreateInfo->imageExtent.height != pProps->currentExtent.height))) {
644 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600645 SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN,
Ian Elliott329da012015-09-22 10:51:24 -0600646 "%s() called with pCreateInfo->imageExtent = "
647 "(%d,%d), which is not equal to the "
648 "currentExtent = (%d,%d) returned by "
649 "vkGetSurfacePropertiesKHR().",
650 fn,
651 pCreateInfo->imageExtent.width,
652 pCreateInfo->imageExtent.height,
653 pProps->currentExtent.width,
654 pProps->currentExtent.height);
655 }
656 // Validate pCreateInfo->preTransform against
657 // VkSurfacePropertiesKHR::supportedTransforms:
658 if (!((1 << pCreateInfo->preTransform) & pProps->supportedTransforms)) {
659 // This is an error situation; one for which we'd like to give
660 // the developer a helpful, multi-line error message. Build it
661 // up a little at a time, and then log it:
662 std::string errorString = "";
663 char str[1024];
664 // Here's the first part of the message:
665 sprintf(str, "%s() called with a non-supported "
666 "pCreateInfo->preTransform (i.e. %s). "
667 "Supported values are:\n",
668 fn,
669 surfaceTransformStr(pCreateInfo->preTransform));
670 errorString += str;
671 for (int i = VK_SURFACE_TRANSFORM_NONE_KHR ;
672 i < VK_SURFACE_TRANSFORM_INHERIT_KHR ; i++) {
673 // Build up the rest of the message:
674 if ((1 << i) & pProps->supportedTransforms) {
675 const char *newStr =
676 surfaceTransformStr((VkSurfaceTransformKHR) (1 << i));
677 sprintf(str, " %s\n", newStr);
678 errorString += str;
679 }
680 }
681 // Log the message that we've built up:
Ian Elliott960df282015-10-07 16:18:35 -0600682 skipCall |= debug_report_log_msg(my_data->report_data,
Ian Elliott329da012015-09-22 10:51:24 -0600683 VK_DBG_REPORT_ERROR_BIT,
684 VK_OBJECT_TYPE_DEVICE,
Ian Elliottf81c2562015-09-25 15:50:55 -0600685 (uint64_t) device, 0,
686 SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,
687 LAYER_NAME,
Ian Elliott329da012015-09-22 10:51:24 -0600688 errorString.c_str());
689 }
690 // Validate pCreateInfo->imageArraySize against
691 // VkSurfacePropertiesKHR::maxImageArraySize:
692 if (pCreateInfo->imageArraySize <= pProps->maxImageArraySize) {
693 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600694 SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,
Ian Elliott329da012015-09-22 10:51:24 -0600695 "%s() called with a non-supported "
696 "pCreateInfo->imageArraySize (i.e. %d). "
697 "Maximum value is %d.",
698 fn,
699 pCreateInfo->imageArraySize,
700 pProps->maxImageArraySize);
701 }
702 // Validate pCreateInfo->imageUsageFlags against
703 // VkSurfacePropertiesKHR::supportedUsageFlags:
704 if (pCreateInfo->imageUsageFlags &&
705 (pCreateInfo->imageUsageFlags !=
706 (pCreateInfo->imageUsageFlags & pProps->supportedUsageFlags))) {
707 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600708 SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,
Ian Elliott329da012015-09-22 10:51:24 -0600709 "%s() called with a non-supported "
710 "pCreateInfo->imageUsageFlags (i.e. 0x%08x)."
711 " Supported flag bits are 0x%08x.",
712 fn,
713 pCreateInfo->imageUsageFlags,
714 pProps->supportedUsageFlags);
715 }
716 }
717 if (!pDevice->surfaceFormatCount) {
718 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600719 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600720 "%s() called before calling "
721 "vkGetSurfaceFormatsKHR().",
722 fn);
723 } else {
724 // Validate pCreateInfo->imageFormat against
725 // VkSurfaceFormatKHR::format:
726 bool foundFormat = false;
727 bool foundColorSpace = false;
728 bool foundMatch = false;
729 for (int i = 0 ; i < pDevice->surfaceFormatCount ; i++) {
730 if (pCreateInfo->imageFormat == pDevice->pSurfaceFormats[i].format) {
731 // Validate pCreateInfo->imageColorSpace against
732 // VkSurfaceFormatKHR::colorSpace:
733 foundFormat = true;
734 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
735 foundMatch = true;
736 break;
737 }
738 } else {
739 if (pCreateInfo->imageColorSpace == pDevice->pSurfaceFormats[i].colorSpace) {
740 foundColorSpace = true;
741 }
742 }
743 }
744 if (!foundMatch) {
745 if (!foundFormat) {
746 if (!foundColorSpace) {
747 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
748 "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600749 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,
Ian Elliott329da012015-09-22 10:51:24 -0600750 "%s() called with neither a "
751 "supported pCreateInfo->imageFormat "
752 "(i.e. %d) nor a supported "
753 "pCreateInfo->imageColorSpace "
754 "(i.e. %d).",
755 fn,
756 pCreateInfo->imageFormat,
757 pCreateInfo->imageColorSpace);
758 } else {
759 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device,
Ian Elliottf81c2562015-09-25 15:50:55 -0600760 "VkDevice",
761 SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,
Ian Elliott329da012015-09-22 10:51:24 -0600762 "%s() called with a non-supported "
763 "pCreateInfo->imageFormat (i.e. %d).",
764 fn, pCreateInfo->imageFormat);
765 }
766 } else if (!foundColorSpace) {
767 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600768 SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,
Ian Elliott329da012015-09-22 10:51:24 -0600769 "%s() called with a non-supported "
770 "pCreateInfo->imageColorSpace (i.e. %d).",
771 fn, pCreateInfo->imageColorSpace);
772 }
773 }
774 }
775 if (!pDevice->presentModeCount) {
776 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600777 SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,
Ian Elliott329da012015-09-22 10:51:24 -0600778 "%s() called before calling "
779 "vkGetSurfacePresentModesKHR().",
780 fn);
781 } else {
782 // Validate pCreateInfo->presentMode against
783 // vkGetSurfacePresentModesKHR():
784 bool foundMatch = false;
785 for (int i = 0 ; i < pDevice->presentModeCount ; i++) {
786 if (pDevice->pPresentModes[i] == pCreateInfo->presentMode) {
787 foundMatch = true;
788 break;
789 }
790 }
791 if (!foundMatch) {
792 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600793 SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,
Ian Elliott329da012015-09-22 10:51:24 -0600794 "%s() called with a non-supported "
795 "pCreateInfo->presentMode (i.e. %s).",
796 fn,
797 presentModeStr(pCreateInfo->presentMode));
798 }
799 }
800
801 // TODO: Validate the following values:
802 // - pCreateInfo->sharingMode
803 // - pCreateInfo->queueFamilyCount
804 // - pCreateInfo->pQueueFamilyIndices
805 // - pCreateInfo->oldSwapchain
806
807 return skipCall;
808}
809
810VK_LAYER_EXPORT VkResult VKAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, VkSwapchainKHR* pSwapchain)
811{
812 VkResult result = VK_SUCCESS;
813 VkBool32 skipCall = validateCreateSwapchainKHR(device, pCreateInfo,
814 pSwapchain);
815
816 if (VK_FALSE == skipCall) {
817 // Call down the call chain:
818 result = device_dispatch_table(device)->CreateSwapchainKHR(
819 device, pCreateInfo, pSwapchain);
820
821 if (result == VK_SUCCESS) {
822 // Remember the swapchain's handle, and link it to the device:
823 SwpDevice *pDevice = &deviceMap[device];
824
825 swapchainMap[pSwapchain->handle].swapchain = *pSwapchain;
826 pDevice->swapchains[pSwapchain->handle] =
827 &swapchainMap[pSwapchain->handle];
828 swapchainMap[pSwapchain->handle].pDevice = pDevice;
829 swapchainMap[pSwapchain->handle].imageCount = 0;
830 }
831
832 return result;
833 }
834 return VK_ERROR_VALIDATION_FAILED;
835}
836
837VK_LAYER_EXPORT VkResult VKAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain)
838{
839 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600840 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600841
842 // Validate that a valid VkDevice was used, and that the device
843 // extension was enabled:
844 SwpDevice *pDevice = &deviceMap[device];
845 if (!pDevice) {
846 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
847 device,
848 "VkDevice");
849 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
850 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600851 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600852 "%s() called even though the "
853 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
854 "extension was not enabled for this VkDevice.",
855 __FUNCTION__);
856 }
857
858 // Regardless of skipCall value, do some internal cleanup:
859 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
860 if (pSwapchain) {
861 // Delete the SwpSwapchain associated with this swapchain:
862 if (pSwapchain->pDevice) {
863 pSwapchain->pDevice->swapchains.erase(swapchain.handle);
864 if (device != pSwapchain->pDevice->device) {
865 LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600866 SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE,
Ian Elliott329da012015-09-22 10:51:24 -0600867 "%s() called with a different VkDevice than the "
868 "VkSwapchainKHR was created with.",
869 __FUNCTION__);
870 }
871 }
872 if (pSwapchain->imageCount) {
873 pSwapchain->images.clear();
874 }
875 swapchainMap.erase(swapchain.handle);
876 } else {
877 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
878 swapchain.handle,
879 "VkSwapchainKHR");
880 }
881
882 if (VK_FALSE == skipCall) {
883 // Call down the call chain:
884 VkResult result = device_dispatch_table(device)->DestroySwapchainKHR(device, swapchain);
885 return result;
886 }
887 return VK_ERROR_VALIDATION_FAILED;
888}
889
890VK_LAYER_EXPORT VkResult VKAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pCount, VkImage* pSwapchainImages)
891{
892 VkResult result = VK_SUCCESS;
893 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600894 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600895
896 // Validate that a valid VkDevice was used, and that the device
897 // extension was enabled:
898 SwpDevice *pDevice = &deviceMap[device];
899 if (!pDevice) {
900 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
901 device,
902 "VkDevice");
903 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
904 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600905 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600906 "%s() called even though the "
907 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
908 "extension was not enabled for this VkDevice.",
909 __FUNCTION__);
910 }
911 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
912 if (!pSwapchain) {
913 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
914 swapchain.handle,
915 "VkSwapchainKHR");
916 }
917
918 if (VK_FALSE == skipCall) {
919 // Call down the call chain:
920 result = device_dispatch_table(device)->GetSwapchainImagesKHR(
921 device, swapchain, pCount, pSwapchainImages);
922
Ian Elliott7b7b61c2015-09-28 11:24:53 -0600923// TBD: Should we validate that this function was called once with
924// pSwapchainImages set to NULL (and record pCount at that time), and then
925// called again with a non-NULL pSwapchainImages?
Ian Elliott329da012015-09-22 10:51:24 -0600926 if ((result == VK_SUCCESS) && pSwapchain &&pSwapchainImages &&
927 pCount && (*pCount > 0)) {
928 // Record the images and their state:
929 if (pSwapchain) {
930 pSwapchain->imageCount = *pCount;
931 for (int i = 0 ; i < *pCount ; i++) {
932 pSwapchain->images[i].image = pSwapchainImages[i];
933 pSwapchain->images[i].pSwapchain = pSwapchain;
934 pSwapchain->images[i].ownedByApp = false;
935 }
936 }
937 }
938
939 return result;
940 }
941 return VK_ERROR_VALIDATION_FAILED;
942}
943
944VK_LAYER_EXPORT VkResult VKAPI vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, uint32_t* pImageIndex)
945{
946// TODO: Record/update the state of the swapchain, in case an error occurs
947// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
948 VkResult result = VK_SUCCESS;
949 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -0600950 layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -0600951
952 // Validate that a valid VkDevice was used, and that the device
953 // extension was enabled:
954 SwpDevice *pDevice = &deviceMap[device];
955 if (!pDevice) {
956 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_DEVICE,
957 device,
958 "VkDevice");
959 } else if (!pDevice->deviceSwapchainExtensionEnabled) {
960 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE, device, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -0600961 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -0600962 "%s() called even though the "
963 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
964 "extension was not enabled for this VkDevice.",
965 __FUNCTION__);
966 }
967 // Validate that a valid VkSwapchainKHR was used:
968 SwpSwapchain *pSwapchain = &swapchainMap[swapchain.handle];
969 if (!pSwapchain) {
970 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
971 swapchain.handle,
972 "VkSwapchainKHR");
973 } else {
974 // Look to see if the application is trying to own too many images at
975 // the same time (i.e. not leave any to display):
976 int imagesOwnedByApp = 0;
977 for (int i = 0 ; i < pSwapchain->imageCount ; i++) {
978 if (pSwapchain->images[i].ownedByApp) {
979 imagesOwnedByApp++;
980 }
981 }
982 if (imagesOwnedByApp >= (pSwapchain->imageCount - 1)) {
Ian Elliotte38ed292015-09-24 18:33:16 -0600983 skipCall |= LOG_PERF_WARNING(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
984 swapchain,
985 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -0600986 SWAPCHAIN_APP_OWNS_TOO_MANY_IMAGES,
Ian Elliotte38ed292015-09-24 18:33:16 -0600987 "%s() called when the application "
988 "already owns all presentable images "
989 "in this swapchain except for the "
990 "image currently being displayed. "
991 "This call to %s() cannot succeed "
992 "unless another thread calls the "
993 "vkQueuePresentKHR() function in "
994 "order to release ownership of one of "
995 "the presentable images of this "
996 "swapchain.",
997 __FUNCTION__, __FUNCTION__);
Ian Elliott329da012015-09-22 10:51:24 -0600998 }
999 }
1000
1001 if (VK_FALSE == skipCall) {
1002 // Call down the call chain:
1003 result = device_dispatch_table(device)->AcquireNextImageKHR(
1004 device, swapchain, timeout, semaphore, pImageIndex);
1005
1006 if (((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) &&
1007 pSwapchain) {
Ian Elliott329da012015-09-22 10:51:24 -06001008 // Change the state of the image (now owned by the application):
1009 pSwapchain->images[*pImageIndex].ownedByApp = true;
1010 }
1011
1012 return result;
1013 }
1014 return VK_ERROR_VALIDATION_FAILED;
1015}
1016
1017VK_LAYER_EXPORT VkResult VKAPI vkQueuePresentKHR(VkQueue queue, VkPresentInfoKHR* pPresentInfo)
1018{
1019// TODOs:
1020//
1021// - Ensure that the queue is active, and is one of the queueFamilyIndex's
1022// that was returned by a previuos query.
1023// - Record/update the state of the swapchain, in case an error occurs
1024// (e.g. VK_ERROR_OUT_OF_DATE_KHR).
1025 VkResult result = VK_SUCCESS;
1026 VkBool32 skipCall = VK_FALSE;
Ian Elliott960df282015-10-07 16:18:35 -06001027 layer_data *my_data = get_my_data_ptr(get_dispatch_key(queue), layer_data_map);
Ian Elliott329da012015-09-22 10:51:24 -06001028
1029 for (int i = 0; i < pPresentInfo->swapchainCount ; i++) {
1030 int index = pPresentInfo->imageIndices[i];
1031 SwpSwapchain *pSwapchain =
1032 &swapchainMap[pPresentInfo->swapchains[i].handle];
1033 if (pSwapchain) {
1034 if (!pSwapchain->pDevice->deviceSwapchainExtensionEnabled) {
1035 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_DEVICE,
1036 pSwapchain->pDevice, "VkDevice",
Ian Elliottf81c2562015-09-25 15:50:55 -06001037 SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,
Ian Elliott329da012015-09-22 10:51:24 -06001038 "%s() called even though the "
1039 VK_EXT_KHR_DEVICE_SWAPCHAIN_EXTENSION_NAME,
1040 "extension was not enabled for this "
1041 "VkDevice.",
1042 __FUNCTION__);
1043 }
1044 if (index >= pSwapchain->imageCount) {
1045 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1046 pPresentInfo->swapchains[i].handle,
1047 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001048 SWAPCHAIN_INDEX_TOO_LARGE,
Ian Elliott329da012015-09-22 10:51:24 -06001049 "%s() called for an index that is too "
1050 "large (i.e. %d). There are only %d "
1051 "images in this VkSwapchainKHR.\n",
1052 __FUNCTION__, index,
1053 pSwapchain->imageCount);
1054 } else {
1055 if (!pSwapchain->images[index].ownedByApp) {
1056 skipCall |= LOG_ERROR(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1057 pPresentInfo->swapchains[i].handle,
1058 "VkSwapchainKHR",
Ian Elliottf81c2562015-09-25 15:50:55 -06001059 SWAPCHAIN_INDEX_NOT_IN_USE,
Ian Elliott329da012015-09-22 10:51:24 -06001060 "%s() returned an index (i.e. %d) "
1061 "for an image that is not owned by "
1062 "the application.",
1063 __FUNCTION__, index);
1064 }
1065 }
1066 } else {
1067 skipCall |= LOG_ERROR_NON_VALID_OBJ(VK_OBJECT_TYPE_SWAPCHAIN_KHR,
1068 pPresentInfo->swapchains[i].handle,
1069 "VkSwapchainKHR");
1070 }
1071 }
1072
1073 if (VK_FALSE == skipCall) {
1074 // Call down the call chain:
1075 result = device_dispatch_table(queue)->QueuePresentKHR(queue,
1076 pPresentInfo);
1077
1078 if ((result == VK_SUCCESS) || (result == VK_SUBOPTIMAL_KHR)) {
1079 for (int i = 0; i < pPresentInfo->swapchainCount ; i++) {
1080 int index = pPresentInfo->imageIndices[i];
1081 SwpSwapchain *pSwapchain =
1082 &swapchainMap[pPresentInfo->swapchains[i].handle];
1083 if (pSwapchain) {
1084 // Change the state of the image (no longer owned by the
1085 // application):
1086 pSwapchain->images[index].ownedByApp = false;
1087 }
1088 }
1089 }
1090
1091 return result;
1092 }
1093 return VK_ERROR_VALIDATION_FAILED;
1094}
1095
1096static inline PFN_vkVoidFunction layer_intercept_proc(const char *name)
1097{
1098 if (!name || name[0] != 'v' || name[1] != 'k')
1099 return NULL;
1100
1101 name += 2;
1102 if (!strcmp(name, "CreateInstance"))
1103 return (PFN_vkVoidFunction) vkCreateInstance;
1104 if (!strcmp(name, "DestroyInstance"))
1105 return (PFN_vkVoidFunction) vkDestroyInstance;
1106 if (!strcmp(name, "EnumeratePhysicalDevices"))
1107 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1108 if (!strcmp(name, "CreateDevice"))
1109 return (PFN_vkVoidFunction) vkCreateDevice;
1110 if (!strcmp(name, "DestroyDevice"))
1111 return (PFN_vkVoidFunction) vkDestroyDevice;
1112
1113 return NULL;
1114}
1115static inline PFN_vkVoidFunction layer_intercept_instance_proc(const char *name)
1116{
1117 if (!name || name[0] != 'v' || name[1] != 'k')
1118 return NULL;
1119
1120 name += 2;
1121 if (!strcmp(name, "CreateInstance"))
1122 return (PFN_vkVoidFunction) vkCreateInstance;
1123 if (!strcmp(name, "DestroyInstance"))
1124 return (PFN_vkVoidFunction) vkDestroyInstance;
1125 if (!strcmp(name, "EnumeratePhysicalDevices"))
1126 return (PFN_vkVoidFunction) vkEnumeratePhysicalDevices;
1127
1128 return NULL;
1129}
1130
1131VK_LAYER_EXPORT VkResult VKAPI vkDbgCreateMsgCallback(VkInstance instance, VkFlags msgFlags, const PFN_vkDbgMsgCallback pfnMsgCallback, void* pUserData, VkDbgMsgCallback* pMsgCallback)
1132{
Ian Elliott960df282015-10-07 16:18:35 -06001133 VkResult result = instance_dispatch_table(instance)->DbgCreateMsgCallback(instance, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1134 if (VK_SUCCESS == result) {
1135 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1136 result = layer_create_msg_callback(my_data->report_data, msgFlags, pfnMsgCallback, pUserData, pMsgCallback);
1137 }
1138 return result;
Ian Elliott329da012015-09-22 10:51:24 -06001139}
1140
1141VK_LAYER_EXPORT VkResult VKAPI vkDbgDestroyMsgCallback(VkInstance instance, VkDbgMsgCallback msgCallback)
1142{
Ian Elliott960df282015-10-07 16:18:35 -06001143 VkResult result = instance_dispatch_table(instance)->DbgDestroyMsgCallback(instance, msgCallback);
1144 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1145 layer_destroy_msg_callback(my_data->report_data, msgCallback);
1146 return result;
Ian Elliott329da012015-09-22 10:51:24 -06001147}
1148
1149VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetDeviceProcAddr(VkDevice device, const char* funcName)
1150{
1151 PFN_vkVoidFunction addr;
1152 if (device == VK_NULL_HANDLE) {
1153 return NULL;
1154 }
Ian Elliott329da012015-09-22 10:51:24 -06001155
1156 /* loader uses this to force layer initialization; device object is wrapped */
1157 if (!strcmp("vkGetDeviceProcAddr", funcName)) {
1158 initDeviceTable((const VkBaseLayerObject *) device);
1159 return (PFN_vkVoidFunction) vkGetDeviceProcAddr;
1160 }
1161
1162 addr = layer_intercept_proc(funcName);
1163 if (addr)
1164 return addr;
1165
1166 VkLayerDispatchTable *pDisp = device_dispatch_table(device);
1167 if (deviceMap.size() != 0 &&
1168 deviceMap[pDisp].deviceSwapchainExtensionEnabled)
1169 {
1170 if (!strcmp("vkGetSurfacePropertiesKHR", funcName))
1171 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePropertiesKHR);
1172 if (!strcmp("vkGetSurfaceFormatsKHR", funcName))
1173 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfaceFormatsKHR);
1174 if (!strcmp("vkGetSurfacePresentModesKHR", funcName))
1175 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSurfacePresentModesKHR);
1176 if (!strcmp("vkCreateSwapchainKHR", funcName))
1177 return reinterpret_cast<PFN_vkVoidFunction>(vkCreateSwapchainKHR);
1178 if (!strcmp("vkDestroySwapchainKHR", funcName))
1179 return reinterpret_cast<PFN_vkVoidFunction>(vkDestroySwapchainKHR);
1180 if (!strcmp("vkGetSwapchainImagesKHR", funcName))
1181 return reinterpret_cast<PFN_vkVoidFunction>(vkGetSwapchainImagesKHR);
1182 if (!strcmp("vkAcquireNextImageKHR", funcName))
1183 return reinterpret_cast<PFN_vkVoidFunction>(vkAcquireNextImageKHR);
1184 if (!strcmp("vkQueuePresentKHR", funcName))
1185 return reinterpret_cast<PFN_vkVoidFunction>(vkQueuePresentKHR);
1186 }
1187 {
1188 if (pDisp->GetDeviceProcAddr == NULL)
1189 return NULL;
1190 return pDisp->GetDeviceProcAddr(device, funcName);
1191 }
1192}
1193
1194VK_LAYER_EXPORT PFN_vkVoidFunction VKAPI vkGetInstanceProcAddr(VkInstance instance, const char* funcName)
1195{
1196 PFN_vkVoidFunction addr;
1197 if (instance == VK_NULL_HANDLE) {
1198 return NULL;
1199 }
Ian Elliott329da012015-09-22 10:51:24 -06001200
1201 /* loader uses this to force layer initialization; instance object is wrapped */
1202 if (!strcmp("vkGetInstanceProcAddr", funcName)) {
1203 initInstanceTable((const VkBaseLayerObject *) instance);
1204 return (PFN_vkVoidFunction) vkGetInstanceProcAddr;
1205 }
1206
1207 addr = layer_intercept_instance_proc(funcName);
1208 if (addr)
1209 return addr;
1210
1211 VkLayerInstanceDispatchTable* pTable = instance_dispatch_table(instance);
Ian Elliott960df282015-10-07 16:18:35 -06001212 layer_data *my_data = get_my_data_ptr(get_dispatch_key(instance), layer_data_map);
1213 addr = debug_report_get_instance_proc_addr(my_data->report_data, funcName);
1214 if (addr) {
1215 return addr;
1216 }
1217
Ian Elliott329da012015-09-22 10:51:24 -06001218 if (instanceMap.size() != 0 &&
1219 instanceMap[instance].swapchainExtensionEnabled)
1220 {
1221 if (!strcmp("vkGetPhysicalDeviceSurfaceSupportKHR", funcName))
1222 return reinterpret_cast<PFN_vkVoidFunction>(vkGetPhysicalDeviceSurfaceSupportKHR);
1223 }
1224
1225 if (pTable->GetInstanceProcAddr == NULL)
1226 return NULL;
1227 return pTable->GetInstanceProcAddr(instance, funcName);
1228}
1229