26 #ifdef FORCE_NO_VALIDATION 27 #define ENABLE_VALIDATION_LAYERS 0 29 #define ENABLE_VALIDATION_LAYERS 1 35 static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT type,
36 uint64_t
object,
size_t location, int32_t messageCode,
37 const char *pLayerPrefix,
const char *pMessage,
void *pUserData)
39 auto *platform =
static_cast<WSIPlatform *
>(pUserData);
40 auto callback = platform->getExternalDebugCallback();
44 return callback(flags, type,
object, location, messageCode, pLayerPrefix, pMessage,
45 platform->getExternalDebugCallbackUserData());
49 if (flags & VK_DEBUG_REPORT_ERROR_BIT_EXT)
51 LOGE(
"Validation Layer: Error: %s: %s\n", pLayerPrefix, pMessage);
53 else if (flags & VK_DEBUG_REPORT_WARNING_BIT_EXT)
55 LOGE(
"Validation Layer: Warning: %s: %s\n", pLayerPrefix, pMessage);
57 else if (flags & VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT)
59 LOGI(
"Validation Layer: Performance warning: %s: %s\n", pLayerPrefix, pMessage);
63 LOGI(
"Validation Layer: Information: %s: %s\n", pLayerPrefix, pMessage);
69 WSIPlatform::~WSIPlatform()
74 bool WSIPlatform::validateExtensions(
const vector<const char *> &required,
75 const std::vector<VkExtensionProperties> &available)
77 for (
auto extension : required)
80 for (
auto &availableExtension : available)
82 if (strcmp(availableExtension.extensionName, extension) == 0)
96 Result WSIPlatform::initialize()
100 return RESULT_ERROR_OUT_OF_MEMORY;
102 return RESULT_SUCCESS;
105 #define NELEMS(x) (sizeof(x) / sizeof((x)[0])) 106 static const char *pValidationLayers[] = {
107 "VK_LAYER_GOOGLE_threading",
"VK_LAYER_LUNARG_parameter_validation",
"VK_LAYER_LUNARG_object_tracker",
108 "VK_LAYER_LUNARG_core_validation",
"VK_LAYER_LUNARG_device_limits",
"VK_LAYER_LUNARG_image",
109 "VK_LAYER_LUNARG_swapchain",
"VK_LAYER_GOOGLE_unique_objects",
112 static const char *pMetaLayers[] = {
113 "VK_LAYER_LUNARG_standard_validation",
116 static void addSupportedLayers(vector<const char *> &activeLayers,
const vector<VkLayerProperties> &instanceLayers,
117 const char **ppRequested,
unsigned numRequested)
119 for (
unsigned i = 0; i < numRequested; i++)
121 auto *layer = ppRequested[i];
122 for (
auto &ext : instanceLayers)
124 if (strcmp(ext.layerName, layer) == 0)
126 activeLayers.push_back(layer);
134 const vector<const char *> &requiredInstanceExtensions,
135 const vector<const char *> &requiredDeviceExtensions)
137 if (!vulkanSymbolWrapperInitLoader())
139 LOGE(
"Cannot find Vulkan loader.\n");
140 return RESULT_ERROR_GENERIC;
143 if (!vulkanSymbolWrapperLoadGlobalSymbols())
145 LOGE(
"Failed to load global Vulkan symbols.\n");
146 return RESULT_ERROR_GENERIC;
149 uint32_t instanceExtensionCount;
150 vector<const char *> activeInstanceExtensions;
152 VK_CHECK(vkEnumerateInstanceExtensionProperties(
nullptr, &instanceExtensionCount,
nullptr));
153 vector<VkExtensionProperties> instanceExtensions(instanceExtensionCount);
154 VK_CHECK(vkEnumerateInstanceExtensionProperties(
nullptr, &instanceExtensionCount, instanceExtensions.data()));
156 for (
auto &instanceExt : instanceExtensions)
157 LOGI(
"Instance extension: %s\n", instanceExt.extensionName);
159 #if ENABLE_VALIDATION_LAYERS 160 uint32_t instanceLayerCount;
161 VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount,
nullptr));
162 vector<VkLayerProperties> instanceLayers(instanceLayerCount);
163 VK_CHECK(vkEnumerateInstanceLayerProperties(&instanceLayerCount, instanceLayers.data()));
166 for (
auto &layer : instanceLayers)
169 VK_CHECK(vkEnumerateInstanceExtensionProperties(layer.layerName, &count,
nullptr));
170 vector<VkExtensionProperties> extensions(count);
171 VK_CHECK(vkEnumerateInstanceExtensionProperties(layer.layerName, &count, extensions.data()));
172 for (
auto &ext : extensions)
173 instanceExtensions.push_back(ext);
178 vector<const char *> activeLayers;
179 addSupportedLayers(activeLayers, instanceLayers, pMetaLayers, NELEMS(pMetaLayers));
182 if (activeLayers.empty())
184 addSupportedLayers(activeLayers, instanceLayers, pValidationLayers, NELEMS(pValidationLayers));
187 if (activeLayers.empty())
188 LOGI(
"Did not find validation layers.\n");
190 LOGI(
"Found validation layers!\n");
192 addExternalLayers(activeLayers, instanceLayers);
195 bool useInstanceExtensions =
true;
196 if (!validateExtensions(requiredInstanceExtensions, instanceExtensions))
198 LOGI(
"Required instance extensions are missing, will try without.\n");
199 useInstanceExtensions =
false;
202 activeInstanceExtensions = requiredInstanceExtensions;
204 bool haveDebugReport =
false;
205 for (
auto &ext : instanceExtensions)
207 if (strcmp(ext.extensionName,
"VK_EXT_debug_report") == 0)
209 haveDebugReport =
true;
210 useInstanceExtensions =
true;
211 activeInstanceExtensions.push_back(
"VK_EXT_debug_report");
216 VkApplicationInfo app = { VK_STRUCTURE_TYPE_APPLICATION_INFO };
217 app.pApplicationName =
"Mali SDK";
218 app.applicationVersion = 0;
219 app.pEngineName =
"Mali SDK";
220 app.engineVersion = 0;
221 app.apiVersion = VK_MAKE_VERSION(1, 0, 24);
223 VkInstanceCreateInfo instanceInfo = { VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
224 instanceInfo.pApplicationInfo = &app;
225 if (useInstanceExtensions)
227 instanceInfo.enabledExtensionCount = activeInstanceExtensions.size();
228 instanceInfo.ppEnabledExtensionNames = activeInstanceExtensions.data();
231 #if ENABLE_VALIDATION_LAYERS 232 if (!activeLayers.empty())
234 instanceInfo.enabledLayerCount = activeLayers.size();
235 instanceInfo.ppEnabledLayerNames = activeLayers.data();
236 LOGI(
"Using Vulkan instance validation layers.\n");
242 VkResult res = vkCreateInstance(&instanceInfo,
nullptr, &instance);
246 if (res == VK_ERROR_INCOMPATIBLE_DRIVER)
248 app.apiVersion = VK_MAKE_VERSION(1, 0, 1);
249 res = vkCreateInstance(&instanceInfo,
nullptr, &instance);
250 if (res == VK_SUCCESS)
251 LOGI(
"Created Vulkan instance with API version 1.0.1.\n");
254 if (res == VK_ERROR_INCOMPATIBLE_DRIVER)
256 app.apiVersion = VK_MAKE_VERSION(1, 0, 2);
257 res = vkCreateInstance(&instanceInfo,
nullptr, &instance);
258 if (res == VK_SUCCESS)
259 LOGI(
"Created Vulkan instance with API version 1.0.2.\n");
262 if (res != VK_SUCCESS)
264 LOGE(
"Failed to create Vulkan instance (error: %d).\n",
int(res));
265 return RESULT_ERROR_GENERIC;
269 if (!vulkanSymbolWrapperLoadCoreInstanceSymbols(instance))
271 LOGE(
"Failed to load instance symbols.");
272 return RESULT_ERROR_GENERIC;
277 VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkCreateDebugReportCallbackEXT);
278 VkDebugReportCallbackCreateInfoEXT info = { VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT };
279 info.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT |
280 VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
282 info.pfnCallback = debugCallback;
283 info.pUserData =
this;
285 if (vkCreateDebugReportCallbackEXT)
286 vkCreateDebugReportCallbackEXT(instance, &info,
nullptr, &debug_callback);
287 LOGI(
"Enabling Vulkan debug reporting.\n");
290 uint32_t gpuCount = 0;
291 VK_CHECK(vkEnumeratePhysicalDevices(instance, &gpuCount,
nullptr));
295 LOGE(
"Failed to enumerate Vulkan physical device.\n");
296 return RESULT_ERROR_GENERIC;
299 vector<VkPhysicalDevice> gpus(gpuCount);
300 VK_CHECK(vkEnumeratePhysicalDevices(instance, &gpuCount, gpus.data()));
302 gpu = VK_NULL_HANDLE;
303 for (
auto device : gpus)
305 VkPhysicalDeviceProperties properties;
306 vkGetPhysicalDeviceProperties(device, &properties);
309 if (strstr(properties.deviceName,
"Mali"))
312 LOGI(
"Found ARM Mali physical device: %s.\n", properties.deviceName);
318 if (gpu == VK_NULL_HANDLE)
321 vkGetPhysicalDeviceProperties(gpu, &gpuProperties);
322 vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProperties);
325 vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount,
nullptr);
326 queueProperties.resize(queueCount);
327 vkGetPhysicalDeviceQueueFamilyProperties(gpu, &queueCount, queueProperties.data());
330 LOGE(
"Failed to query number of queues.");
331 return RESULT_ERROR_GENERIC;
334 uint32_t deviceExtensionCount;
335 VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu,
nullptr, &deviceExtensionCount,
nullptr));
336 vector<VkExtensionProperties> deviceExtensions(deviceExtensionCount);
337 VK_CHECK(vkEnumerateDeviceExtensionProperties(gpu,
nullptr, &deviceExtensionCount, deviceExtensions.data()));
339 #if ENABLE_VALIDATION_LAYERS 340 uint32_t deviceLayerCount;
341 VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount,
nullptr));
342 vector<VkLayerProperties> deviceLayers(deviceLayerCount);
343 VK_CHECK(vkEnumerateDeviceLayerProperties(gpu, &deviceLayerCount, deviceLayers.data()));
345 activeLayers.clear();
348 addSupportedLayers(activeLayers, deviceLayers, pMetaLayers, NELEMS(pMetaLayers));
351 if (activeLayers.empty())
353 addSupportedLayers(activeLayers, deviceLayers, pValidationLayers, NELEMS(pValidationLayers));
355 addExternalLayers(activeLayers, deviceLayers);
358 for (
auto &deviceExt : deviceExtensions)
359 LOGI(
"Device extension: %s\n", deviceExt.extensionName);
361 bool useDeviceExtensions =
true;
362 if (!validateExtensions(requiredDeviceExtensions, deviceExtensions))
364 LOGI(
"Required device extensions are missing, will try without.\n");
365 useDeviceExtensions =
false;
368 if (FAILED(loadInstanceSymbols()))
370 LOGE(
"Failed to load instance symbols.");
371 return RESULT_ERROR_GENERIC;
374 surface = createSurface();
375 if (surface == VK_NULL_HANDLE)
377 LOGE(
"Failed to create surface.");
378 return RESULT_ERROR_GENERIC;
381 bool foundQueue =
false;
382 for (
unsigned i = 0; i < queueCount; i++)
384 VkBool32 supportsPresent;
388 const VkQueueFlags required = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT;
390 vkGetPhysicalDeviceSurfaceSupportKHR(gpu, i, surface, &supportsPresent);
393 if (((queueProperties[i].queueFlags & required) == required) && supportsPresent)
395 graphicsQueueIndex = i;
403 LOGE(
"Did not find suitable queue which supports graphics, compute and " 405 return RESULT_ERROR_GENERIC;
408 static const float one = 1.0f;
409 VkDeviceQueueCreateInfo queueInfo = { VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO };
410 queueInfo.queueFamilyIndex = graphicsQueueIndex;
411 queueInfo.queueCount = 1;
412 queueInfo.pQueuePriorities = &one;
414 VkPhysicalDeviceFeatures features = {
false };
415 VkDeviceCreateInfo deviceInfo = { VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO };
416 deviceInfo.queueCreateInfoCount = 1;
417 deviceInfo.pQueueCreateInfos = &queueInfo;
418 if (useDeviceExtensions)
420 deviceInfo.enabledExtensionCount = requiredDeviceExtensions.size();
421 deviceInfo.ppEnabledExtensionNames = requiredDeviceExtensions.data();
424 #if ENABLE_VALIDATION_LAYERS 425 if (!activeLayers.empty())
427 deviceInfo.enabledLayerCount = activeLayers.size();
428 deviceInfo.ppEnabledLayerNames = activeLayers.data();
429 LOGI(
"Using Vulkan device validation layers.\n");
433 deviceInfo.pEnabledFeatures = &features;
435 VK_CHECK(vkCreateDevice(gpu, &deviceInfo,
nullptr, &device));
437 if (!vulkanSymbolWrapperLoadCoreDeviceSymbols(device))
439 LOGE(
"Failed to load device symbols.");
440 return RESULT_ERROR_GENERIC;
443 if (FAILED(loadDeviceSymbols()))
445 LOGE(
"Failed to load device symbols.");
446 return RESULT_ERROR_GENERIC;
449 vkGetDeviceQueue(device, graphicsQueueIndex, 0, &queue);
451 Result res = initSwapchain(swapchain);
452 if (res != RESULT_SUCCESS)
454 LOGE(
"Failed to init swapchain.");
458 res = pContext->onPlatformUpdate(
this);
463 return RESULT_SUCCESS;
466 void WSIPlatform::destroySwapchain()
469 vkDeviceWaitIdle(device);
473 vkDestroySwapchainKHR(device, swapchain,
nullptr);
474 swapchain = VK_NULL_HANDLE;
478 void WSIPlatform::terminate()
482 vkDeviceWaitIdle(device);
484 delete semaphoreManager;
485 semaphoreManager =
nullptr;
497 vkDestroySurfaceKHR(instance, surface,
nullptr);
498 surface = VK_NULL_HANDLE;
503 vkDestroyDevice(device,
nullptr);
504 device = VK_NULL_HANDLE;
509 VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDestroyDebugReportCallbackEXT);
510 vkDestroyDebugReportCallbackEXT(instance, debug_callback,
nullptr);
511 debug_callback = VK_NULL_HANDLE;
516 vkDestroyInstance(instance,
nullptr);
517 instance = VK_NULL_HANDLE;
521 Result WSIPlatform::loadDeviceSymbols()
523 if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, vkCreateSwapchainKHR))
524 return RESULT_ERROR_GENERIC;
525 if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, vkDestroySwapchainKHR))
526 return RESULT_ERROR_GENERIC;
527 if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, vkGetSwapchainImagesKHR))
528 return RESULT_ERROR_GENERIC;
529 if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, vkAcquireNextImageKHR))
530 return RESULT_ERROR_GENERIC;
531 if (!VULKAN_SYMBOL_WRAPPER_LOAD_DEVICE_EXTENSION_SYMBOL(device, vkQueuePresentKHR))
532 return RESULT_ERROR_GENERIC;
533 return RESULT_SUCCESS;
536 Result WSIPlatform::loadInstanceSymbols()
538 if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfaceSupportKHR))
539 return RESULT_ERROR_GENERIC;
540 if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfaceCapabilitiesKHR))
541 return RESULT_ERROR_GENERIC;
542 if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfaceFormatsKHR))
543 return RESULT_ERROR_GENERIC;
544 if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceSurfacePresentModesKHR))
545 return RESULT_ERROR_GENERIC;
546 if (!VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkDestroySurfaceKHR))
547 return RESULT_ERROR_GENERIC;
548 return RESULT_SUCCESS;
553 VkSurfaceCapabilitiesKHR surfaceProperties;
554 VK_CHECK(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &surfaceProperties));
556 uint32_t formatCount;
557 vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount,
nullptr);
558 vector<VkSurfaceFormatKHR> formats(formatCount);
559 vkGetPhysicalDeviceSurfaceFormatsKHR(gpu, surface, &formatCount, formats.data());
561 VkSurfaceFormatKHR format;
562 if (formatCount == 1 && formats[0].format == VK_FORMAT_UNDEFINED)
565 format.format = dim.
format;
569 if (formatCount == 0)
571 LOGE(
"Surface has no formats.\n");
572 return RESULT_ERROR_GENERIC;
575 format.format = VK_FORMAT_UNDEFINED;
576 for (
auto &candidate : formats)
578 switch (candidate.format)
581 case VK_FORMAT_R8G8B8A8_UNORM:
582 case VK_FORMAT_B8G8R8A8_UNORM:
583 case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
591 if (format.format != VK_FORMAT_UNDEFINED)
595 if (format.format == VK_FORMAT_UNDEFINED)
599 VkExtent2D swapchainSize;
602 if (surfaceProperties.currentExtent.width == -1u)
604 swapchainSize.width = dim.
width;
605 swapchainSize.height = dim.
height;
608 swapchainSize = surfaceProperties.currentExtent;
611 VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
617 uint32_t desiredSwapchainImages = surfaceProperties.minImageCount + 1;
618 if ((surfaceProperties.maxImageCount > 0) && (desiredSwapchainImages > surfaceProperties.maxImageCount))
621 desiredSwapchainImages = surfaceProperties.maxImageCount;
625 VkSurfaceTransformFlagBitsKHR preTransform;
626 if (surfaceProperties.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
627 preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
629 preTransform = surfaceProperties.currentTransform;
631 VkSwapchainKHR oldSwapchain = swapchain;
634 VkCompositeAlphaFlagBitsKHR composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
635 if (surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR)
636 composite = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
637 else if (surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
638 composite = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
639 else if (surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR)
640 composite = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;
641 else if (surfaceProperties.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR)
642 composite = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;
644 VkSwapchainCreateInfoKHR info = { VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR };
645 info.surface = surface;
646 info.minImageCount = desiredSwapchainImages;
647 info.imageFormat = format.format;
648 info.imageColorSpace = format.colorSpace;
649 info.imageExtent.width = swapchainSize.width;
650 info.imageExtent.height = swapchainSize.height;
651 info.imageArrayLayers = 1;
652 info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
653 info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
654 info.preTransform = preTransform;
655 info.compositeAlpha = composite;
656 info.presentMode = swapchainPresentMode;
658 info.oldSwapchain = oldSwapchain;
660 VK_CHECK(vkCreateSwapchainKHR(device, &info,
nullptr, &swapchain));
662 if (oldSwapchain != VK_NULL_HANDLE)
663 vkDestroySwapchainKHR(device, oldSwapchain,
nullptr);
665 swapchainDimensions.width = swapchainSize.width;
666 swapchainDimensions.height = swapchainSize.height;
667 swapchainDimensions.format = format.format;
670 VK_CHECK(vkGetSwapchainImagesKHR(device, swapchain, &imageCount,
nullptr));
671 swapchainImages.resize(imageCount);
672 VK_CHECK(vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data()));
674 return RESULT_SUCCESS;
679 *images = swapchainImages;
680 *swapchain = swapchainDimensions;
683 unsigned WSIPlatform::getNumSwapchainImages()
const 685 return swapchainImages.size();
688 Result WSIPlatform::acquireNextImage(
unsigned *image)
690 auto acquireSemaphore = semaphoreManager->getClearedSemaphore();
691 VkResult res = vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, acquireSemaphore, VK_NULL_HANDLE, image);
693 if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
695 vkQueueWaitIdle(queue);
696 semaphoreManager->addClearedSemaphore(acquireSemaphore);
699 if (SUCCEEDED(initSwapchain(swapchainDimensions)))
700 return RESULT_ERROR_OUTDATED_SWAPCHAIN;
702 return RESULT_ERROR_GENERIC;
704 else if (res != VK_SUCCESS)
706 vkQueueWaitIdle(queue);
707 semaphoreManager->addClearedSemaphore(acquireSemaphore);
708 return RESULT_ERROR_GENERIC;
718 auto oldSemaphore = pContext->beginFrame(*image, acquireSemaphore);
721 if (oldSemaphore != VK_NULL_HANDLE)
722 semaphoreManager->addClearedSemaphore(oldSemaphore);
724 return RESULT_SUCCESS;
728 Result WSIPlatform::presentImage(
unsigned index)
731 VkPresentInfoKHR present = { VK_STRUCTURE_TYPE_PRESENT_INFO_KHR };
732 present.swapchainCount = 1;
733 present.pSwapchains = &swapchain;
734 present.pImageIndices = &index;
735 present.pResults = &result;
736 present.waitSemaphoreCount = 1;
737 present.pWaitSemaphores = &pContext->getSwapchainReleaseSemaphore();
739 VkResult res = vkQueuePresentKHR(queue, &present);
741 if (res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR)
742 return RESULT_ERROR_OUTDATED_SWAPCHAIN;
743 else if (res != VK_SUCCESS)
744 return RESULT_ERROR_GENERIC;
746 return RESULT_SUCCESS;
The Context is the primary way for samples to interact with the swapchain and get rendered images to ...
The SemaphoreManager keeps track of semaphores.