diff --git a/.gitignore b/.gitignore index 33cc21d..41b2f02 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ *.o *.swp *.swx +sandbox/test diff --git a/kvf.h b/kvf.h index c41f01d..bd5fe87 100644 --- a/kvf.h +++ b/kvf.h @@ -39,8 +39,7 @@ * If you are using Volk or any other meta loader you must define KVF_IMPL_VK_NO_PROTOTYPES * before including this file to avoid conflicts with Vulkan prototypes. * - * You can also #define KVF_ENABLE_VALIDATION_LAYERS to enable validation layers when - * compiling in release (they are always enabled in debug). + * You can also #define KVF_ENABLE_VALIDATION_LAYERS to enable validation layers. */ #ifndef KBZ_8_VULKAN_FRAMEWORK_H @@ -52,11 +51,17 @@ #include +/* ============================================= Prototypes ============================================= */ + #ifdef __cplusplus extern "C" { #endif -/* ============================================= Prototypes ============================================= */ +typedef enum +{ + KVF_GRAPHICS_QUEUE, + KVF_PRESENT_QUEUE +} KvfQueueType; VkInstance kvfCreateInstance(const char** extensionsEnabled, uint32_t extensionsCount); void kvfDestroyInstance(VkInstance instance); @@ -66,17 +71,24 @@ VkPhysicalDevice kvfPickGoodDefaultPhysicalDevice(VkInstance instance, VkSurface VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR surface, const char** deviceExtensions, uint32_t deviceExtensionsCount); void kvfFindQueueFamilies(VkPhysicalDevice physical, VkSurfaceKHR surface); +VkQueue kvfGetDeviceQueue(VkDevice device, KvfQueueType queue); VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical); VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uint32_t extensions_count); void kvfDestroyDevice(VkDevice device); -/* ========================================== Implementation =========================================== */ +VkFence kvfCreateFence(VkDevice device); +void kvfDestroyFence(VkDevice device, VkFence fence); + +VkSemaphore kvfCreateSemaphore(VkDevice device); +void kvfDestroySemaphore(VkDevice device, VkSemaphore semaphore); #ifdef __cplusplus } #endif +/* ========================================== Implementation =========================================== */ + #ifdef KVF_IMPLEMENTATION #ifndef KVF_MALLOC @@ -101,6 +113,10 @@ void kvfDestroyDevice(VkDevice device); int32_t __kvf_graphics_queue_family = -1; int32_t __kvf_present_queue_family = -1; +#ifdef KVF_ENABLE_VALIDATION_LAYERS + VkDebugUtilsMessengerEXT __kvf_debug_messenger; +#endif + const char* verbaliseResultVk(VkResult result) { switch(result) @@ -139,6 +155,40 @@ void checkVk(VkResult result) printf("KVF Vulkan error : %s\n", verbaliseResultVk(result)); } +#ifdef KVF_ENABLE_VALIDATION_LAYERS + bool __kvfCheckValidationLayerSupport() + { + uint32_t layer_count; + vkEnumerateInstanceLayerProperties(&layer_count, NULL); + VkLayerProperties* available_layers = KVF_MALLOC(sizeof(VkLayerProperties) * layer_count); + vkEnumerateInstanceLayerProperties(&layer_count, available_layers); + + for(int i = 0; i < layer_count; i++) + { + if(strcmp(available_layers[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) + return true; + } + return false; + } + + VKAPI_ATTR VkBool32 VKAPI_CALL __kvfDebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageType, const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, void* pUserData) + { + if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT) + printf("\nKVF Vulkan validation layer error : %s\n", pCallbackData->pMessage); + else if(messageSeverity == VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) + printf("\nKVF Vulkan validation layer warning : %s\n", pCallbackData->pMessage); + return VK_FALSE; + } + + void __kvfPopulateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT* createInfo) + { + createInfo->sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + createInfo->messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + createInfo->messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT; + createInfo->pfnUserCallback = __kvfDebugCallback; + } +#endif // KVF_ENABLE_VALIDATION_LAYERS + VkInstance kvfCreateInstance(const char** extensionsEnabled, uint32_t extensionsCount) { VkInstance vk_instance = VK_NULL_HANDLE; @@ -146,10 +196,36 @@ VkInstance kvfCreateInstance(const char** extensionsEnabled, uint32_t extensions VkInstanceCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = NULL; + createInfo.flags = 0; createInfo.enabledExtensionCount = extensionsCount; createInfo.ppEnabledExtensionNames = extensionsEnabled; + createInfo.enabledLayerCount = 0; + createInfo.ppEnabledLayerNames = NULL; + createInfo.pNext = NULL; + +#ifdef KVF_ENABLE_VALIDATION_LAYERS + const char** new_extension_set = NULL; + if(__kvfCheckValidationLayerSupport()) + { + const char* layers[] = { "VK_LAYER_KHRONOS_validation" }; + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = { 0 }; + __kvfPopulateDebugMessengerCreateInfo(&debugCreateInfo); + new_extension_set = KVF_MALLOC(sizeof(char*) * (extensionsCount + 1)); + memcpy(new_extension_set, extensionsEnabled, sizeof(char*) * extensionsCount); + new_extension_set[extensionsCount] = VK_EXT_DEBUG_UTILS_EXTENSION_NAME; + + createInfo.enabledExtensionCount = extensionsCount + 1; + createInfo.ppEnabledExtensionNames = new_extension_set; + createInfo.enabledLayerCount = 1; + createInfo.ppEnabledLayerNames = layers; + createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*)&debugCreateInfo; + } +#endif checkVk(vkCreateInstance(&createInfo, NULL, &vk_instance)); +#ifdef KVF_ENABLE_VALIDATION_LAYERS + KVF_FREE(new_extension_set); +#endif return vk_instance; } @@ -157,14 +233,19 @@ void kvfDestroyInstance(VkInstance instance) { if(instance == VK_NULL_HANDLE) return; - checkVk(vkDestroyInstance(instance, NULL)); +#ifdef KVF_ENABLE_VALIDATION_LAYERS + PFN_vkDestroyDebugUtilsMessengerEXT func = (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"); + if(func) + func(instance, __kvf_debug_messenger, NULL); +#endif + vkDestroyInstance(instance, NULL); } VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance) { uint32_t device_count; - vkphysicaldevice* devices = NULL; - vkphysicaldevice chosen_one = VK_NULL_HANDLE; + VkPhysicalDevice* devices = NULL; + VkPhysicalDevice chosen_one = VK_NULL_HANDLE; KVF_ASSERT(instance != VK_NULL_HANDLE); @@ -178,17 +259,20 @@ VkPhysicalDevice kvfPickFirstPhysicalDevice(VkInstance instance) void kvfFindQueueFamilies(VkPhysicalDevice physical, VkSurfaceKHR surface) { - if(__kvf_graphics_queue_family == -1 || __kvf_present_queue_family == -1) + if(__kvf_graphics_queue_family != -1 && __kvf_present_queue_family != -1) return; uint32_t queue_family_count; - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, nullptr); + vkGetPhysicalDeviceQueueFamilyProperties(physical, &queue_family_count, NULL); VkQueueFamilyProperties* queue_families = KVF_MALLOC(sizeof(VkQueueFamilyProperties) * queue_family_count); - vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_family_count, queue_families); + vkGetPhysicalDeviceQueueFamilyProperties(physical, &queue_family_count, queue_families); for(int i = 0; i < queue_family_count; i++) { - if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) + if(queue_families[i].queueFlags & VK_QUEUE_GRAPHICS_BIT && __kvf_graphics_queue_family == -1) + { __kvf_graphics_queue_family = i; + continue; + } VkBool32 present_support = false; vkGetPhysicalDeviceSurfaceSupportKHR(physical, i, surface, &present_support); if(present_support) @@ -216,8 +300,8 @@ VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR sur KVF_ASSERT(surface != VK_NULL_HANDLE); vkEnumeratePhysicalDevices(instance, &device_count, NULL); - devices = KVF_MALLOC(sizeof(VkPhysicaDevice) * device_count + 1); - vkEnumeratePhysicalDvices(instance, &device_count, devices); + devices = KVF_MALLOC(sizeof(VkPhysicalDevice) * device_count + 1); + vkEnumeratePhysicalDevices(instance, &device_count, devices); for(int i = 0; i < device_count; i++) { @@ -228,12 +312,12 @@ VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR sur vkEnumerateDeviceExtensionProperties(devices[i], NULL, &extension_count, props); bool are_there_required_device_extensions = true; - for(int j = 0; j < extensions_count; j++) + for(int j = 0; j < deviceExtensionsCount; j++) { bool is_there_extension = false; - for(int k = 0; k < deviceExtensionsCount; k++) + for(int k = 0; k < extension_count; k++) { - if(strcmp(deviceExtensions[k], props[j].extensionName) == 0) + if(strcmp(deviceExtensions[j], props[k].extensionName) == 0) { is_there_extension = true; break; @@ -262,11 +346,11 @@ VkPhysicalDevice kvfPickGoodPhysicalDevice(VkInstance instance, VkSurfaceKHR sur // If we get there, the device is good chosen_one = devices[i]; - break; + KVF_FREE(devices); + return chosen_one; } - KVF_FREE(devices); - return chosen_one; + return VK_NULL_HANDLE; } VkDevice kvfCreateDefaultDevice(VkPhysicalDevice physical) @@ -287,21 +371,28 @@ VkDevice kvfCreateDevice(VkPhysicalDevice physical, const char** extensions, uin queue_create_info[0].queueFamilyIndex = __kvf_graphics_queue_family; queue_create_info[0].queueCount = 1; queue_create_info[0].pQueuePriorities = &queue_priority; + queue_create_info[0].flags = 0; + queue_create_info[0].pNext = NULL; queue_create_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_create_info[1].queueFamilyIndex = __kvf_present_queue_family; queue_create_info[1].queueCount = 1; queue_create_info[1].pQueuePriorities = &queue_priority; + queue_create_info[1].flags = 0; + queue_create_info[1].pNext = NULL; - VkPhysicalDeviceFeatures device_features; + VkPhysicalDeviceFeatures device_features = { VK_FALSE }; VkDeviceCreateInfo createInfo; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - createInfo.queueCreateInfoCount = sizeof(queue_create_info) / sizeof(queue_create_info[0]); + createInfo.queueCreateInfoCount = 2; createInfo.pQueueCreateInfos = queue_create_info; createInfo.pEnabledFeatures = &device_features; - createInfo.enabledExtensionCount = deviceExtensions.size(); - createInfo.ppEnabledExtensionNames = deviceExtensions.data(); + createInfo.enabledExtensionCount = extensions_count; + createInfo.ppEnabledExtensionNames = extensions; createInfo.enabledLayerCount = 0; + createInfo.ppEnabledLayerNames = NULL; + createInfo.flags = 0; + createInfo.pNext = NULL; VkDevice device = VK_NULL_HANDLE; checkVk(vkCreateDevice(physical, &createInfo, NULL, &device)); @@ -312,7 +403,58 @@ void kvfDestroyDevice(VkDevice device) { if(device == VK_NULL_HANDLE) return; - checkVk(vkDestroyDevice(device, NULL)); + vkDestroyDevice(device, NULL); +} + +VkQueue kvfGetDeviceQueue(VkDevice device, KvfQueueType queue) +{ + KVF_ASSERT(__kvf_graphics_queue_family != -1); + KVF_ASSERT(__kvf_present_queue_family != -1); + + VkQueue vk_queue = VK_NULL_HANDLE; + + if(queue == KVF_GRAPHICS_QUEUE) + vkGetDeviceQueue(device, __kvf_graphics_queue_family, 0, &vk_queue); + else if(queue == KVF_GRAPHICS_QUEUE) + vkGetDeviceQueue(device, __kvf_present_queue_family, 0, &vk_queue); + return vk_queue; +} + +VkFence kvfCreateFence(VkDevice device) +{ + VkFenceCreateInfo fenceInfo = { 0 }; + fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + VkFence fence = VK_NULL_HANDLE; + checkVk(vkCreateFence(device, &fenceInfo, NULL, &fence)); + return fence; +} + +void kvfDestroyFence(VkDevice device, VkFence fence) +{ + if(fence == VK_NULL_HANDLE) + return; + KVF_ASSERT(device != VK_NULL_HANDLE); + vkDestroyFence(device, fence, NULL); +} + +VkSemaphore kvfCreateSemaphore(VkDevice device) +{ + VkSemaphoreCreateInfo semaphoreInfo{}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkSemaphore semaphore = VK_NULL_HANDLE; + checkVk(vkCreateSemaphore(Render_Core::get().getDevice().get(), &semaphoreInfo, NULL, &semaphores)); + return semaphore; +} + +void kvfDestroySemaphore(VkDevice device, VkSemaphore semaphore) +{ + if(semaphore == VK_NULL_HANDLE) + return; + KVF_ASSERT(device != VK_NULL_HANDLE); + vkDestroySemaphore(device, semaphores, NULL); } #endif // KVF_IMPLEMENTATION diff --git a/sandbox/Makefile b/sandbox/Makefile new file mode 100644 index 0000000..a8786bb --- /dev/null +++ b/sandbox/Makefile @@ -0,0 +1,10 @@ +NAME = ./test + +CC = clang + +all : $(NAME) + +$(NAME): + $(CC) -o $(NAME) main.c -lvulkan -lSDL2 -g + +.PHONY: all diff --git a/sandbox/main.c b/sandbox/main.c new file mode 100644 index 0000000..a81fed0 --- /dev/null +++ b/sandbox/main.c @@ -0,0 +1,32 @@ +#include +#include +#include +#define KVF_IMPLEMENTATION +#define KVF_ENABLE_VALIDATION_LAYERS +#include "../kvf.h" + +int main(void) +{ + SDL_Window* win = SDL_CreateWindow("KVF Sandbox", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 600, 400, SDL_WINDOW_VULKAN); + uint32_t ext_count; + SDL_Vulkan_GetInstanceExtensions(win, &ext_count, NULL); + const char** exts = malloc(sizeof(char*) * (ext_count + 1)); + exts[0] = VK_EXT_DEBUG_REPORT_EXTENSION_NAME; + SDL_Vulkan_GetInstanceExtensions(win, &ext_count, exts + 1); + + VkInstance instance = kvfCreateInstance(exts, ext_count + 1); + VkSurfaceKHR surface = VK_NULL_HANDLE; + SDL_Vulkan_CreateSurface(win, instance, &surface); + VkPhysicalDevice ph_device = kvfPickGoodDefaultPhysicalDevice(instance, surface); + VkDevice device = kvfCreateDefaultDevice(ph_device); + VkQueue graphics_queue = kvfGetDeviceQueue(device, KVF_GRAPHICS_QUEUE); + VkQueue present_queue = kvfGetDeviceQueue(device, KVF_PRESENT_QUEUE); + + SDL_Delay(2000); + + vkDestroySurfaceKHR(instance, surface, NULL); + kvfDestroyDevice(device); + kvfDestroyInstance(instance); + + return 0; +}