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