diff options
author | gramanas <anastasis.gramm2@gmail.com> | 2024-06-05 02:48:40 +0300 |
---|---|---|
committer | gramanas <anastasis.gramm2@gmail.com> | 2024-06-05 02:48:40 +0300 |
commit | 6af7e785890a322f60c21a51e3d41cd9015e6773 (patch) | |
tree | 02c9953325490dff640742ae6d3a53f7ef352d52 /src/vksetup.h | |
parent | 269be80a1d6ba761e080c711f40df4de012c2465 (diff) | |
download | cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.tar.gz cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.tar.bz2 cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.zip |
more vks
Diffstat (limited to 'src/vksetup.h')
-rw-r--r-- | src/vksetup.h | 896 |
1 files changed, 693 insertions, 203 deletions
diff --git a/src/vksetup.h b/src/vksetup.h index e78b887..e3b8f75 100644 --- a/src/vksetup.h +++ b/src/vksetup.h @@ -124,9 +124,9 @@ const char *const device_extensions[] = { const uint32_t deviceExtensionCount = VK_ARRAY_LEN(device_extensions); #ifdef VKDEBUG - const bool enableValidationLayers = true; + const bool enable_validation_layers = true; #else - const bool enableValidationLayers = false; + const bool enable_validation_layers = false; #endif @@ -143,8 +143,6 @@ extern "C" { #endif #endif -// TODO Create structs for vulkan data - typedef struct vks_swapchain { VkSwapchainKHR handle; @@ -181,6 +179,8 @@ typedef struct vks_context { VkSurfaceKHR surface; vks_swapchain swapchain; + + VkSampleCountFlagBits msaa_samples; } vks_context; typedef struct vks_frame_data { @@ -222,19 +222,15 @@ typedef struct vks_transition_image_layout_info /* Exported API */ -VKSDEF VkInstance vks_create_instance (bool validation_layers_toggle, const char * const validation_layers[], uint32_t validation_layer_count, SDL_Window *window); -VKSDEF void vks_create_buffer (const vks_context vk, const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags properties, vks_buffer *buffer); -VKSDEF void vks_create_image (const vks_context vk, const uint32_t width, const uint32_t height, const uint32_t mipLevels, const VkFormat format, const VkImageTiling tiling, const VkImageUsageFlags usage, const VkMemoryPropertyFlags properties, const VkSampleCountFlagBits numSamples, vks_image *image); -VKSDEF void vks_transition_image_layout (const vks_transition_image_layout_info *info); -VKSDEF void vks_copy_buffer (const vks_command_info *cmd_info, const VkBuffer src_buffer, VkBuffer dst_buffer, const VkDeviceSize size); -VKSDEF void vks_copy_buffer_to_image (const vks_command_info* cmd_info, const VkBuffer buffer, VkImage image, const uint32_t width, const uint32_t height); -VKSDEF void vks_generate_mipmaps (const vks_command_info* cmd_info, VkImage image, const VkFormat imageFormat, const int32_t texWidth, const int32_t texHeight, const uint32_t mipLevels); - -/* 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 vks_create_vulkan_context (vks_context *vk, VkQueue *graphics_and_compute_queue, VkQueue *present_queue); +VKSDEF void vks_create_buffer (const vks_context vk, const VkDeviceSize size, const VkBufferUsageFlags usage, const VkMemoryPropertyFlags properties, vks_buffer *buffer); +VKSDEF void vks_create_image (const vks_context vk, const uint32_t width, const uint32_t height, const uint32_t mipLevels, const VkFormat format, const VkImageTiling tiling, const VkImageUsageFlags usage, const VkMemoryPropertyFlags properties, const VkSampleCountFlagBits numSamples, vks_image *image); +VKSDEF void vks_transition_image_layout (const vks_transition_image_layout_info *info); +VKSDEF void vks_copy_buffer (const vks_command_info *cmd_info, const VkBuffer src_buffer, VkBuffer dst_buffer, const VkDeviceSize size); +VKSDEF void vks_copy_buffer_to_image (const vks_command_info* cmd_info, const VkBuffer buffer, VkImage image, const uint32_t width, const uint32_t height); +VKSDEF void vks_generate_mipmaps (const vks_command_info* cmd_info, VkImage image, const VkFormat imageFormat, const int32_t texWidth, const int32_t texHeight, const uint32_t mipLevels); +VKSDEF VkImageView vks_create_image_view (const vks_context vk, VkImage image, VkFormat format, VkImageAspectFlags aspectFlags, uint32_t mipLevels); + /* VKSDEF void vulkan_create_descriptor_set_layout(); */ /* VKSDEF void vulkan_create_graphics_pipeline(); */ /* VKSDEF void vulkan_create_command_pool(); */ @@ -265,9 +261,9 @@ VKSDEF void vks_generate_mipmaps (const vks_command_info* cmd_info, /* Vks helpers */ -bool -vks_check_validation_layer_support(const char* const validation_layers[], - uint32_t validation_layer_count) +static bool +_vks_check_validation_layer_support(const char* const validation_layers[], + uint32_t validation_layer_count) { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, NULL); @@ -288,10 +284,10 @@ vks_check_validation_layer_support(const char* const validation_layers[], return layerFound; } -uint32_t -find_memory_type(const vks_context vk, - const uint32_t typeFilter, - const VkMemoryPropertyFlags properties) +static uint32_t +_find_memory_type(const vks_context vk, + const uint32_t typeFilter, + const VkMemoryPropertyFlags properties) { VkPhysicalDeviceMemoryProperties mem_properties; vkGetPhysicalDeviceMemoryProperties(vk.physical_device, &mem_properties); @@ -308,8 +304,8 @@ find_memory_type(const vks_context vk, return 9999; } -VkCommandBuffer -begin_single_time_commands(const vks_command_info *info) +static VkCommandBuffer +_vks_begin_single_time_commands(const vks_command_info *info) { VkCommandBufferAllocateInfo allocInfo = {0}; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; @@ -328,9 +324,8 @@ begin_single_time_commands(const vks_command_info *info) return commandBuffer; } - -void -end_single_time_commands(const vks_command_info *info, VkCommandBuffer command_buffer) +static void +_vks_end_single_time_commands(const vks_command_info *info, VkCommandBuffer command_buffer) { VK_CHECK(vkEndCommandBuffer(command_buffer)); @@ -345,132 +340,729 @@ end_single_time_commands(const vks_command_info *info, VkCommandBuffer command_b vkFreeCommandBuffers(info->vk.device, info->pool, 1, &command_buffer); } -int -has_stencil_component(VkFormat format) +static int +_has_stencil_component(VkFormat format) +{ + return format == VK_FORMAT_D32_SFLOAT_S8_UINT || + format == VK_FORMAT_D24_UNORM_S8_UINT; +} + +static 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; +} + +static bool +_vulkan_check_device_extension_support(VkPhysicalDevice device) +{ + uint32_t extensionCount; + vkEnumerateDeviceExtensionProperties(device, NULL, &extensionCount, NULL); + + VkExtensionProperties availableExtensions[extensionCount]; + vkEnumerateDeviceExtensionProperties( + device, NULL, &extensionCount, availableExtensions); + + uint32_t flag = 0; + + for (uint32_t i = 0; i < deviceExtensionCount; i++) { + for (uint32_t j = 0; j < extensionCount; j++) { + if (strcmp(device_extensions[i], availableExtensions[j].extensionName) == + 0) { + flag++; + break; + } + } + } + + return flag == deviceExtensionCount; +} + +typedef struct _QueueFamilyIndices +{ + uint32_t graphicsAndComputeFamily; + bool graphicsFlag; + uint32_t presentFamily; + bool presentFlag; +} _QueueFamilyIndices; + +static bool +_vulkan_queue_family_check_flags(_QueueFamilyIndices x) +{ + return x.graphicsFlag && x.presentFlag; +} + +static _QueueFamilyIndices +_vulkan_find_queue_families(vks_context* vk, VkPhysicalDevice device) +{ + _QueueFamilyIndices indices; + indices.graphicsFlag = false; + indices.presentFlag = false; + + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, NULL); + + VkQueueFamilyProperties queueFamilies[queueFamilyCount]; + vkGetPhysicalDeviceQueueFamilyProperties( + device, &queueFamilyCount, queueFamilies); + + for (uint32_t i = 0; i < queueFamilyCount; i++) { + if ((queueFamilies[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) && + (queueFamilies[i].queueFlags & VK_QUEUE_COMPUTE_BIT)) { + indices.graphicsAndComputeFamily = i; + indices.graphicsFlag = true; + } + + VkBool32 presentSupport = false; + vkGetPhysicalDeviceSurfaceSupportKHR( + device, i, vk->surface, &presentSupport); + if (presentSupport) { + indices.presentFamily = i; + indices.presentFlag = true; + } + + if (_vulkan_queue_family_check_flags(indices)) + break; + } + + return indices; +} + +typedef struct _swap_chain_support_details +{ + VkSurfaceCapabilitiesKHR capabilities; + VkSurfaceFormatKHR formats[100]; + uint32_t formatCount; + VkPresentModeKHR presentModes[100]; + uint32_t presentModeCount; +} _swap_chain_support_details; + +static _swap_chain_support_details +_query_swap_chain_support(const vks_context* vk, VkPhysicalDevice device) +{ + // TODO Make SwapChainSupportDetails malloc it;s arrays and free it after it + // is used. + _swap_chain_support_details details; + + vkGetPhysicalDeviceSurfaceCapabilitiesKHR( + device, vk->surface, &details.capabilities); + + vkGetPhysicalDeviceSurfaceFormatsKHR( + device, vk->surface, &details.formatCount, NULL); + + if (details.formatCount != 0) { + // todo alloc format arrray + vkGetPhysicalDeviceSurfaceFormatsKHR( + device, vk->surface, &details.formatCount, details.formats); + } + + vkGetPhysicalDeviceSurfacePresentModesKHR( + device, vk->surface, &details.presentModeCount, NULL); + + if (details.presentModeCount != 0) { + // todo alloc presentModes array + vkGetPhysicalDeviceSurfacePresentModesKHR( + device, vk->surface, &details.presentModeCount, details.presentModes); + } + + return details; +} + +static bool +_vulkan_is_device_suitable(vks_context* vk, VkPhysicalDevice device) +{ + _QueueFamilyIndices indices = _vulkan_find_queue_families(vk, device); + bool extensionsSupported = _vulkan_check_device_extension_support(device); + + bool swapChainAdequate = false; + if (extensionsSupported) { + _swap_chain_support_details swapChainSupport = + _query_swap_chain_support(vk, device); + swapChainAdequate = !(swapChainSupport.formatCount == 0) && + !(swapChainSupport.presentModeCount == 0); + } + + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(device, &supportedFeatures); + + return _vulkan_queue_family_check_flags(indices) && extensionsSupported && + swapChainAdequate && supportedFeatures.samplerAnisotropy; +} + +static VkSampleCountFlagBits +_get_max_usable_sample_count(vks_context* vk) +{ + VkPhysicalDeviceProperties physicalDeviceProperties; + vkGetPhysicalDeviceProperties(vk->physical_device, &physicalDeviceProperties); + + VkSampleCountFlags counts = + physicalDeviceProperties.limits.framebufferColorSampleCounts & + physicalDeviceProperties.limits.framebufferDepthSampleCounts; + if (counts & VK_SAMPLE_COUNT_64_BIT) { + return VK_SAMPLE_COUNT_64_BIT; + } + if (counts & VK_SAMPLE_COUNT_32_BIT) { + return VK_SAMPLE_COUNT_32_BIT; + } + if (counts & VK_SAMPLE_COUNT_16_BIT) { + return VK_SAMPLE_COUNT_16_BIT; + } + if (counts & VK_SAMPLE_COUNT_8_BIT) { + return VK_SAMPLE_COUNT_8_BIT; + } + if (counts & VK_SAMPLE_COUNT_4_BIT) { + return VK_SAMPLE_COUNT_4_BIT; + } + if (counts & VK_SAMPLE_COUNT_2_BIT) { + return VK_SAMPLE_COUNT_2_BIT; + } + + return VK_SAMPLE_COUNT_1_BIT; +} + +static void +_vulkan_pick_physical_device(vks_context* vk) +{ + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(vk->instance, &deviceCount, NULL); + if (deviceCount == 0) { + vk_log(VK_INFO, "failed to find GPUs with Vulkan support!\n"); + } + + VkPhysicalDevice devices[deviceCount]; + vkEnumeratePhysicalDevices(vk->instance, &deviceCount, devices); + + for (uint32_t i = 0; i < deviceCount; i++) { + if (_vulkan_is_device_suitable(vk, devices[i])) { + vk->physical_device = devices[i]; + vk->msaa_samples = _get_max_usable_sample_count(vk); + break; + } + } + + if (vk->physical_device == VK_NULL_HANDLE) { + vk_log(VK_ERROR, "failed to find a suitable GPU!\n"); + } + + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(vk->physical_device, &deviceProperties); + vk_log( + VK_INFO, "Picked [%s] physical device.\n", deviceProperties.deviceName); + + uint32_t extensionCount = 0; + vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, NULL); + VkExtensionProperties extensions[extensionCount]; + VkResult result = + vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensions); + + vk_log(VK_INFO, "Vulkan enabled extensions:\n"); + for (uint32_t i = 0; i < extensionCount; i++) { + vk_log(VK_INFO, "\t%s\n", extensions[i].extensionName); + } +} + +static void +_vulkan_create_logical_device(vks_context* vk, + VkQueue* graphics_and_compute_queue, + VkQueue* present_queue) +{ + _QueueFamilyIndices indices = + _vulkan_find_queue_families(vk, vk->physical_device); + + // TODO CREATE MULPILE QUEUES + // https://vulkan-tutorial.com/en/Drawing_a_triangle/Presentation/Window_surface#page_Creating-the-presentation-queue + + VkDeviceQueueCreateInfo queueCreateInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = indices.graphicsAndComputeFamily, + .queueCount = 1, + }; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + VkPhysicalDeviceFeatures deviceFeatures = { 0 }; + vkGetPhysicalDeviceFeatures(vk->physical_device, &deviceFeatures); + deviceFeatures.samplerAnisotropy = VK_TRUE; + // deviceFeatures.sampleRateShading = VK_TRUE; +#ifndef VKDEBUG + /* Disable robust buffer access when building without debug */ + deviceFeatures.robustBufferAccess = VK_FALSE; +#endif + + VkPhysicalDeviceDynamicRenderingFeaturesKHR dynamic_rendering_feature = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, + .dynamicRendering = VK_TRUE, + }; + + VkDeviceCreateInfo createInfo = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = &queueCreateInfo, + .queueCreateInfoCount = 1, + .pNext = &dynamic_rendering_feature, + .pEnabledFeatures = &deviceFeatures, + .enabledExtensionCount = deviceExtensionCount, + .ppEnabledExtensionNames = device_extensions, + .enabledLayerCount = 0, + }; + + if (vkCreateDevice(vk->physical_device, &createInfo, NULL, &vk->device) != + VK_SUCCESS) { + vk_log(VK_ERROR, "failed to create logical device!\n"); + } + vk_log(VK_INFO, "Vulkan logical device created\n"); + + vkGetDeviceQueue(vk->device, + indices.graphicsAndComputeFamily, + 0, + graphics_and_compute_queue); + vkGetDeviceQueue(vk->device, indices.presentFamily, 0, present_queue); +} + +static VkSurfaceFormatKHR +_chooseSwapSurfaceFormat(const VkSurfaceFormatKHR* availableFormats, + uint32_t formatCount) +{ + for (uint32_t i = 0; i < formatCount; i++) { + if (availableFormats[i].format == VK_FORMAT_B8G8R8A8_SRGB && + availableFormats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + return availableFormats[i]; + } + } + + // if it fails pick the first one + return availableFormats[0]; +} + +static VkPresentModeKHR +_chooseSwapPresentMode(const VkPresentModeKHR* presentModes, + uint32_t presentModeCount) { - return format == VK_FORMAT_D32_SFLOAT_S8_UINT || format == VK_FORMAT_D24_UNORM_S8_UINT; + for (uint32_t i = 0; i < presentModeCount; i++) { + if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR) { + return presentModes[i]; + } + } + + // if it fails pick the the FIFO one + return VK_PRESENT_MODE_FIFO_KHR; +} + +static VkExtent2D +_chooseSwapExtent(const vks_context* vk, + const VkSurfaceCapabilitiesKHR* capabilities) +{ + if (capabilities->currentExtent.width != UINT32_MAX) { + return capabilities->currentExtent; + } else { + int width, height; + SDL_GetWindowSize(vk->window, &width, &height); + + VkExtent2D actualExtent; + actualExtent.width = (uint32_t)width; + actualExtent.height = (uint32_t)height; + + // Manual implementation of std::clamp since it is not available in C + actualExtent.width = + (actualExtent.width < capabilities->minImageExtent.width) + ? capabilities->minImageExtent.width + : (actualExtent.width > capabilities->maxImageExtent.width) + ? capabilities->maxImageExtent.width + : actualExtent.width; + + actualExtent.height = + (actualExtent.height < capabilities->minImageExtent.height) + ? capabilities->minImageExtent.height + : (actualExtent.height > capabilities->maxImageExtent.height) + ? capabilities->maxImageExtent.height + : actualExtent.height; + + return actualExtent; + } +} + +static void bla() {printf("blah\n");} + +VKSDEF void +_vulkan_create_swap_chain(vks_context* vk) +{ + _swap_chain_support_details swapChainSupport = + _query_swap_chain_support(vk, vk->physical_device); + + VkSurfaceFormatKHR surfaceFormat = _chooseSwapSurfaceFormat( + swapChainSupport.formats, swapChainSupport.formatCount); + VkPresentModeKHR presentMode = _chooseSwapPresentMode( + swapChainSupport.presentModes, swapChainSupport.presentModeCount); + VkExtent2D extent = _chooseSwapExtent(vk, &swapChainSupport.capabilities); + + uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1; + + if (swapChainSupport.capabilities.maxImageCount > 0 && + imageCount > swapChainSupport.capabilities.maxImageCount) { + imageCount = swapChainSupport.capabilities.maxImageCount; + } + + VkSwapchainCreateInfoKHR createInfo = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = vk->surface, + .minImageCount = imageCount, + .imageFormat = surfaceFormat.format, + .imageColorSpace = surfaceFormat.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + }; + + _QueueFamilyIndices indices = + _vulkan_find_queue_families(vk, vk->physical_device); + + uint32_t queueFamilyIndices[] = { indices.graphicsAndComputeFamily, + indices.presentFamily }; + + if (indices.graphicsAndComputeFamily != indices.presentFamily) { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = 2; + createInfo.pQueueFamilyIndices = queueFamilyIndices; + } else { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; // Optional + createInfo.pQueueFamilyIndices = NULL; // Optional + } + + createInfo.preTransform = swapChainSupport.capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + VK_CHECK( + vkCreateSwapchainKHR(vk->device, &createInfo, NULL, &vk->swapchain.handle)); + /* if (result != VK_SUCCESS) { */ + /* vk_log(VK_ERROR, "ERROR: failed to create swap chain! %s\n", + * string_VkResult(result)); */ + /* } */ + + VK_CHECK(vkGetSwapchainImagesKHR( + vk->device, vk->swapchain.handle, &vk->swapchain.image_count, NULL)); + // vk_log(VK_INFO, "vk_swap_chain_images count: %d\n", + // vk->swapchain.image_count); + // todo alloc space for images + VK_CHECK(vkGetSwapchainImagesKHR(vk->device, + vk->swapchain.handle, + &vk->swapchain.image_count, + vk->swapchain.images)); + + vk->swapchain.image_format = surfaceFormat.format; + vk->swapchain.extent = extent; + + vk_log(VK_INFO, "Vulkan swapchain created!\n"); + + for (size_t i = 0; i < vk->swapchain.image_count; i++) { + vk->swapchain.image_views[i] = + vks_create_image_view(*vk, + vk->swapchain.images[i], + vk->swapchain.image_format, + VK_IMAGE_ASPECT_COLOR_BIT, + 1); + } } /* Vks API implementation */ + +VKSDEF void +vks_create_vulkan_context(vks_context* vk, + VkQueue* graphics_and_compute_queue, + VkQueue* present_queue) +{ + /* Create vulkan instance */ + vk->instance = _vks_create_instance(enable_validation_layers, + validation_layers, + validation_layer_count, + vk->window); + + /* Create render surface */ + if (SDL_Vulkan_CreateSurface(vk->window, vk->instance, &vk->surface) == + SDL_FALSE) { + vk_log(VK_ERROR, "Failed to create surface\n"); + } else { + vk_log(VK_INFO, "Vulkan surface created\n"); + } + + /* Pick physical device */ + _vulkan_pick_physical_device(vk); + + /* Create logical device and get queues */ + /* TODO: Create vks_get_queue helpers?? */ + _vulkan_create_logical_device(vk, graphics_and_compute_queue, present_queue); + + /* Create swapchain */ + /* TODO: Make swapchain api */ + _vulkan_create_swap_chain(vk); +} + +VKSDEF VkImageView +vks_create_image_view(const vks_context vk, + VkImage image, + VkFormat format, + VkImageAspectFlags aspectFlags, + uint32_t mipLevels) +{ + VkImageViewCreateInfo viewInfo = { 0 }; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = image; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = format; + viewInfo.subresourceRange.aspectMask = aspectFlags; + viewInfo.subresourceRange.baseMipLevel = 0; + viewInfo.subresourceRange.levelCount = mipLevels; + viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.layerCount = 1; + + VkImageView imageView; + VK_CHECK(vkCreateImageView(vk.device, &viewInfo, NULL, &imageView)); + + return imageView; +} + VKSDEF void vks_generate_mipmaps(const vks_command_info* cmd_info, - VkImage image, - const VkFormat imageFormat, - const int32_t texWidth, - const int32_t texHeight, - const uint32_t mipLevels) + VkImage image, + const VkFormat imageFormat, + const int32_t texWidth, + const int32_t texHeight, + const uint32_t mipLevels) { - VkCommandBuffer command_buffer = begin_single_time_commands(cmd_info); + VkCommandBuffer command_buffer = _vks_begin_single_time_commands(cmd_info); - VkImageMemoryBarrier barrier = {0}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.image = image; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + VkImageMemoryBarrier barrier = { 0 }; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = image; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.layerCount = 1; + barrier.subresourceRange.levelCount = 1; - int32_t mipWidth = texWidth; + int32_t mipWidth = texWidth; int32_t mipHeight = texHeight; for (uint32_t i = 1; i < mipLevels; i++) { barrier.subresourceRange.baseMipLevel = i - 1; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1, + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_TRANSFER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 1, &barrier); - VkImageBlit blit = {0}; - blit.srcOffsets[0] = (VkOffset3D){ 0, 0, 0 }; - blit.srcOffsets[1] = (VkOffset3D){ mipWidth, mipHeight, 1 }; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = i - 1; + VkImageBlit blit = { 0 }; + blit.srcOffsets[0] = (VkOffset3D){ 0, 0, 0 }; + blit.srcOffsets[1] = (VkOffset3D){ mipWidth, mipHeight, 1 }; + blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.srcSubresource.mipLevel = i - 1; blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = 1; - blit.dstOffsets[0] = (VkOffset3D){ 0, 0, 0 }; - blit.dstOffsets[1] = (VkOffset3D){ mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, 1 }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = i; + blit.srcSubresource.layerCount = 1; + blit.dstOffsets[0] = (VkOffset3D){ 0, 0, 0 }; + blit.dstOffsets[1] = (VkOffset3D){ mipWidth > 1 ? mipWidth / 2 : 1, + mipHeight > 1 ? mipHeight / 2 : 1, + 1 }; + blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + blit.dstSubresource.mipLevel = i; blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = 1; - - vkCmdBlitImage(command_buffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, + blit.dstSubresource.layerCount = 1; + + vkCmdBlitImage(command_buffer, + image, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + image, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, + &blit, VK_FILTER_LINEAR); - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT, - VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, - NULL, 1, &barrier); + vkCmdPipelineBarrier(command_buffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, + VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, + 0, + 0, + NULL, + 0, + NULL, + 1, + &barrier); - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; + if (mipWidth > 1) + mipWidth /= 2; + if (mipHeight > 1) + mipHeight /= 2; } - end_single_time_commands(cmd_info, command_buffer); + _vks_end_single_time_commands(cmd_info, command_buffer); } VKSDEF void vks_copy_buffer_to_image(const vks_command_info* cmd_info, - const VkBuffer buffer, - VkImage image, - const uint32_t width, - const uint32_t height) + const VkBuffer buffer, + VkImage image, + const uint32_t width, + const uint32_t height) { - VkCommandBuffer command_buffer = begin_single_time_commands(cmd_info); + VkCommandBuffer command_buffer = _vks_begin_single_time_commands(cmd_info); - VkBufferImageCopy region = {0}; - region.bufferOffset = 0; - region.bufferRowLength = 0; + VkBufferImageCopy region = { 0 }; + region.bufferOffset = 0; + region.bufferRowLength = 0; region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = 0; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; + region.imageSubresource.layerCount = 1; - region.imageOffset = (VkOffset3D){0, 0, 0}; - region.imageExtent = (VkExtent3D){width, height, 1}; + region.imageOffset = (VkOffset3D){ 0, 0, 0 }; + region.imageExtent = (VkExtent3D){ width, height, 1 }; vkCmdCopyBufferToImage(command_buffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, - ®ion - ); + ®ion); - end_single_time_commands(cmd_info, command_buffer); + _vks_end_single_time_commands(cmd_info, command_buffer); } VKSDEF void -vks_copy_buffer(const vks_command_info *cmd_info, const VkBuffer src_buffer, VkBuffer dst_buffer, const VkDeviceSize size) +vks_copy_buffer(const vks_command_info* cmd_info, + const VkBuffer src_buffer, + VkBuffer dst_buffer, + const VkDeviceSize size) { - VkCommandBuffer command_buffer = begin_single_time_commands(cmd_info); + VkCommandBuffer command_buffer = _vks_begin_single_time_commands(cmd_info); - VkBufferCopy copy_region = {0}; - copy_region.srcOffset = 0; // Optional - copy_region.dstOffset = 0; // Optional - copy_region.size = size; + VkBufferCopy copy_region = { 0 }; + copy_region.srcOffset = 0; // Optional + copy_region.dstOffset = 0; // Optional + copy_region.size = size; vkCmdCopyBuffer(command_buffer, src_buffer, dst_buffer, 1, ©_region); - end_single_time_commands(cmd_info, command_buffer); + _vks_end_single_time_commands(cmd_info, command_buffer); } VKSDEF void -vks_transition_image_layout(const vks_transition_image_layout_info *info) +vks_transition_image_layout(const vks_transition_image_layout_info* info) { - VkCommandBuffer command_buffer = begin_single_time_commands(&info->cmd_info); + VkCommandBuffer command_buffer = _vks_begin_single_time_commands(&info->cmd_info); VkImageMemoryBarrier barrier = { 0 }; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -486,7 +1078,7 @@ vks_transition_image_layout(const vks_transition_image_layout_info *info) if (info->newLayout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) { barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (has_stencil_component(info->format)) { + if (_has_stencil_component(info->format)) { barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; } } else { @@ -509,7 +1101,7 @@ vks_transition_image_layout(const vks_transition_image_layout_info *info) 1, &barrier); - end_single_time_commands(&info->cmd_info, command_buffer); + _vks_end_single_time_commands(&info->cmd_info, command_buffer); } VKSDEF void @@ -548,7 +1140,7 @@ vks_create_image(const vks_context vk, allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = - find_memory_type(vk, memRequirements.memoryTypeBits, properties); + _find_memory_type(vk, memRequirements.memoryTypeBits, properties); // TODO: group allocations etc... (allocations limited by hardware) VK_CHECK(vkAllocateMemory(vk.device, &allocInfo, NULL, &image->memory)); @@ -578,112 +1170,10 @@ vks_create_buffer(const vks_context vk, allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = mem_requirements.size; allocInfo.memoryTypeIndex = - find_memory_type(vk, mem_requirements.memoryTypeBits, properties); + _find_memory_type(vk, mem_requirements.memoryTypeBits, properties); // TODO: group allocations etc... (allocations limited by hardware) VK_CHECK(vkAllocateMemory(vk.device, &allocInfo, NULL, &buffer->memory)); VK_CHECK(vkBindBufferMemory(vk.device, buffer->handle, buffer->memory, 0)); } - -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 */ |