Atlas - testvulkan.c
Home / ext / SDL / test Lines: 1 | Size: 46418 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 3 4 This software is provided 'as-is', without any express or implied 5 warranty. In no event will the authors be held liable for any damages 6 arising from the use of this software. 7 8 Permission is granted to anyone to use this software for any purpose, 9 including commercial applications, and to alter it and redistribute it 10 freely. 11*/ 12#include <stdlib.h> 13 14#include <SDL3/SDL_test_common.h> 15#include <SDL3/SDL_main.h> 16 17#if defined(SDL_PLATFORM_ANDROID) && defined(__ARM_EABI__) && !defined(__ARM_ARCH_7A__) 18 19int main(int argc, char *argv[]) 20{ 21 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "No Vulkan support on this system"); 22 return 1; 23} 24 25#else 26 27#define VK_NO_PROTOTYPES 28#ifdef HAVE_VULKAN_H 29#include <vulkan/vulkan.h> 30#else 31/* SDL includes a copy for building on systems without the Vulkan SDK */ 32#include "../src/video/khronos/vulkan/vulkan.h" 33#endif 34#include <SDL3/SDL_vulkan.h> 35 36#ifndef UINT64_MAX /* VS2008 */ 37#define UINT64_MAX 18446744073709551615 38#endif 39 40#define VULKAN_FUNCTIONS() \ 41 VULKAN_DEVICE_FUNCTION(vkAcquireNextImageKHR) \ 42 VULKAN_DEVICE_FUNCTION(vkAllocateCommandBuffers) \ 43 VULKAN_DEVICE_FUNCTION(vkBeginCommandBuffer) \ 44 VULKAN_DEVICE_FUNCTION(vkCmdClearColorImage) \ 45 VULKAN_DEVICE_FUNCTION(vkCmdPipelineBarrier) \ 46 VULKAN_DEVICE_FUNCTION(vkCreateCommandPool) \ 47 VULKAN_DEVICE_FUNCTION(vkCreateFence) \ 48 VULKAN_DEVICE_FUNCTION(vkCreateImageView) \ 49 VULKAN_DEVICE_FUNCTION(vkCreateSemaphore) \ 50 VULKAN_DEVICE_FUNCTION(vkCreateSwapchainKHR) \ 51 VULKAN_DEVICE_FUNCTION(vkDestroyCommandPool) \ 52 VULKAN_DEVICE_FUNCTION(vkDestroyDevice) \ 53 VULKAN_DEVICE_FUNCTION(vkDestroyFence) \ 54 VULKAN_DEVICE_FUNCTION(vkDestroyImageView) \ 55 VULKAN_DEVICE_FUNCTION(vkDestroySemaphore) \ 56 VULKAN_DEVICE_FUNCTION(vkDestroySwapchainKHR) \ 57 VULKAN_DEVICE_FUNCTION(vkDeviceWaitIdle) \ 58 VULKAN_DEVICE_FUNCTION(vkEndCommandBuffer) \ 59 VULKAN_DEVICE_FUNCTION(vkFreeCommandBuffers) \ 60 VULKAN_DEVICE_FUNCTION(vkGetDeviceQueue) \ 61 VULKAN_DEVICE_FUNCTION(vkGetFenceStatus) \ 62 VULKAN_DEVICE_FUNCTION(vkGetSwapchainImagesKHR) \ 63 VULKAN_DEVICE_FUNCTION(vkQueuePresentKHR) \ 64 VULKAN_DEVICE_FUNCTION(vkQueueSubmit) \ 65 VULKAN_DEVICE_FUNCTION(vkResetCommandBuffer) \ 66 VULKAN_DEVICE_FUNCTION(vkResetFences) \ 67 VULKAN_DEVICE_FUNCTION(vkWaitForFences) \ 68 VULKAN_GLOBAL_FUNCTION(vkCreateInstance) \ 69 VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceExtensionProperties) \ 70 VULKAN_GLOBAL_FUNCTION(vkEnumerateInstanceLayerProperties) \ 71 VULKAN_INSTANCE_FUNCTION(vkCreateDevice) \ 72 VULKAN_INSTANCE_FUNCTION(vkDestroyInstance) \ 73 VULKAN_INSTANCE_FUNCTION(vkDestroySurfaceKHR) \ 74 VULKAN_INSTANCE_FUNCTION(vkEnumerateDeviceExtensionProperties) \ 75 VULKAN_INSTANCE_FUNCTION(vkEnumeratePhysicalDevices) \ 76 VULKAN_INSTANCE_FUNCTION(vkGetDeviceProcAddr) \ 77 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceFeatures) \ 78 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceProperties) \ 79 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceQueueFamilyProperties) \ 80 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceCapabilitiesKHR) \ 81 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceFormatsKHR) \ 82 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfacePresentModesKHR) \ 83 VULKAN_INSTANCE_FUNCTION(vkGetPhysicalDeviceSurfaceSupportKHR) 84 85#define VULKAN_DEVICE_FUNCTION(name) static PFN_##name name = NULL; 86#define VULKAN_GLOBAL_FUNCTION(name) static PFN_##name name = NULL; 87#define VULKAN_INSTANCE_FUNCTION(name) static PFN_##name name = NULL; 88VULKAN_FUNCTIONS() 89#undef VULKAN_DEVICE_FUNCTION 90#undef VULKAN_GLOBAL_FUNCTION 91#undef VULKAN_INSTANCE_FUNCTION 92static PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = NULL; 93 94/* Based on the headers found in 95 * https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers 96 */ 97#if VK_HEADER_VERSION < 22 98enum 99{ 100 VK_ERROR_FRAGMENTED_POOL = -12, 101}; 102#endif 103#if VK_HEADER_VERSION < 38 104enum 105{ 106 VK_ERROR_OUT_OF_POOL_MEMORY_KHR = -1000069000 107}; 108#endif 109 110static const char *getVulkanResultString(VkResult result) 111{ 112 switch ((int)result) { 113#define RESULT_CASE(x) \ 114 case x: \ 115 return #x 116 RESULT_CASE(VK_SUCCESS); 117 RESULT_CASE(VK_NOT_READY); 118 RESULT_CASE(VK_TIMEOUT); 119 RESULT_CASE(VK_EVENT_SET); 120 RESULT_CASE(VK_EVENT_RESET); 121 RESULT_CASE(VK_INCOMPLETE); 122 RESULT_CASE(VK_ERROR_OUT_OF_HOST_MEMORY); 123 RESULT_CASE(VK_ERROR_OUT_OF_DEVICE_MEMORY); 124 RESULT_CASE(VK_ERROR_INITIALIZATION_FAILED); 125 RESULT_CASE(VK_ERROR_DEVICE_LOST); 126 RESULT_CASE(VK_ERROR_MEMORY_MAP_FAILED); 127 RESULT_CASE(VK_ERROR_LAYER_NOT_PRESENT); 128 RESULT_CASE(VK_ERROR_EXTENSION_NOT_PRESENT); 129 RESULT_CASE(VK_ERROR_FEATURE_NOT_PRESENT); 130 RESULT_CASE(VK_ERROR_INCOMPATIBLE_DRIVER); 131 RESULT_CASE(VK_ERROR_TOO_MANY_OBJECTS); 132 RESULT_CASE(VK_ERROR_FORMAT_NOT_SUPPORTED); 133 RESULT_CASE(VK_ERROR_FRAGMENTED_POOL); 134 RESULT_CASE(VK_ERROR_SURFACE_LOST_KHR); 135 RESULT_CASE(VK_ERROR_NATIVE_WINDOW_IN_USE_KHR); 136 RESULT_CASE(VK_SUBOPTIMAL_KHR); 137 RESULT_CASE(VK_ERROR_OUT_OF_DATE_KHR); 138 RESULT_CASE(VK_ERROR_INCOMPATIBLE_DISPLAY_KHR); 139 RESULT_CASE(VK_ERROR_VALIDATION_FAILED_EXT); 140 RESULT_CASE(VK_ERROR_OUT_OF_POOL_MEMORY_KHR); 141 RESULT_CASE(VK_ERROR_INVALID_SHADER_NV); 142#undef RESULT_CASE 143 default: 144 break; 145 } 146 return (result < 0) ? "VK_ERROR_<Unknown>" : "VK_<Unknown>"; 147} 148 149typedef struct VulkanContext 150{ 151 SDL_Window *window; 152 VkInstance instance; 153 VkDevice device; 154 VkSurfaceKHR surface; 155 VkSwapchainKHR swapchain; 156 VkPhysicalDeviceProperties physicalDeviceProperties; 157 VkPhysicalDeviceFeatures physicalDeviceFeatures; 158 uint32_t graphicsQueueFamilyIndex; 159 uint32_t presentQueueFamilyIndex; 160 VkPhysicalDevice physicalDevice; 161 VkQueue graphicsQueue; 162 VkQueue presentQueue; 163 VkSemaphore imageAvailableSemaphore; 164 VkSemaphore renderingFinishedSemaphore; 165 VkSurfaceCapabilitiesKHR surfaceCapabilities; 166 VkSurfaceFormatKHR *surfaceFormats; 167 uint32_t surfaceFormatsAllocatedCount; 168 uint32_t surfaceFormatsCount; 169 uint32_t swapchainDesiredImageCount; 170 VkSurfaceFormatKHR surfaceFormat; 171 VkExtent2D swapchainSize; 172 VkCommandPool commandPool; 173 uint32_t swapchainImageCount; 174 VkImage *swapchainImages; 175 VkCommandBuffer *commandBuffers; 176 VkFence *fences; 177} VulkanContext; 178 179static SDLTest_CommonState *state; 180static VulkanContext *vulkanContexts = NULL; /* an array of state->num_windows items */ 181static VulkanContext *vulkanContext = NULL; /* for the currently-rendering window */ 182 183static void shutdownVulkan(bool doDestroySwapchain); 184 185/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */ 186static void quit(int rc) 187{ 188 shutdownVulkan(true); 189 SDLTest_CommonQuit(state); 190 /* Let 'main()' return normally */ 191 if (rc != 0) { 192 exit(rc); 193 } 194} 195 196static void loadGlobalFunctions(void) 197{ 198 vkGetInstanceProcAddr = (PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr(); 199 if (!vkGetInstanceProcAddr) { 200 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 201 "SDL_Vulkan_GetVkGetInstanceProcAddr(): %s", 202 SDL_GetError()); 203 quit(2); 204 } 205 206#define VULKAN_DEVICE_FUNCTION(name) 207#define VULKAN_GLOBAL_FUNCTION(name) \ 208 name = (PFN_##name)vkGetInstanceProcAddr(VK_NULL_HANDLE, #name); \ 209 if (!name) { \ 210 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ 211 "vkGetInstanceProcAddr(VK_NULL_HANDLE, \"" #name "\") failed"); \ 212 quit(2); \ 213 } 214#define VULKAN_INSTANCE_FUNCTION(name) 215 VULKAN_FUNCTIONS() 216#undef VULKAN_DEVICE_FUNCTION 217#undef VULKAN_GLOBAL_FUNCTION 218#undef VULKAN_INSTANCE_FUNCTION 219} 220 221static void createInstance(void) 222{ 223 VkApplicationInfo appInfo = { 0 }; 224 VkInstanceCreateInfo instanceCreateInfo = { 0 }; 225 VkResult result; 226 227 appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; 228 appInfo.apiVersion = VK_API_VERSION_1_0; 229 instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; 230 instanceCreateInfo.pApplicationInfo = &appInfo; 231#ifdef __APPLE__ 232 instanceCreateInfo.flags = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; 233#endif 234 235 instanceCreateInfo.ppEnabledExtensionNames = SDL_Vulkan_GetInstanceExtensions(&instanceCreateInfo.enabledExtensionCount); 236 result = vkCreateInstance(&instanceCreateInfo, NULL, &vulkanContext->instance); 237 if (result != VK_SUCCESS) { 238 vulkanContext->instance = VK_NULL_HANDLE; 239 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 240 "vkCreateInstance(): %s", 241 getVulkanResultString(result)); 242 quit(2); 243 } 244} 245 246static void loadInstanceFunctions(void) 247{ 248#define VULKAN_DEVICE_FUNCTION(name) 249#define VULKAN_GLOBAL_FUNCTION(name) 250#define VULKAN_INSTANCE_FUNCTION(name) \ 251 name = (PFN_##name)vkGetInstanceProcAddr(vulkanContext->instance, #name); \ 252 if (!name) { \ 253 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ 254 "vkGetInstanceProcAddr(instance, \"" #name "\") failed"); \ 255 quit(2); \ 256 } 257 VULKAN_FUNCTIONS() 258#undef VULKAN_DEVICE_FUNCTION 259#undef VULKAN_GLOBAL_FUNCTION 260#undef VULKAN_INSTANCE_FUNCTION 261} 262 263static void createSurface(void) 264{ 265 if (!SDL_Vulkan_CreateSurface(vulkanContext->window, vulkanContext->instance, NULL, &vulkanContext->surface)) { 266 vulkanContext->surface = VK_NULL_HANDLE; 267 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_Vulkan_CreateSurface(): %s", SDL_GetError()); 268 quit(2); 269 } 270} 271 272static void findPhysicalDevice(void) 273{ 274 uint32_t physicalDeviceCount = 0; 275 VkPhysicalDevice *physicalDevices; 276 VkQueueFamilyProperties *queueFamiliesProperties = NULL; 277 uint32_t queueFamiliesPropertiesAllocatedSize = 0; 278 VkExtensionProperties *deviceExtensions = NULL; 279 uint32_t deviceExtensionsAllocatedSize = 0; 280 uint32_t physicalDeviceIndex; 281 VkResult result; 282 283 result = vkEnumeratePhysicalDevices(vulkanContext->instance, &physicalDeviceCount, NULL); 284 if (result != VK_SUCCESS) { 285 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 286 "vkEnumeratePhysicalDevices(): %s", 287 getVulkanResultString(result)); 288 quit(2); 289 } 290 if (physicalDeviceCount == 0) { 291 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 292 "vkEnumeratePhysicalDevices(): no physical devices"); 293 quit(2); 294 } 295 physicalDevices = (VkPhysicalDevice *)SDL_malloc(sizeof(VkPhysicalDevice) * physicalDeviceCount); 296 if (!physicalDevices) { 297 quit(2); 298 } 299 result = vkEnumeratePhysicalDevices(vulkanContext->instance, &physicalDeviceCount, physicalDevices); 300 if (result != VK_SUCCESS) { 301 SDL_free(physicalDevices); 302 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 303 "vkEnumeratePhysicalDevices(): %s", 304 getVulkanResultString(result)); 305 quit(2); 306 } 307 vulkanContext->physicalDevice = NULL; 308 for (physicalDeviceIndex = 0; physicalDeviceIndex < physicalDeviceCount; physicalDeviceIndex++) { 309 uint32_t queueFamiliesCount = 0; 310 uint32_t queueFamilyIndex; 311 uint32_t deviceExtensionCount = 0; 312 bool hasSwapchainExtension = false; 313 bool supportsPresent; 314 uint32_t i; 315 316 VkPhysicalDevice physicalDevice = physicalDevices[physicalDeviceIndex]; 317 vkGetPhysicalDeviceProperties(physicalDevice, &vulkanContext->physicalDeviceProperties); 318 if (VK_VERSION_MAJOR(vulkanContext->physicalDeviceProperties.apiVersion) < 1) { 319 continue; 320 } 321 vkGetPhysicalDeviceFeatures(physicalDevice, &vulkanContext->physicalDeviceFeatures); 322 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, NULL); 323 if (queueFamiliesCount == 0) { 324 continue; 325 } 326 if (queueFamiliesPropertiesAllocatedSize < queueFamiliesCount) { 327 SDL_free(queueFamiliesProperties); 328 queueFamiliesPropertiesAllocatedSize = queueFamiliesCount; 329 queueFamiliesProperties = (VkQueueFamilyProperties *)SDL_malloc(sizeof(VkQueueFamilyProperties) * queueFamiliesPropertiesAllocatedSize); 330 if (!queueFamiliesProperties) { 331 SDL_free(physicalDevices); 332 SDL_free(deviceExtensions); 333 quit(2); 334 } 335 } 336 vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamiliesCount, queueFamiliesProperties); 337 vulkanContext->graphicsQueueFamilyIndex = queueFamiliesCount; 338 vulkanContext->presentQueueFamilyIndex = queueFamiliesCount; 339 for (queueFamilyIndex = 0; queueFamilyIndex < queueFamiliesCount; queueFamilyIndex++) { 340 VkBool32 supported = 0; 341 342 if (queueFamiliesProperties[queueFamilyIndex].queueCount == 0) { 343 continue; 344 } 345 346 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 347 vulkanContext->graphicsQueueFamilyIndex = queueFamilyIndex; 348 } 349 350 result = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, queueFamilyIndex, vulkanContext->surface, &supported); 351 if (result != VK_SUCCESS) { 352 SDL_free(physicalDevices); 353 SDL_free(queueFamiliesProperties); 354 SDL_free(deviceExtensions); 355 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 356 "vkGetPhysicalDeviceSurfaceSupportKHR(): %s", 357 getVulkanResultString(result)); 358 quit(2); 359 } 360 if (supported) { 361 /* This check isn't necessary if you are able to check a 362 * VkSurfaceKHR like above, but just as a sanity check we do 363 * this here as part of testing the API. 364 * -flibit 365 */ 366 supportsPresent = SDL_Vulkan_GetPresentationSupport(vulkanContext->instance, physicalDevice, queueFamilyIndex); 367 if (!supportsPresent) { 368 SDL_free(physicalDevices); 369 SDL_free(queueFamiliesProperties); 370 SDL_free(deviceExtensions); 371 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 372 "SDL_Vulkan_GetPresentationSupport(): %s", 373 SDL_GetError()); 374 quit(2); 375 } 376 377 vulkanContext->presentQueueFamilyIndex = queueFamilyIndex; 378 if (queueFamiliesProperties[queueFamilyIndex].queueFlags & VK_QUEUE_GRAPHICS_BIT) { 379 break; // use this queue because it can present and do graphics 380 } 381 } 382 } 383 384 if (vulkanContext->graphicsQueueFamilyIndex == queueFamiliesCount) { // no good queues found 385 continue; 386 } 387 if (vulkanContext->presentQueueFamilyIndex == queueFamiliesCount) { // no good queues found 388 continue; 389 } 390 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, NULL); 391 if (result != VK_SUCCESS) { 392 SDL_free(physicalDevices); 393 SDL_free(queueFamiliesProperties); 394 SDL_free(deviceExtensions); 395 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 396 "vkEnumerateDeviceExtensionProperties(): %s", 397 getVulkanResultString(result)); 398 quit(2); 399 } 400 if (deviceExtensionCount == 0) { 401 continue; 402 } 403 if (deviceExtensionsAllocatedSize < deviceExtensionCount) { 404 SDL_free(deviceExtensions); 405 deviceExtensionsAllocatedSize = deviceExtensionCount; 406 deviceExtensions = SDL_malloc(sizeof(VkExtensionProperties) * deviceExtensionsAllocatedSize); 407 if (!deviceExtensions) { 408 SDL_free(physicalDevices); 409 SDL_free(queueFamiliesProperties); 410 quit(2); 411 } 412 } 413 result = vkEnumerateDeviceExtensionProperties(physicalDevice, NULL, &deviceExtensionCount, deviceExtensions); 414 if (result != VK_SUCCESS) { 415 SDL_free(physicalDevices); 416 SDL_free(queueFamiliesProperties); 417 SDL_free(deviceExtensions); 418 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 419 "vkEnumerateDeviceExtensionProperties(): %s", 420 getVulkanResultString(result)); 421 quit(2); 422 } 423 for (i = 0; i < deviceExtensionCount; i++) { 424 if (SDL_strcmp(deviceExtensions[i].extensionName, VK_KHR_SWAPCHAIN_EXTENSION_NAME) == 0) { 425 hasSwapchainExtension = true; 426 break; 427 } 428 } 429 if (!hasSwapchainExtension) { 430 continue; 431 } 432 vulkanContext->physicalDevice = physicalDevice; 433 break; 434 } 435 SDL_free(physicalDevices); 436 SDL_free(queueFamiliesProperties); 437 SDL_free(deviceExtensions); 438 if (!vulkanContext->physicalDevice) { 439 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Vulkan: no viable physical devices found"); 440 quit(2); 441 } 442} 443 444static void createDevice(void) 445{ 446 VkDeviceQueueCreateInfo deviceQueueCreateInfo[2] = { { 0 }, { 0 } }; 447 static const float queuePriority[] = { 1.0f }; 448 VkDeviceCreateInfo deviceCreateInfo = { 0 }; 449 static const char *const deviceExtensionNames[] = { 450 VK_KHR_SWAPCHAIN_EXTENSION_NAME, 451#ifdef __APPLE__ 452 "VK_KHR_portability_subset" 453#endif 454 }; 455 VkResult result; 456 457 deviceCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; 458 deviceCreateInfo.queueCreateInfoCount = 0; 459 deviceCreateInfo.pQueueCreateInfos = deviceQueueCreateInfo; 460 deviceCreateInfo.pEnabledFeatures = NULL; 461 deviceCreateInfo.enabledExtensionCount = SDL_arraysize(deviceExtensionNames); 462 deviceCreateInfo.ppEnabledExtensionNames = deviceExtensionNames; 463 464 deviceQueueCreateInfo[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 465 deviceQueueCreateInfo[0].queueFamilyIndex = vulkanContext->graphicsQueueFamilyIndex; 466 deviceQueueCreateInfo[0].queueCount = 1; 467 deviceQueueCreateInfo[0].pQueuePriorities = queuePriority; 468 ++deviceCreateInfo.queueCreateInfoCount; 469 470 if (vulkanContext->presentQueueFamilyIndex != vulkanContext->graphicsQueueFamilyIndex) { 471 deviceQueueCreateInfo[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; 472 deviceQueueCreateInfo[1].queueFamilyIndex = vulkanContext->presentQueueFamilyIndex; 473 deviceQueueCreateInfo[1].queueCount = 1; 474 deviceQueueCreateInfo[1].pQueuePriorities = queuePriority; 475 ++deviceCreateInfo.queueCreateInfoCount; 476 } 477 478 result = vkCreateDevice(vulkanContext->physicalDevice, &deviceCreateInfo, NULL, &vulkanContext->device); 479 if (result != VK_SUCCESS) { 480 vulkanContext->device = VK_NULL_HANDLE; 481 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkCreateDevice(): %s", getVulkanResultString(result)); 482 quit(2); 483 } 484} 485 486static void loadDeviceFunctions(void) 487{ 488#define VULKAN_DEVICE_FUNCTION(name) \ 489 name = (PFN_##name)vkGetDeviceProcAddr(vulkanContext->device, #name); \ 490 if (!name) { \ 491 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, \ 492 "vkGetDeviceProcAddr(device, \"" #name "\") failed"); \ 493 quit(2); \ 494 } 495#define VULKAN_GLOBAL_FUNCTION(name) 496#define VULKAN_INSTANCE_FUNCTION(name) 497 VULKAN_FUNCTIONS() 498#undef VULKAN_DEVICE_FUNCTION 499#undef VULKAN_GLOBAL_FUNCTION 500#undef VULKAN_INSTANCE_FUNCTION 501} 502 503#undef VULKAN_FUNCTIONS 504 505static void getQueues(void) 506{ 507 vkGetDeviceQueue(vulkanContext->device, 508 vulkanContext->graphicsQueueFamilyIndex, 509 0, 510 &vulkanContext->graphicsQueue); 511 if (vulkanContext->graphicsQueueFamilyIndex != vulkanContext->presentQueueFamilyIndex) { 512 vkGetDeviceQueue(vulkanContext->device, 513 vulkanContext->presentQueueFamilyIndex, 514 0, 515 &vulkanContext->presentQueue); 516 } else { 517 vulkanContext->presentQueue = vulkanContext->graphicsQueue; 518 } 519} 520 521static void createSemaphore(VkSemaphore *semaphore) 522{ 523 VkResult result; 524 525 VkSemaphoreCreateInfo createInfo = { 0 }; 526 createInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; 527 result = vkCreateSemaphore(vulkanContext->device, &createInfo, NULL, semaphore); 528 if (result != VK_SUCCESS) { 529 *semaphore = VK_NULL_HANDLE; 530 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 531 "vkCreateSemaphore(): %s", 532 getVulkanResultString(result)); 533 quit(2); 534 } 535} 536 537static void createSemaphores(void) 538{ 539 createSemaphore(&vulkanContext->imageAvailableSemaphore); 540 createSemaphore(&vulkanContext->renderingFinishedSemaphore); 541} 542 543static void getSurfaceCaps(void) 544{ 545 VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(vulkanContext->physicalDevice, vulkanContext->surface, &vulkanContext->surfaceCapabilities); 546 if (result != VK_SUCCESS) { 547 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 548 "vkGetPhysicalDeviceSurfaceCapabilitiesKHR(): %s", 549 getVulkanResultString(result)); 550 quit(2); 551 } 552 553 // check surface usage 554 if (!(vulkanContext->surfaceCapabilities.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) { 555 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 556 "Vulkan surface doesn't support VK_IMAGE_USAGE_TRANSFER_DST_BIT"); 557 quit(2); 558 } 559} 560 561static void getSurfaceFormats(void) 562{ 563 VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext->physicalDevice, 564 vulkanContext->surface, 565 &vulkanContext->surfaceFormatsCount, 566 NULL); 567 if (result != VK_SUCCESS) { 568 vulkanContext->surfaceFormatsCount = 0; 569 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 570 "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s", 571 getVulkanResultString(result)); 572 quit(2); 573 } 574 if (vulkanContext->surfaceFormatsCount > vulkanContext->surfaceFormatsAllocatedCount) { 575 vulkanContext->surfaceFormatsAllocatedCount = vulkanContext->surfaceFormatsCount; 576 SDL_free(vulkanContext->surfaceFormats); 577 vulkanContext->surfaceFormats = (VkSurfaceFormatKHR *)SDL_malloc(sizeof(VkSurfaceFormatKHR) * vulkanContext->surfaceFormatsAllocatedCount); 578 if (!vulkanContext->surfaceFormats) { 579 vulkanContext->surfaceFormatsCount = 0; 580 quit(2); 581 } 582 } 583 result = vkGetPhysicalDeviceSurfaceFormatsKHR(vulkanContext->physicalDevice, 584 vulkanContext->surface, 585 &vulkanContext->surfaceFormatsCount, 586 vulkanContext->surfaceFormats); 587 if (result != VK_SUCCESS) { 588 vulkanContext->surfaceFormatsCount = 0; 589 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 590 "vkGetPhysicalDeviceSurfaceFormatsKHR(): %s", 591 getVulkanResultString(result)); 592 quit(2); 593 } 594} 595 596static void getSwapchainImages(void) 597{ 598 VkResult result; 599 600 SDL_free(vulkanContext->swapchainImages); 601 vulkanContext->swapchainImages = NULL; 602 result = vkGetSwapchainImagesKHR(vulkanContext->device, vulkanContext->swapchain, &vulkanContext->swapchainImageCount, NULL); 603 if (result != VK_SUCCESS) { 604 vulkanContext->swapchainImageCount = 0; 605 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 606 "vkGetSwapchainImagesKHR(): %s", 607 getVulkanResultString(result)); 608 quit(2); 609 } 610 vulkanContext->swapchainImages = SDL_malloc(sizeof(VkImage) * vulkanContext->swapchainImageCount); 611 if (!vulkanContext->swapchainImages) { 612 quit(2); 613 } 614 result = vkGetSwapchainImagesKHR(vulkanContext->device, 615 vulkanContext->swapchain, 616 &vulkanContext->swapchainImageCount, 617 vulkanContext->swapchainImages); 618 if (result != VK_SUCCESS) { 619 SDL_free(vulkanContext->swapchainImages); 620 vulkanContext->swapchainImages = NULL; 621 vulkanContext->swapchainImageCount = 0; 622 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 623 "vkGetSwapchainImagesKHR(): %s", 624 getVulkanResultString(result)); 625 quit(2); 626 } 627} 628 629static bool createSwapchain(void) 630{ 631 uint32_t i; 632 int w, h; 633 VkSwapchainCreateInfoKHR createInfo = { 0 }; 634 VkResult result; 635 SDL_WindowFlags flags; 636 637 // pick an image count 638 vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.minImageCount + 1; 639 if ((vulkanContext->swapchainDesiredImageCount > vulkanContext->surfaceCapabilities.maxImageCount) && 640 (vulkanContext->surfaceCapabilities.maxImageCount > 0)) { 641 vulkanContext->swapchainDesiredImageCount = vulkanContext->surfaceCapabilities.maxImageCount; 642 } 643 644 // pick a format 645 if ((vulkanContext->surfaceFormatsCount == 1) && 646 (vulkanContext->surfaceFormats[0].format == VK_FORMAT_UNDEFINED)) { 647 // aren't any preferred formats, so we pick 648 vulkanContext->surfaceFormat.colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR; 649 vulkanContext->surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM; 650 } else { 651 vulkanContext->surfaceFormat = vulkanContext->surfaceFormats[0]; 652 for (i = 0; i < vulkanContext->surfaceFormatsCount; i++) { 653 if (vulkanContext->surfaceFormats[i].format == VK_FORMAT_R8G8B8A8_UNORM) { 654 vulkanContext->surfaceFormat = vulkanContext->surfaceFormats[i]; 655 break; 656 } 657 } 658 } 659 660 // get size 661 SDL_GetWindowSizeInPixels(vulkanContext->window, &w, &h); 662 663 // get flags 664 flags = SDL_GetWindowFlags(vulkanContext->window); 665 666 // Clamp the size to the allowable image extent. 667 // SDL_GetWindowSizeInPixels()'s result it not always in this range (bug #3287) 668 vulkanContext->swapchainSize.width = SDL_clamp((uint32_t)w, 669 vulkanContext->surfaceCapabilities.minImageExtent.width, 670 vulkanContext->surfaceCapabilities.maxImageExtent.width); 671 672 vulkanContext->swapchainSize.height = SDL_clamp((uint32_t)h, 673 vulkanContext->surfaceCapabilities.minImageExtent.height, 674 vulkanContext->surfaceCapabilities.maxImageExtent.height); 675 676 if (w == 0 || h == 0) { 677 return false; 678 } 679 680 getSurfaceCaps(); 681 682 createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; 683 createInfo.surface = vulkanContext->surface; 684 createInfo.minImageCount = vulkanContext->swapchainDesiredImageCount; 685 createInfo.imageFormat = vulkanContext->surfaceFormat.format; 686 createInfo.imageColorSpace = vulkanContext->surfaceFormat.colorSpace; 687 createInfo.imageExtent = vulkanContext->swapchainSize; 688 createInfo.imageArrayLayers = 1; 689 createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; 690 createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; 691 createInfo.preTransform = vulkanContext->surfaceCapabilities.currentTransform; 692 if (flags & SDL_WINDOW_TRANSPARENT) { 693 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR; 694 } else { 695 createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; 696 } 697 createInfo.presentMode = VK_PRESENT_MODE_FIFO_KHR; 698 createInfo.clipped = VK_TRUE; 699 createInfo.oldSwapchain = vulkanContext->swapchain; 700 result = vkCreateSwapchainKHR(vulkanContext->device, &createInfo, NULL, &vulkanContext->swapchain); 701 702 if (createInfo.oldSwapchain) { 703 vkDestroySwapchainKHR(vulkanContext->device, createInfo.oldSwapchain, NULL); 704 } 705 706 if (result != VK_SUCCESS) { 707 vulkanContext->swapchain = VK_NULL_HANDLE; 708 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 709 "vkCreateSwapchainKHR(): %s", 710 getVulkanResultString(result)); 711 quit(2); 712 } 713 714 getSwapchainImages(); 715 return true; 716} 717 718static void destroySwapchain(void) 719{ 720 if (vulkanContext->swapchain) { 721 vkDestroySwapchainKHR(vulkanContext->device, vulkanContext->swapchain, NULL); 722 vulkanContext->swapchain = VK_NULL_HANDLE; 723 } 724 SDL_free(vulkanContext->swapchainImages); 725 vulkanContext->swapchainImages = NULL; 726} 727 728static void destroyCommandBuffers(void) 729{ 730 if (vulkanContext->commandBuffers) { 731 vkFreeCommandBuffers(vulkanContext->device, 732 vulkanContext->commandPool, 733 vulkanContext->swapchainImageCount, 734 vulkanContext->commandBuffers); 735 SDL_free(vulkanContext->commandBuffers); 736 vulkanContext->commandBuffers = NULL; 737 } 738} 739 740static void destroyCommandPool(void) 741{ 742 if (vulkanContext->commandPool) { 743 vkDestroyCommandPool(vulkanContext->device, vulkanContext->commandPool, NULL); 744 } 745 vulkanContext->commandPool = VK_NULL_HANDLE; 746} 747 748static void createCommandPool(void) 749{ 750 VkResult result; 751 VkCommandPoolCreateInfo createInfo = { 0 }; 752 createInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; 753 createInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT; 754 createInfo.queueFamilyIndex = vulkanContext->graphicsQueueFamilyIndex; 755 result = vkCreateCommandPool(vulkanContext->device, &createInfo, NULL, &vulkanContext->commandPool); 756 if (result != VK_SUCCESS) { 757 vulkanContext->commandPool = VK_NULL_HANDLE; 758 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 759 "vkCreateCommandPool(): %s", 760 getVulkanResultString(result)); 761 quit(2); 762 } 763} 764 765static void createCommandBuffers(void) 766{ 767 VkResult result; 768 VkCommandBufferAllocateInfo allocateInfo = { 0 }; 769 allocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; 770 allocateInfo.commandPool = vulkanContext->commandPool; 771 allocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; 772 allocateInfo.commandBufferCount = vulkanContext->swapchainImageCount; 773 vulkanContext->commandBuffers = (VkCommandBuffer *)SDL_malloc(sizeof(VkCommandBuffer) * vulkanContext->swapchainImageCount); 774 result = vkAllocateCommandBuffers(vulkanContext->device, &allocateInfo, vulkanContext->commandBuffers); 775 if (result != VK_SUCCESS) { 776 SDL_free(vulkanContext->commandBuffers); 777 vulkanContext->commandBuffers = NULL; 778 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 779 "vkAllocateCommandBuffers(): %s", 780 getVulkanResultString(result)); 781 quit(2); 782 } 783} 784 785static void createFences(void) 786{ 787 uint32_t i; 788 789 vulkanContext->fences = SDL_malloc(sizeof(VkFence) * vulkanContext->swapchainImageCount); 790 if (!vulkanContext->fences) { 791 quit(2); 792 } 793 for (i = 0; i < vulkanContext->swapchainImageCount; i++) { 794 VkResult result; 795 VkFenceCreateInfo createInfo = { 0 }; 796 createInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; 797 createInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; 798 result = vkCreateFence(vulkanContext->device, &createInfo, NULL, &vulkanContext->fences[i]); 799 if (result != VK_SUCCESS) { 800 for (; i > 0; i--) { 801 vkDestroyFence(vulkanContext->device, vulkanContext->fences[i - 1], NULL); 802 } 803 SDL_free(vulkanContext->fences); 804 vulkanContext->fences = NULL; 805 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 806 "vkCreateFence(): %s", 807 getVulkanResultString(result)); 808 quit(2); 809 } 810 } 811} 812 813static void destroyFences(void) 814{ 815 uint32_t i; 816 817 if (!vulkanContext->fences) { 818 return; 819 } 820 821 for (i = 0; i < vulkanContext->swapchainImageCount; i++) { 822 vkDestroyFence(vulkanContext->device, vulkanContext->fences[i], NULL); 823 } 824 SDL_free(vulkanContext->fences); 825 vulkanContext->fences = NULL; 826} 827 828static void recordPipelineImageBarrier(VkCommandBuffer commandBuffer, 829 VkAccessFlags sourceAccessMask, 830 VkAccessFlags destAccessMask, 831 VkImageLayout sourceLayout, 832 VkImageLayout destLayout, 833 VkImage image) 834{ 835 VkImageMemoryBarrier barrier = { 0 }; 836 barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 837 barrier.srcAccessMask = sourceAccessMask; 838 barrier.dstAccessMask = destAccessMask; 839 barrier.oldLayout = sourceLayout; 840 barrier.newLayout = destLayout; 841 barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 842 barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 843 barrier.image = image; 844 barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 845 barrier.subresourceRange.baseMipLevel = 0; 846 barrier.subresourceRange.levelCount = 1; 847 barrier.subresourceRange.baseArrayLayer = 0; 848 barrier.subresourceRange.layerCount = 1; 849 vkCmdPipelineBarrier(commandBuffer, 850 VK_PIPELINE_STAGE_TRANSFER_BIT, 851 VK_PIPELINE_STAGE_TRANSFER_BIT, 852 0, 853 0, 854 NULL, 855 0, 856 NULL, 857 1, 858 &barrier); 859} 860 861static void rerecordCommandBuffer(uint32_t frameIndex, const VkClearColorValue *clearColor) 862{ 863 VkCommandBuffer commandBuffer = vulkanContext->commandBuffers[frameIndex]; 864 VkImage image = vulkanContext->swapchainImages[frameIndex]; 865 VkCommandBufferBeginInfo beginInfo = { 0 }; 866 VkImageSubresourceRange clearRange = { 0 }; 867 868 VkResult result = vkResetCommandBuffer(commandBuffer, 0); 869 if (result != VK_SUCCESS) { 870 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 871 "vkResetCommandBuffer(): %s", 872 getVulkanResultString(result)); 873 quit(2); 874 } 875 beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 876 beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; 877 result = vkBeginCommandBuffer(commandBuffer, &beginInfo); 878 if (result != VK_SUCCESS) { 879 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 880 "vkBeginCommandBuffer(): %s", 881 getVulkanResultString(result)); 882 quit(2); 883 } 884 recordPipelineImageBarrier(commandBuffer, 885 0, 886 VK_ACCESS_TRANSFER_WRITE_BIT, 887 VK_IMAGE_LAYOUT_UNDEFINED, 888 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 889 image); 890 clearRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 891 clearRange.baseMipLevel = 0; 892 clearRange.levelCount = 1; 893 clearRange.baseArrayLayer = 0; 894 clearRange.layerCount = 1; 895 vkCmdClearColorImage(commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, clearColor, 1, &clearRange); 896 recordPipelineImageBarrier(commandBuffer, 897 VK_ACCESS_TRANSFER_WRITE_BIT, 898 VK_ACCESS_MEMORY_READ_BIT, 899 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 900 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, 901 image); 902 result = vkEndCommandBuffer(commandBuffer); 903 if (result != VK_SUCCESS) { 904 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 905 "vkEndCommandBuffer(): %s", 906 getVulkanResultString(result)); 907 quit(2); 908 } 909} 910 911static void destroySwapchainAndSwapchainSpecificStuff(bool doDestroySwapchain) 912{ 913 if (vkDeviceWaitIdle != NULL) { 914 vkDeviceWaitIdle(vulkanContext->device); 915 } 916 destroyFences(); 917 destroyCommandBuffers(); 918 destroyCommandPool(); 919 if (doDestroySwapchain) { 920 destroySwapchain(); 921 } 922} 923 924static bool createNewSwapchainAndSwapchainSpecificStuff(void) 925{ 926 destroySwapchainAndSwapchainSpecificStuff(false); 927 getSurfaceCaps(); 928 getSurfaceFormats(); 929 if (!createSwapchain()) { 930 return false; 931 } 932 createCommandPool(); 933 createCommandBuffers(); 934 createFences(); 935 return true; 936} 937 938static void initVulkan(void) 939{ 940 int i; 941 942 SDL_Vulkan_LoadLibrary(NULL); 943 944 vulkanContexts = (VulkanContext *)SDL_calloc(state->num_windows, sizeof(VulkanContext)); 945 if (!vulkanContexts) { 946 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!"); 947 quit(2); 948 } 949 950 for (i = 0; i < state->num_windows; ++i) { 951 vulkanContext = &vulkanContexts[i]; 952 vulkanContext->window = state->windows[i]; 953 loadGlobalFunctions(); 954 createInstance(); 955 loadInstanceFunctions(); 956 createSurface(); 957 findPhysicalDevice(); 958 createDevice(); 959 loadDeviceFunctions(); 960 getQueues(); 961 createSemaphores(); 962 createNewSwapchainAndSwapchainSpecificStuff(); 963 } 964} 965 966static void shutdownVulkan(bool doDestroySwapchain) 967{ 968 if (vulkanContexts) { 969 int i; 970 for (i = 0; i < state->num_windows; ++i) { 971 vulkanContext = &vulkanContexts[i]; 972 if (vulkanContext->device && vkDeviceWaitIdle) { 973 vkDeviceWaitIdle(vulkanContext->device); 974 } 975 976 destroySwapchainAndSwapchainSpecificStuff(doDestroySwapchain); 977 978 if (vulkanContext->imageAvailableSemaphore && vkDestroySemaphore) { 979 vkDestroySemaphore(vulkanContext->device, vulkanContext->imageAvailableSemaphore, NULL); 980 } 981 982 if (vulkanContext->renderingFinishedSemaphore && vkDestroySemaphore) { 983 vkDestroySemaphore(vulkanContext->device, vulkanContext->renderingFinishedSemaphore, NULL); 984 } 985 986 if (vulkanContext->device && vkDestroyDevice) { 987 vkDestroyDevice(vulkanContext->device, NULL); 988 } 989 990 if (vulkanContext->surface && vkDestroySurfaceKHR) { 991 vkDestroySurfaceKHR(vulkanContext->instance, vulkanContext->surface, NULL); 992 } 993 994 if (vulkanContext->instance && vkDestroyInstance) { 995 vkDestroyInstance(vulkanContext->instance, NULL); 996 } 997 998 SDL_free(vulkanContext->surfaceFormats); 999 } 1000 SDL_free(vulkanContexts); 1001 vulkanContexts = NULL; 1002 } 1003 1004 SDL_Vulkan_UnloadLibrary(); 1005} 1006 1007static bool render(void) 1008{ 1009 uint32_t frameIndex; 1010 VkResult rc; 1011 double currentTime; 1012 VkClearColorValue clearColor = { { 0 } }; 1013 VkPipelineStageFlags waitDestStageMask = VK_PIPELINE_STAGE_TRANSFER_BIT; 1014 VkSubmitInfo submitInfo = { 0 }; 1015 VkPresentInfoKHR presentInfo = { 0 }; 1016 int w, h; 1017 1018 if (!vulkanContext->swapchain) { 1019 bool result = createNewSwapchainAndSwapchainSpecificStuff(); 1020 if (!result) { 1021 SDL_Delay(100); 1022 } 1023 return result; 1024 } 1025 rc = vkAcquireNextImageKHR(vulkanContext->device, 1026 vulkanContext->swapchain, 1027 UINT64_MAX, 1028 vulkanContext->imageAvailableSemaphore, 1029 VK_NULL_HANDLE, 1030 &frameIndex); 1031 if (rc == VK_ERROR_OUT_OF_DATE_KHR) { 1032 return createNewSwapchainAndSwapchainSpecificStuff(); 1033 } 1034 1035 if ((rc != VK_SUBOPTIMAL_KHR) && (rc != VK_SUCCESS)) { 1036 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 1037 "vkAcquireNextImageKHR(): %s", 1038 getVulkanResultString(rc)); 1039 quit(2); 1040 } 1041 rc = vkWaitForFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex], VK_FALSE, UINT64_MAX); 1042 if (rc != VK_SUCCESS) { 1043 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkWaitForFences(): %s", getVulkanResultString(rc)); 1044 quit(2); 1045 } 1046 rc = vkResetFences(vulkanContext->device, 1, &vulkanContext->fences[frameIndex]); 1047 if (rc != VK_SUCCESS) { 1048 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkResetFences(): %s", getVulkanResultString(rc)); 1049 quit(2); 1050 } 1051 currentTime = (double)SDL_GetPerformanceCounter() / SDL_GetPerformanceFrequency(); 1052 clearColor.float32[0] = (float)(0.5 + 0.5 * SDL_sin(currentTime)); 1053 clearColor.float32[1] = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 2 / 3)); 1054 clearColor.float32[2] = (float)(0.5 + 0.5 * SDL_sin(currentTime + SDL_PI_D * 4 / 3)); 1055 clearColor.float32[3] = 0.5; // for SDL_WINDOW_TRANSPARENT, ignored with VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR 1056 rerecordCommandBuffer(frameIndex, &clearColor); 1057 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 1058 submitInfo.waitSemaphoreCount = 1; 1059 submitInfo.pWaitSemaphores = &vulkanContext->imageAvailableSemaphore; 1060 submitInfo.pWaitDstStageMask = &waitDestStageMask; 1061 submitInfo.commandBufferCount = 1; 1062 submitInfo.pCommandBuffers = &vulkanContext->commandBuffers[frameIndex]; 1063 submitInfo.signalSemaphoreCount = 1; 1064 submitInfo.pSignalSemaphores = &vulkanContext->renderingFinishedSemaphore; 1065 rc = vkQueueSubmit(vulkanContext->graphicsQueue, 1, &submitInfo, vulkanContext->fences[frameIndex]); 1066 1067 if (rc != VK_SUCCESS) { 1068 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "vkQueueSubmit(): %s", getVulkanResultString(rc)); 1069 quit(2); 1070 } 1071 presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; 1072 presentInfo.waitSemaphoreCount = 1; 1073 presentInfo.pWaitSemaphores = &vulkanContext->renderingFinishedSemaphore; 1074 presentInfo.swapchainCount = 1; 1075 presentInfo.pSwapchains = &vulkanContext->swapchain; 1076 presentInfo.pImageIndices = &frameIndex; 1077 rc = vkQueuePresentKHR(vulkanContext->presentQueue, &presentInfo); 1078 if ((rc == VK_ERROR_OUT_OF_DATE_KHR) || (rc == VK_SUBOPTIMAL_KHR)) { 1079 return createNewSwapchainAndSwapchainSpecificStuff(); 1080 } 1081 1082 if (rc != VK_SUCCESS) { 1083 SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, 1084 "vkQueuePresentKHR(): %s", 1085 getVulkanResultString(rc)); 1086 quit(2); 1087 } 1088 SDL_GetWindowSizeInPixels(vulkanContext->window, &w, &h); 1089 if (w != (int)vulkanContext->swapchainSize.width || h != (int)vulkanContext->swapchainSize.height) { 1090 return createNewSwapchainAndSwapchainSpecificStuff(); 1091 } 1092 return true; 1093} 1094 1095int main(int argc, char **argv) 1096{ 1097 int done; 1098 const SDL_DisplayMode *mode; 1099 SDL_Event event; 1100 Uint64 then, now; 1101 Uint32 frames; 1102 int dw, dh; 1103 1104 /* Initialize test framework */ 1105 state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO); 1106 if (!state) { 1107 return 1; 1108 } 1109 1110 /* Set Vulkan parameters */ 1111 state->window_flags |= SDL_WINDOW_VULKAN; 1112 state->skip_renderer = 1; 1113 1114 if (!SDLTest_CommonDefaultArgs(state, argc, argv) || !SDLTest_CommonInit(state)) { 1115 SDLTest_CommonQuit(state); 1116 return 1; 1117 } 1118 1119 mode = SDL_GetCurrentDisplayMode(SDL_GetPrimaryDisplay()); 1120 if (mode) { 1121 SDL_Log("Screen BPP : %d", SDL_BITSPERPIXEL(mode->format)); 1122 } 1123 SDL_GetWindowSize(state->windows[0], &dw, &dh); 1124 SDL_Log("Window Size : %d,%d", dw, dh); 1125 SDL_GetWindowSizeInPixels(state->windows[0], &dw, &dh); 1126 SDL_Log("Draw Size : %d,%d", dw, dh); 1127 SDL_Log("%s", ""); 1128 1129 initVulkan(); 1130 1131 /* Main render loop */ 1132 frames = 0; 1133 then = SDL_GetTicks(); 1134 done = 0; 1135 while (!done) { 1136 /* Check for events */ 1137 frames++; 1138 while (SDL_PollEvent(&event)) { 1139 /* Need to destroy the swapchain before the window created 1140 * by SDL. 1141 */ 1142 if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) { 1143 destroySwapchainAndSwapchainSpecificStuff(true); 1144 } 1145 SDLTest_CommonEvent(state, &event, &done); 1146 } 1147 1148 if (!done) { 1149 int i; 1150 for (i = 0; i < state->num_windows; ++i) { 1151 if (state->windows[i]) { 1152 vulkanContext = &vulkanContexts[i]; 1153 render(); 1154 } 1155 } 1156 } 1157 } 1158 1159 /* Print out some timing information */ 1160 now = SDL_GetTicks(); 1161 if (now > then) { 1162 SDL_Log("%2.2f frames per second", ((double)frames * 1000) / (now - then)); 1163 } 1164 1165 shutdownVulkan(true); 1166 SDLTest_CommonQuit(state); 1167 return 0; 1168} 1169 1170#endif 1171[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.