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