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 | |
parent | 269be80a1d6ba761e080c711f40df4de012c2465 (diff) | |
download | cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.tar.gz cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.tar.bz2 cgame-6af7e785890a322f60c21a51e3d41cd9015e6773.zip |
more vks
-rw-r--r-- | src/render.c | 428 | ||||
-rw-r--r-- | src/state.h | 3 | ||||
-rw-r--r-- | src/vksetup.h | 896 |
3 files changed, 708 insertions, 619 deletions
diff --git a/src/render.c b/src/render.c index 810db51..ae9c05b 100644 --- a/src/render.c +++ b/src/render.c @@ -170,7 +170,7 @@ debugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, void vulkan_setup_debug_messenger() { - if (!enableValidationLayers) return; + if (!enable_validation_layers) return; VkDebugUtilsMessengerCreateInfoEXT createInfo = {0}; 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; @@ -191,92 +191,6 @@ vulkan_setup_debug_messenger() } } -VkExtent2D -chooseSwapExtent(const VkSurfaceCapabilitiesKHR * capabilities) -{ - if (capabilities->currentExtent.width != UINT32_MAX) { - return capabilities->currentExtent; - } else { - int width, height; - SDL_GetWindowSize(s.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; - } -} - -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]; -} - -VkPresentModeKHR -chooseSwapPresentMode(const VkPresentModeKHR * presentModes, uint32_t presentModeCount) -{ - 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; -} - -typedef struct SwapChainSupportDetails { - VkSurfaceCapabilitiesKHR capabilities; - VkSurfaceFormatKHR formats[100]; - uint32_t formatCount; - VkPresentModeKHR presentModes[100]; - uint32_t presentModeCount; -} SwapChainSupportDetails; - -SwapChainSupportDetails -querySwapChainSupport(VkPhysicalDevice device) -{ - // TODO Make SwapChainSupportDetails malloc it;s arrays and free it after it is used. - SwapChainSupportDetails details; - - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, s.vk.surface, &details.capabilities); - - vkGetPhysicalDeviceSurfaceFormatsKHR(device, s.vk.surface, &details.formatCount, NULL); - - if (details.formatCount != 0) { - // todo alloc format arrray - vkGetPhysicalDeviceSurfaceFormatsKHR(device, s.vk.surface, &details.formatCount, details.formats); - } - - vkGetPhysicalDeviceSurfacePresentModesKHR(device, s.vk.surface, &details.presentModeCount, NULL); - - if (details.presentModeCount != 0) { - // todo alloc presentModes array - vkGetPhysicalDeviceSurfacePresentModesKHR(device, s.vk.surface, &details.presentModeCount, details.presentModes); - } - - return details; -} - typedef struct QueueFamilyIndices { uint32_t graphicsAndComputeFamily; bool graphicsFlag; @@ -320,154 +234,6 @@ QueueFamilyIndices vulkan_find_queue_families(VkPhysicalDevice device) { return indices; } -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; -} - -bool -vulkan_is_device_suitable(VkPhysicalDevice device) -{ - QueueFamilyIndices indices = vulkan_find_queue_families(device); - bool extensionsSupported = vulkan_check_device_extension_support(device); - - bool swapChainAdequate = false; - if (extensionsSupported) { - SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device); - swapChainAdequate = !(swapChainSupport.formatCount == 0) && !(swapChainSupport.presentModeCount == 0); - } - - VkPhysicalDeviceFeatures supportedFeatures; - vkGetPhysicalDeviceFeatures(device, &supportedFeatures); - - return vulkan_queue_family_check_flags(indices) && extensionsSupported - && swapChainAdequate && supportedFeatures.samplerAnisotropy; -} - -VkSampleCountFlagBits getMaxUsableSampleCount() { - VkPhysicalDeviceProperties physicalDeviceProperties; - vkGetPhysicalDeviceProperties(s.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; -} - -void -vulkan_pick_physical_device() -{ - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(s.vk.instance, &deviceCount, NULL); - if (deviceCount == 0) { - vk_log(VK_INFO, "failed to find GPUs with Vulkan support!\n"); - } - - VkPhysicalDevice devices[deviceCount]; - vkEnumeratePhysicalDevices(s.vk.instance, &deviceCount, devices); - - for (uint32_t i = 0; i < deviceCount; i++) { - if (vulkan_is_device_suitable(devices[i])) { - s.vk.physical_device = devices[i]; - s.msaa_samples = getMaxUsableSampleCount(); - break; - } - } - - if (s.vk.physical_device == VK_NULL_HANDLE) { - vk_log(VK_ERROR, "failed to find a suitable GPU!\n"); - } - - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(s.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: %s\n", string_VkResult(result)); - for (uint32_t i = 0; i < extensionCount; i++) { - vk_log(VK_INFO, "\t%s\n", extensions[i].extensionName); - } - -} - -void -vulkan_create_logical_device() -{ - QueueFamilyIndices indices = vulkan_find_queue_families(s.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(s.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(s.vk.physical_device, &createInfo, NULL, &s.vk.device) != VK_SUCCESS) { - vk_log(VK_ERROR, "failed to create logical device!\n"); - } - vk_log(VK_INFO, "Vulkan logical device created\n"); - - vkGetDeviceQueue(s.vk.device, indices.graphicsAndComputeFamily, 0, &s.vk_graphics_and_compute_queue); - vkGetDeviceQueue(s.vk.device, indices.presentFamily, 0, &s.vk_present_queue); -} - void move_relative(vec3 position, vec3 front, float step, int x) { // Calculate the direction vector from position to front float direction_vec[3] = { @@ -549,108 +315,6 @@ mouseCallback(SDL_Event *event) return; } -void -vulkan_create_surface() -{ - if (SDL_Vulkan_CreateSurface(s.vk.window, s.vk.instance, &s.vk.surface) == SDL_FALSE) { - vk_log(VK_ERROR, "Failed to create surface\n"); - } else { - vk_log(VK_INFO, "Vulkan surface created\n"); - } -} - -void -vulkan_create_swap_chain() -{ - SwapChainSupportDetails swapChainSupport = querySwapChainSupport(s.vk.physical_device); - - VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats, swapChainSupport.formatCount); - VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes, swapChainSupport.presentModeCount); - VkExtent2D extent = chooseSwapExtent(&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 = s.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(s.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(s.vk.device, &createInfo, NULL, &s.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(s.vk.device, s.vk.swapchain.handle, &s.vk.swapchain.image_count, NULL)); - //vk_log(VK_INFO, "vk_swap_chain_images count: %d\n", s.vk.swapchain.image_count); - // todo alloc space for images - VK_CHECK(vkGetSwapchainImagesKHR(s.vk.device, s.vk.swapchain.handle, &s.vk.swapchain.image_count, s.vk.swapchain.images)); - - s.vk.swapchain.image_format = surfaceFormat.format; - s.vk.swapchain.extent = extent; - - vk_log(VK_INFO, "Vulkan swapchain created!\n"); -} - - -VkImageView -create_image_view(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(s.vk.device, &viewInfo, NULL, &imageView)); - - return imageView; -} - -void -vulkan_create_image_views() -{ - for (size_t i = 0; i < s.vk.swapchain.image_count; i++) { - s.vk.swapchain.image_views[i] = create_image_view(s.vk.swapchain.images[i], s.vk.swapchain.image_format, VK_IMAGE_ASPECT_COLOR_BIT, 1); - } - vk_log(VK_INFO, "Vulkan image views created!\n"); -} - VkShaderModule createShaderModule(const char * code, long size) { @@ -719,59 +383,6 @@ load_compile_shader_data(const char * path, shaderc_shader_kind shader_kind) return result; } -uint32_t -findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) -{ - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(s.vk.physical_device, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - vk_log(VK_ERROR, "failed to find suitable memory type!\n"); - return 9999; -} - -VkCommandBuffer -beginSingleTimeCommands() -{ - VkCommandBufferAllocateInfo allocInfo = {0}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = s.vk_command_pool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - VK_CHECK(vkAllocateCommandBuffers(s.vk.device, &allocInfo, &commandBuffer)); - - VkCommandBufferBeginInfo beginInfo = {0}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - VK_CHECK(vkBeginCommandBuffer(commandBuffer, &beginInfo)); - - return commandBuffer; -} - -void -endSingleTimeCommands(VkCommandBuffer commandBuffer) -{ - VK_CHECK(vkEndCommandBuffer(commandBuffer)); - - VkSubmitInfo submitInfo = {0}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - VK_CHECK(vkQueueSubmit(s.vk_graphics_and_compute_queue, 1, &submitInfo, VK_NULL_HANDLE)); - VK_CHECK(vkQueueWaitIdle(s.vk_graphics_and_compute_queue)); - - vkFreeCommandBuffers(s.vk.device, s.vk_command_pool, 1, &commandBuffer); -} - VkFormat findSupportedFormat(VkFormat *candidates, size_t n, VkImageTiling tiling, @@ -809,10 +420,10 @@ vulkan_create_depth_resources() vks_create_image(s.vk, s.vk.swapchain.extent.width, s.vk.swapchain.extent.height, 1, depth_format, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, s.msaa_samples, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, s.vk.msaa_samples, &s.depth_image); - s.depth_image.view = create_image_view(s.depth_image.handle, depth_format, - VK_IMAGE_ASPECT_DEPTH_BIT, 1); + s.depth_image.view = vks_create_image_view(s.vk, s.depth_image.handle, depth_format, + VK_IMAGE_ASPECT_DEPTH_BIT, 1); vks_transition_image_layout_info transition_info = { 0 }; transition_info.cmd_info.vk = s.vk; @@ -839,9 +450,9 @@ void vulkan_create_color_resources() { colorFormat, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, s.msaa_samples, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, s.vk.msaa_samples, &s.color_image); - s.color_image.view = create_image_view(s.color_image.handle, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); + s.color_image.view = vks_create_image_view(s.vk, s.color_image.handle, colorFormat, VK_IMAGE_ASPECT_COLOR_BIT, 1); } void @@ -972,7 +583,7 @@ vulkan_create_graphics_pipeline(VkPolygonMode polygon_mode) VkPipelineMultisampleStateCreateInfo multisampling = {0}; multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; multisampling.sampleShadingEnable = VK_FALSE; - multisampling.rasterizationSamples = s.msaa_samples; + multisampling.rasterizationSamples = s.vk.msaa_samples; multisampling.minSampleShading = 1.0f; // Optional multisampling.pSampleMask = NULL; // Optional multisampling.alphaToCoverageEnable = VK_FALSE; // Optional @@ -1441,8 +1052,7 @@ recreateSwapChain() cleanupSwapChain(); - vulkan_create_swap_chain(); - vulkan_create_image_views(); + _vulkan_create_swap_chain(&s.vk); vulkan_create_color_resources(); vulkan_create_depth_resources(); } @@ -1665,7 +1275,7 @@ vulkan_create_texture_image() void vulkan_create_texture_image_view() { - s.texture_image.view = create_image_view(s.texture_image.handle, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, s.vk_mip_levels); + s.texture_image.view = vks_create_image_view(s.vk, s.texture_image.handle, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT, s.vk_mip_levels); } void vulkan_create_texture_sampler() { @@ -1765,7 +1375,6 @@ load_model_obj() vk_log(VK_INFO, "[obj] %s: Loaded %ld vertices %ld indices\n", s.model_path, s.vertices_count, s.indices_count); - fast_obj_destroy(m); } @@ -1941,8 +1550,6 @@ void vulkan_create_compute_stuff() VK_CHECK(vkCreateDescriptorSetLayout(s.vk.device, &layoutInfo, NULL, &s.vk_compute_descriptor_set_layout)); - - VkComputePipelineCreateInfo pipelineInfo = {0}; pipelineInfo.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO; pipelineInfo.layout = s.vk_compute_pipeline_layout; @@ -1972,16 +1579,8 @@ init_vulkan() vk_log(VK_WARN, " DEBUG ON \n"); vk_log(VK_WARN, "====================================\n"); - //vulkan_create_instance(); - s.vk.instance = - vks_create_instance(enableValidationLayers, validation_layers, - validation_layer_count, s.vk.window); - // vulkan_setup_debug_messenger(); - vulkan_create_surface(); - vulkan_pick_physical_device(); - vulkan_create_logical_device(); - vulkan_create_swap_chain(); - vulkan_create_image_views(); + vks_create_vulkan_context(&s.vk, &s.vk_graphics_and_compute_queue, &s.vk_present_queue); + vulkan_create_descriptor_set_layout(); vulkan_create_graphics_pipeline(s.polygon_mode); //vulkan_create_compute_stuff(); @@ -2040,7 +1639,7 @@ close_vulkan() vkDestroyPipelineLayout(s.vk.device, s.graphics_pipeline.layout, NULL); vkDestroyDevice(s.vk.device, NULL); vkDestroySurfaceKHR(s.vk.instance, s.vk.surface, NULL); - /* if (enableValidationLayers) { */ + /* if (enable_validation_layers) { */ /* DestroyDebugUtilsMessengerEXT(s.vk.instance, s.vk_debug_messenger, NULL); */ /* } */ vkDestroyInstance(s.vk.instance, NULL); @@ -2113,7 +1712,8 @@ updateUniformBuffer(uint32_t currentImage, float dt) float prev_time = 0; void -draw_frame() { +draw_frame() +{ float time = current_time(); float dt = time - prev_time; diff --git a/src/state.h b/src/state.h index b9c9921..d4f7e6c 100644 --- a/src/state.h +++ b/src/state.h @@ -134,7 +134,6 @@ typedef struct state { char model_path[1000]; - VkSampleCountFlagBits msaa_samples; vks_image color_image; @@ -197,5 +196,5 @@ init_state(state_t *s) s->polygon_mode = VK_POLYGON_MODE_FILL; - s->msaa_samples = VK_SAMPLE_COUNT_1_BIT; + s->vk.msaa_samples = VK_SAMPLE_COUNT_1_BIT; } 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 */ |