#ifndef _VKSETUP_H #define _VKSETUP_H /* Start header file */ /** vulkan setup and basic vector math Single header file with included implementation in the spirit of stb_* ASSUMPTIONS: ~~~~~~~~~~~~ - Using SDL2 for the window - Using cglm for maths - Using shaderc for compiling glsl - Using vulkan(!) This is not meant to be a generic werapper around vulkan. It is actively paired and chaned by the currently in development application, whatever that might be. Think of it as the vulkan setup configuratior and helper. USAGE: ~~~~~~ Do this: #define VKSETUP_IMPLEMENTATION before you include this file in *one* C or C++ file to create the implementation. // i.e. it should look like this: #include ... #include ... #include ... #define VKSETUP_IMPLEMENTATION #include "vksetup.h" */ #define SDL_MAIN_HANDLED #define VK_USE_PLATFORM_XCB_KHR #include #include #include #include #include // for string_VkResult #include #include "../lib/cglm/include/cglm/cglm.h" #define VK_ARRAY_LEN(arr) sizeof((arr))/sizeof((arr)[0]) #ifdef __clang__ #define __FILENAME__ __FILE_NAME__ #else #define __FILENAME__ __FILE__ #endif #define VK_CHECK(x) \ do { \ VkResult err = x; \ if (err < 0) { \ fprintf(stderr, "src/%s:%d:0: vulkan error: %s \n", \ __FILENAME__, __LINE__, string_VkResult(err)); \ abort(); \ } \ } while (0) typedef enum { VK_INFO = 0, VK_WARN, VK_ERROR, } log_type; static inline void _vk_log(log_type t, const char * f, ...) { #ifdef VKDEBUG va_list args; va_start(args, f); switch (t) { case VK_INFO: printf("INFO: "); vprintf(f, args); break; case VK_WARN: fprintf(stderr, "WARN: "); vfprintf(stderr, f, args); break; case VK_ERROR: fprintf(stderr, "ERROR: "); vfprintf(stderr, f, args); break; } va_end(args); #else return; #endif } #ifdef VKDEBUG #define vk_log(t, ...) do { \ fprintf(t == VK_INFO ? stdout : stderr, "src/%s:%d:0: ", \ __FILENAME__, __LINE__); \ _vk_log(t, __VA_ARGS__); \ } while(0) #else #define vk_log(t, ...) #endif /**********/ /* config */ /**********/ const char *const validation_layers[] = { "VK_LAYER_KHRONOS_validation" }; const uint32_t validation_layer_count = VK_ARRAY_LEN(validation_layers); const char *const device_extensions[] = { VK_KHR_SWAPCHAIN_EXTENSION_NAME, }; const uint32_t deviceExtensionCount = VK_ARRAY_LEN(device_extensions); #ifdef VKDEBUG const bool enableValidationLayers = true; #else const bool enableValidationLayers = false; #endif #ifdef __cplusplus extern "C" { #endif #ifndef VKSDEF #ifdef VKS_STATIC #define VKSDEF static #else #define VKSDEF extern #endif #endif // TODO Create structs for vulkan data typedef struct {void * a;} vks_vulkan; typedef struct {void * a;} vks_image; typedef struct {void * a;} vks_; /** Create a VkInstance */ VKSDEF VkInstance vks_create_instance(bool validation_layers_toggle, const char * const validation_layers[], uint32_t validation_layer_count, SDL_Window *window); /* VKSDEF void vulkan_create_surface(); */ /* VKSDEF void vulkan_pick_physical_device(); */ /* VKSDEF void vulkan_create_logical_device(); */ /* VKSDEF void vulkan_create_swap_chain(); */ /* VKSDEF void vulkan_create_image_views(); */ /* VKSDEF void vulkan_create_descriptor_set_layout(); */ /* VKSDEF void vulkan_create_graphics_pipeline(); */ /* VKSDEF void vulkan_create_command_pool(); */ /* VKSDEF void vulkan_create_depth_resources(); */ /* VKSDEF void vulkan_create_texture_image(); */ /* VKSDEF void vulkan_create_texture_image_view(); */ /* VKSDEF void vulkan_create_texture_sampler(); */ /* VKSDEF void vulkan_create_vertex_buffer(); */ /* VKSDEF void vulkan_create_index_buffer(); */ /* VKSDEF void vulkan_create_uniform_buffers(); */ /* VKSDEF void vulkan_create_descriptor_pool(); */ /* VKSDEF void vulkan_create_descriptor_sets(); */ /* VKSDEF void vulkan_create_command_buffer(); */ /* VKSDEF void vulkan_create_sync_objects(); */ #ifdef __cplusplus } #endif /* End header file */ #endif /* _VKSETUP_H */ #ifdef VKSETUP_IMPLEMENTATION #include #include #include /* Vks helpers */ bool vks_check_validation_layer_support(const char * const validation_layers[], uint32_t validation_layer_count) { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, NULL); VkLayerProperties availableLayers[layerCount]; vkEnumerateInstanceLayerProperties(&layerCount, availableLayers); bool layerFound = false; for (uint32_t i = 0; i < validation_layer_count; i++) { for (uint32_t j = 0; j < layerCount; j++) { if (strcmp(validation_layers[i], availableLayers[j].layerName) == 0) { layerFound = true; break; } } } return layerFound; } /* Vks API implementation */ VKSDEF VkInstance vks_create_instance(bool validation_layers_toggle, const char * const validation_layers[], uint32_t validation_layer_count, SDL_Window *window) { if (validation_layers_toggle && !vks_check_validation_layer_support(validation_layers, validation_layer_count)) { vk_log(VK_ERROR, "validation layers requested, but not available!\n"); abort(); } uint32_t instanceVersion; VkResult result = vkEnumerateInstanceVersion(&instanceVersion); if (result == VK_SUCCESS) { if (instanceVersion < VK_MAKE_API_VERSION(0, 1, 3, 0)) { vk_log(VK_ERROR, "Vulkan version 1.3 or greater required!\n"); exit(1); } vk_log(VK_INFO, "Vulkan version found (%d) %d.%d.%d\n", VK_API_VERSION_VARIANT(instanceVersion), VK_API_VERSION_MAJOR(instanceVersion), VK_API_VERSION_MINOR(instanceVersion), VK_API_VERSION_PATCH(instanceVersion)); } else { vk_log(VK_ERROR, "Failed to retrieve vulkan version, is vulkan supported in this system?\n"); exit(1); } // Load Vulkan and create instance VkApplicationInfo appInfo = { .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .pApplicationName = "Vulkan Application", .applicationVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), .pEngineName = NULL, .engineVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), .apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0), }; uint32_t sdlExtensionCount = 0; if (SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, NULL) == SDL_FALSE) { vk_log(VK_ERROR, "SDL_Vulkan_GetInstanceExtensions failed: %s\n", SDL_GetError()); abort(); } // make space for debug extenetion if (validation_layers_toggle) { sdlExtensionCount++; } const char* sdlExtensions[sdlExtensionCount]; if (SDL_Vulkan_GetInstanceExtensions(window, &sdlExtensionCount, sdlExtensions) == SDL_FALSE) { vk_log(VK_ERROR, "SDL_Vulkan_GetInstanceExtensions failed: %s\n", SDL_GetError()); abort(); } // add debug extenetion if (validation_layers_toggle) { sdlExtensions[sdlExtensionCount] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; } vk_log(VK_INFO, "The sdl extensions:\n"); for (uint32_t i = 0; i < sdlExtensionCount; i++) { vk_log(VK_INFO, "\t%s\n", sdlExtensions[i]); } VkInstanceCreateInfo createInfo = { .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, .pApplicationInfo = &appInfo, .enabledExtensionCount = sdlExtensionCount, .ppEnabledExtensionNames = sdlExtensions, .enabledLayerCount = 0, }; if (validation_layers_toggle) { createInfo.enabledLayerCount = validation_layer_count; createInfo.ppEnabledLayerNames = validation_layers; } VkInstance instance; if (vkCreateInstance(&createInfo, NULL, &instance) != VK_SUCCESS) { vk_log(VK_ERROR, "Can't start vulkan instance\n"); } vk_log(VK_INFO, "Vulkan instance created\n"); return instance; } #endif /* VKSETUP_IMPLEMENTATION */