From d2d05c9217517dc3cd1a4b56ee305dc53bc8e13f Mon Sep 17 00:00:00 2001 From: Supercip971 Date: Wed, 27 Apr 2022 01:54:13 +0000 Subject: [PATCH] misc: more advancements with vulkan (doesn't work rn tho) --- .clang-format | 25 ++++ src/config.h | 3 + src/log/log.h | 13 +- src/main.c | 4 +- src/render/render.h | 14 ++- src/render/vulkan/debug.c | 18 +-- src/render/vulkan/device.c | 74 ++++++++++-- src/render/vulkan/device.h | 7 +- src/render/vulkan/glfw_vulkan_handle.c | 38 ++++++ src/render/vulkan/layer.c | 6 + src/render/vulkan/layer.h | 6 +- src/render/vulkan/logical.c | 103 ++++++++++++++++ src/render/vulkan/logical.h | 9 ++ src/render/vulkan/render.c | 35 ++++-- src/render/vulkan/surface.h | 8 ++ src/render/vulkan/swapchain.c | 158 +++++++++++++++++++++++++ src/render/vulkan/swapchain.h | 30 +++++ src/render/vulkan/vulkan.c | 42 +++++-- src/render/vulkan/vulkan.h | 36 ++++-- src/utils.h | 12 +- src/window/glfw_window.c | 23 +++- src/window/surface.h | 1 + src/window/window.h | 9 +- 23 files changed, 609 insertions(+), 65 deletions(-) create mode 100644 .clang-format create mode 100644 src/render/vulkan/glfw_vulkan_handle.c create mode 100644 src/render/vulkan/logical.c create mode 100644 src/render/vulkan/logical.h create mode 100644 src/render/vulkan/surface.h create mode 100644 src/render/vulkan/swapchain.c create mode 100644 src/render/vulkan/swapchain.h create mode 100644 src/window/surface.h diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..2be9071 --- /dev/null +++ b/.clang-format @@ -0,0 +1,25 @@ +--- + +BasedOnStyle: LLVM +UseTab: Never +IndentWidth: 4 +TabWidth: 4 +BreakBeforeBraces: Allman +AllowShortIfStatementsOnASingleLine: false +IndentCaseLabels: false +ColumnLimit: 0 +AccessModifierOffset: -4 +FixNamespaceComments: true +SpaceBeforeInheritanceColon: true +BreakInheritanceList: AfterColon +IndentPPDirectives: AfterHash +ForEachMacros: ["__dummy_foreach"] +IncludeBlocks: Merge +IncludeCategories: + - Regex: '<([A-Za-z0-9.\/-_])+>' + Priority: 0 + SortPriority: 0 + - Regex: '"([A-Za-z0-9.\/-_])+"' + Priority: 10 + SortPriority: 10 +... diff --git a/src/config.h b/src/config.h index e22f66a..24f7c83 100644 --- a/src/config.h +++ b/src/config.h @@ -8,3 +8,6 @@ #define WINDOW_WIDTH (1920) #define WINDOW_HEIGHT (1080) + +#define USE_GLFW +#define USE_VULKAN diff --git a/src/log/log.h b/src/log/log.h index 84a1624..79b10c3 100644 --- a/src/log/log.h +++ b/src/log/log.h @@ -1,2 +1,13 @@ -#pragma once +#pragma once +// Regular bold text +#define BBLK "\e[1;30m" +#define BRED "\e[1;31m" +#define BGRN "\e[1;32m" +#define BYEL "\e[1;33m" +#define BBLU "\e[1;34m" +#define BMAG "\e[1;35m" +#define BCYN "\e[1;36m" +#define BWHT "\e[1;37m" + +#define CRESET "\e[0m" diff --git a/src/main.c b/src/main.c index 1de5f6b..8988668 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,7 @@ #include +#include #include #include -#include #include int main(MAYBE_UNUSED int argc, MAYBE_UNUSED char **argv) @@ -11,7 +11,7 @@ int main(MAYBE_UNUSED int argc, MAYBE_UNUSED char **argv) window_engine_init(); window_init(&curr_window); - render_engine_init(); + render_engine_init(&curr_window); render_init(&render); while (!window_should_close(&curr_window)) { diff --git a/src/render/render.h b/src/render/render.h index 1ccd83d..a80660d 100644 --- a/src/render/render.h +++ b/src/render/render.h @@ -1,15 +1,21 @@ -#pragma once +#pragma once +#include +#include typedef struct { int id; } Render; -int render_engine_init(void); +int render_engine_init(Window *window); int render_engine_deinit(void); -int render_init(Render* self); +int render_init(Render *self); -int render_deinit(Render* self); +int render_deinit(Render *self); + +int render_surface_init(Render *self, uintptr_t handle); + +int render_surface_deinit(Render *self, uintptr_t handle); diff --git a/src/render/vulkan/debug.c b/src/render/vulkan/debug.c index 0ee47c3..a410fa3 100644 --- a/src/render/vulkan/debug.c +++ b/src/render/vulkan/debug.c @@ -1,3 +1,4 @@ +#include #include #include @@ -9,31 +10,32 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_callback( { (void)pUserData; + printf("[VULKAN] "); switch (messageSeverity) { case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT: { - printf("[VULKAN] verbose: "); + printf(BWHT "verbose: "); break; } case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT: { - printf("[VULKAN] info: "); + printf(BGRN "info: "); break; } case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT: { - printf("[VULKAN] *warn*: "); + printf(BYEL "*warn*: "); break; } case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT: { - printf("[VULKAN] **error**: "); + printf(BRED "**error**: "); break; } default: { - printf("[VULKAN] **unknown** %i: ", messageSeverity); + printf("**unknown** %i: ", messageSeverity); } } @@ -41,12 +43,12 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_callback( { case VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT: { - printf("validation: "); + printf(BCYN "validation: "); break; } case VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT: { - printf("performance:"); + printf(BMAG "performance:"); break; } default: @@ -55,7 +57,7 @@ VKAPI_ATTR VkBool32 VKAPI_CALL vulkan_debug_callback( } } - printf("%s\n", pCallbackData->pMessage); + printf(CRESET "%s\n", pCallbackData->pMessage); return VK_FALSE; } diff --git a/src/render/vulkan/device.c b/src/render/vulkan/device.c index 138971b..ceb7bb7 100644 --- a/src/render/vulkan/device.c +++ b/src/render/vulkan/device.c @@ -1,30 +1,53 @@ #include #include +#include +#include #include #include #include #include -static QueueFamilyIndices vulkan_find_queue_family(VkPhysicalDevice dev) +static QueueFamilyIndices vulkan_find_queue_family(VulkanCtx *self, VkPhysicalDevice dev) { - QueueFamilyIndices idx = (QueueFamilyIndices){.index = 0, ._present = false}; - + QueueFamilyIndices idx = {}; vec_t(VkQueueFamilyProperties) queue_famiy_properties = {}; vec_init(&queue_famiy_properties); uint32_t queue_family_count = 0; vkGetPhysicalDeviceQueueFamilyProperties(dev, &queue_family_count, NULL); + if (queue_family_count == 0) + { + return idx; + } + vec_reserve(&queue_famiy_properties, queue_family_count); - vkGetPhysicalDeviceQueueFamilyProperties(dev, &queue_family_count, queue_famiy_properties.data); + vkGetPhysicalDeviceQueueFamilyProperties(dev, &queue_family_count, + queue_famiy_properties.data); for (size_t i = 0; i < queue_family_count; i++) { VkQueueFamilyProperties curr = queue_famiy_properties.data[i]; if (curr.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - idx.index = i; + idx.family_idx = i; idx._present = true; + VkBool32 present_support; + + vkGetPhysicalDeviceSurfaceSupportKHR(dev, idx.family_idx, self->surface, &present_support); + + if (present_support) + { + idx._has_present_family = true; + idx.present_family = i; + + vec_deinit(&queue_famiy_properties); + return idx; + } + } + else + { + idx._present = false; } } @@ -32,22 +55,41 @@ static QueueFamilyIndices vulkan_find_queue_family(VkPhysicalDevice dev) return idx; } -static QueueFamilyIndices vulkan_pick_queue_family(VulkanCtx *self) +QueueFamilyIndices vulkan_pick_queue_family(VulkanCtx *self) { - return vulkan_find_queue_family(self->device); + + QueueFamilyIndices idx = vulkan_find_queue_family(self, self->physical_device); + return idx; } -static bool vulkan_is_device_suitable(VkPhysicalDevice device) +static bool vulkan_is_device_suitable(VulkanCtx *self, VkPhysicalDevice device) { VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(device, &properties); VkPhysicalDeviceFeatures features; vkGetPhysicalDeviceFeatures(device, &features); - QueueFamilyIndices idx = vulkan_find_queue_family(device); + QueueFamilyIndices idx = vulkan_find_queue_family(self, device); - return properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && - features.geometryShader && idx._present; + if (properties.deviceType != VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU || + !features.geometryShader || + !idx._present || + !idx._has_present_family || + !vulkan_check_device_extensions(device)) + { + return false; + } + + SwapChainSupportDetails swapchain = swap_chain_support_query(self, device); + + if (swapchain.formats.length == 0 || swapchain.modes.length == 0) + { + swap_chain_support_deinit(&swapchain); + return false; + } + + swap_chain_support_deinit(&swapchain); + return true; } void vulkan_pick_physical_device(VulkanCtx *self) @@ -72,7 +114,7 @@ void vulkan_pick_physical_device(VulkanCtx *self) VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(devices.data[i], &properties); printf("device[%u]: %s \n", i, properties.deviceName); - if (vulkan_is_device_suitable(devices.data[i])) + if (vulkan_is_device_suitable(self, devices.data[i])) { device = devices.data[i]; break; @@ -81,7 +123,13 @@ void vulkan_pick_physical_device(VulkanCtx *self) vec_deinit(&devices); - self->device = device; + if (device == VK_NULL_HANDLE) + { + printf("no device founded\n!"); + exit(-1); + return; + } + self->physical_device = device; vulkan_pick_queue_family(self); } diff --git a/src/render/vulkan/device.h b/src/render/vulkan/device.h index 0c08c85..6bd802d 100644 --- a/src/render/vulkan/device.h +++ b/src/render/vulkan/device.h @@ -1,12 +1,17 @@ #pragma once +#include #include #include typedef struct { - uint32_t index; + uint32_t family_idx; + uint32_t present_family; bool _present; + bool _has_present_family; } QueueFamilyIndices; void vulkan_pick_physical_device(VulkanCtx *self); + +QueueFamilyIndices vulkan_pick_queue_family(VulkanCtx *self); diff --git a/src/render/vulkan/glfw_vulkan_handle.c b/src/render/vulkan/glfw_vulkan_handle.c new file mode 100644 index 0000000..9922255 --- /dev/null +++ b/src/render/vulkan/glfw_vulkan_handle.c @@ -0,0 +1,38 @@ +#define VK_USE_PLATFORM_XLIB_KHR +#define GLFW_INCLUDE_VULKAN +#include +#define GLFW_EXPOSE_NATIVE_X11 +#include +#include +#include + +VkXlibSurfaceCreateInfoKHR glfw_vulkan_handle(GLFWwindow *window) +{ + VkXlibSurfaceCreateInfoKHR sinfo = { + .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, + .dpy = glfwGetX11Display(), + .window = glfwGetX11Window(window), + .pNext = NULL, + }; + return sinfo; +} +int vulkan_render_surface_init(VulkanCtx *self, uintptr_t handle) +{ + VkXlibSurfaceCreateInfoKHR sinfo = glfw_vulkan_handle((GLFWwindow *)handle); + vulkan_assert_success$(vkCreateXlibSurfaceKHR(self->instance, &sinfo, NULL, &self->surface)); + + // vulkan_assert_success$(glfwCreateWindowSurface(self->instance, (GLFWwindow *)handle, NULL, &self->surface)); + return 0; +} +int vulkan_render_surface_deinit(VulkanCtx *self) +{ + + vkDestroySurfaceKHR(self->instance, self->surface, NULL); + return 0; +} + +void vulkan_render_surface_target_size(VulkanCtx *self, uintptr_t handle, int *width, int *height) +{ + (void)self; + glfwGetFramebufferSize((GLFWwindow *)handle, width, height); +} diff --git a/src/render/vulkan/layer.c b/src/render/vulkan/layer.c index fdd7776..9a6d030 100644 --- a/src/render/vulkan/layer.c +++ b/src/render/vulkan/layer.c @@ -50,3 +50,9 @@ bool vulkan_load_validation_layer(VkInstanceCreateInfo *create) return true; } + +void vulkan_load_validation_layer_device(VkDeviceCreateInfo *info) +{ + info->enabledLayerCount = sizeof(enabled_layers) / sizeof(enabled_layers[0]); + info->ppEnabledLayerNames = enabled_layers; +} diff --git a/src/render/vulkan/layer.h b/src/render/vulkan/layer.h index f6bc9a0..d1a2f49 100644 --- a/src/render/vulkan/layer.h +++ b/src/render/vulkan/layer.h @@ -1,5 +1,7 @@ #pragma once -#include #include +#include + +bool vulkan_load_validation_layer(VkInstanceCreateInfo *create); -bool vulkan_load_validation_layer(VkInstanceCreateInfo* create); +void vulkan_load_validation_layer_device(VkDeviceCreateInfo *info); diff --git a/src/render/vulkan/logical.c b/src/render/vulkan/logical.c new file mode 100644 index 0000000..36d7fcf --- /dev/null +++ b/src/render/vulkan/logical.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include + +const char *device_required_exts[] = { + VK_KHR_SWAPCHAIN_EXTENSION_NAME, +}; + +bool vulkan_check_device_extensions(VkPhysicalDevice device) +{ + uint32_t extensions_count = 0; + vkEnumerateDeviceExtensionProperties(device, NULL, &extensions_count, NULL); + + vec_t(VkExtensionProperties) availableExtensions; + vec_init(&availableExtensions); + vec_reserve(&availableExtensions, extensions_count); + availableExtensions.length = extensions_count; + + vkEnumerateDeviceExtensionProperties(device, NULL, &extensions_count, availableExtensions.data); + + for (size_t i = 0; i < sizeof(device_required_exts) / sizeof(device_required_exts[0]); i++) + { + bool found = false; + for (int j = 0; j < availableExtensions.length; j++) + { + + if (strcmp(device_required_exts[i], availableExtensions.data[j].extensionName) == 0) + { + found = true; + break; + } + } + + if (!found) + { + return false; + } + } + + return true; +} +void vulkan_logical_device_init(VulkanCtx *ctx) +{ + float priority = 1.0f; + + vec_t(VkDeviceQueueCreateInfo) queue_create_infos = {}; + vec_t(uint32_t) queue_create_idx = {}; + + vec_init(&queue_create_idx); + vec_init(&queue_create_infos); + + QueueFamilyIndices idx = vulkan_pick_queue_family(ctx); + vec_push(&queue_create_idx, idx.family_idx); + + if (idx._has_present_family) + { + vec_push(&queue_create_idx, idx.present_family); + } + + uint32_t queue_idx = 0; + (void)queue_idx; + int i = 0; + vec_foreach(&queue_create_idx, queue_idx, i) + { + VkDeviceQueueCreateInfo queue_create_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, + .queueFamilyIndex = i, + .queueCount = 1, + .pQueuePriorities = &priority, + }; + + vec_push(&queue_create_infos, queue_create_info); + } + + VkPhysicalDeviceFeatures features = {}; + + VkDeviceCreateInfo create_info = { + .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, + .pQueueCreateInfos = queue_create_infos.data, + .queueCreateInfoCount = queue_create_infos.length, + .enabledExtensionCount = sizeof(device_required_exts) / sizeof(device_required_exts[0]), + .ppEnabledExtensionNames = device_required_exts, + .pEnabledFeatures = &features, + }; + + vulkan_load_validation_layer_device(&create_info); + vulkan_assert_success$(vkCreateDevice(ctx->physical_device, &create_info, NULL, &ctx->logical_device)); + + vkGetDeviceQueue(ctx->logical_device, idx.family_idx, 0, &ctx->gfx_queue); + + vkGetDeviceQueue(ctx->logical_device, idx.present_family, 0, &ctx->present_queue); + + vec_deinit(&queue_create_infos); + vec_deinit(&queue_create_idx); +} + +void vulkan_logical_device_deinit(VulkanCtx *ctx) +{ + vkDestroyDevice(ctx->logical_device, NULL); +} diff --git a/src/render/vulkan/logical.h b/src/render/vulkan/logical.h new file mode 100644 index 0000000..e8f1b4e --- /dev/null +++ b/src/render/vulkan/logical.h @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +void vulkan_logical_device_init(VulkanCtx *ctx); + +void vulkan_logical_device_deinit(VulkanCtx *ctx); + +bool vulkan_check_device_extensions(VkPhysicalDevice device); diff --git a/src/render/vulkan/render.c b/src/render/vulkan/render.c index 75c6b8b..5651470 100644 --- a/src/render/vulkan/render.c +++ b/src/render/vulkan/render.c @@ -1,27 +1,41 @@ +#include +#include #include - -#include +#include +#include #include -#include +#include #include -#include +#include typedef struct { - void* _dummy; + void *_dummy; } RenderImpl; VulkanCtx ctx = {}; vec_t(RenderImpl) impls = {}; -int render_engine_init(void) +int render_surface_init(Render *self, uintptr_t handle) { - vulkan_init(&ctx); + (void)self; + return vulkan_render_surface_init(&ctx, handle); +} +int render_surface_deinit(Render *self, uintptr_t handle) +{ + (void)self; + (void)handle; + return vulkan_render_surface_deinit(&ctx); +} + +int render_engine_init(Window *window) +{ + vulkan_init(&ctx, window_raw_handle(window)); vec_init(&impls); return 0; } -int render_init(Render* self) +int render_init(Render *self) { *self = (Render){}; @@ -33,14 +47,15 @@ int render_init(Render* self) return impls.length - 1; } -int render_deinit(MAYBE_UNUSED Render* self) +int render_deinit(MAYBE_UNUSED Render *self) { return 0; } int render_engine_deinit(void) { - vec_deinit(&impls); vulkan_deinit(&ctx); + + vec_deinit(&impls); return 0; } diff --git a/src/render/vulkan/surface.h b/src/render/vulkan/surface.h new file mode 100644 index 0000000..bdfbc70 --- /dev/null +++ b/src/render/vulkan/surface.h @@ -0,0 +1,8 @@ +#pragma once +#include + +int vulkan_render_surface_deinit(VulkanCtx *self); + +int vulkan_render_surface_init(VulkanCtx *self, uintptr_t handle); + +void vulkan_render_surface_target_size(VulkanCtx *self, uintptr_t handle, int *width, int *height); diff --git a/src/render/vulkan/swapchain.c b/src/render/vulkan/swapchain.c new file mode 100644 index 0000000..a927b67 --- /dev/null +++ b/src/render/vulkan/swapchain.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +void swap_chain_support_deinit(SwapChainSupportDetails *self) +{ + vec_deinit(&self->formats); + vec_deinit(&self->modes); +} + +// query modes & formats +SwapChainSupportDetails swap_chain_support_query(VulkanCtx *self, VkPhysicalDevice device) +{ + SwapChainSupportDetails details = {}; + vec_init(&details.modes); + vec_init(&details.formats); + + vulkan_assert_success$(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, self->surface, &details.capabilities)); + + uint32_t format_count = 0; + vulkan_assert_success$(vkGetPhysicalDeviceSurfaceFormatsKHR(device, self->surface, &format_count, NULL)); + + if (format_count != 0) + { + vec_reserve(&details.formats, format_count); + details.formats.length = format_count; + vulkan_assert_success$(vkGetPhysicalDeviceSurfaceFormatsKHR(device, self->surface, &format_count, details.formats.data)); + } + else + { + printf("no format mode! \n"); + } + + uint32_t present_mode_count = 0; + vulkan_assert_success$(vkGetPhysicalDeviceSurfacePresentModesKHR(device, self->surface, &present_mode_count, NULL)); + + if (present_mode_count != 0) + { + vec_reserve(&details.modes, present_mode_count); + details.modes.length = present_mode_count; + vulkan_assert_success$(vkGetPhysicalDeviceSurfacePresentModesKHR(device, self->surface, &present_mode_count, + details.modes.data)); + } + else + { + printf("no present mode! \n"); + } + + return details; +} + +VkSurfaceFormatKHR swap_chain_get_best_format(SwapChainSupportDetails *self) +{ + if (self->formats.length == 1 && self->formats.data[0].format == VK_FORMAT_UNDEFINED) + { + return (VkSurfaceFormatKHR){ + .format = VK_FORMAT_B8G8R8A8_SRGB, + .colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR, + }; + } + + for (int i = 0; i < self->formats.length; ++i) + { + if (self->formats.data[i].format == VK_FORMAT_B8G8R8A8_SRGB && + self->formats.data[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + return self->formats.data[i]; + } + } + + return self->formats.data[0]; +} + +VkPresentModeKHR swap_chain_get_best_present_mode(SwapChainSupportDetails *self) +{ + + for (int i = 0; i < self->modes.length; ++i) + { + if (self->modes.data[i] == VK_PRESENT_MODE_MAILBOX_KHR) + { + return self->modes.data[i]; + } + } + + return VK_PRESENT_MODE_FIFO_KHR; +} + +VkExtent2D swap_chain_get_best_extent(SwapChainSupportDetails *self, int width, int height) +{ + if (self->capabilities.currentExtent.width != UINT32_MAX) + { + return self->capabilities.currentExtent; + } + else + { + VkExtent2D actual_extent = { + .width = clamp(self->capabilities.minImageExtent.width, + self->capabilities.maxImageExtent.width, (uint32_t)width), + .height = clamp(self->capabilities.minImageExtent.height, + self->capabilities.maxImageExtent.height, (uint32_t)height), + }; + + return actual_extent; + } +} + +void vulkan_swapchain_init(VulkanCtx *self, int width, int height) +{ + SwapChainSupportDetails details = swap_chain_support_query(self, self->physical_device); + + VkSurfaceFormatKHR surface_format = swap_chain_get_best_format(&details); + VkPresentModeKHR present_mode = swap_chain_get_best_present_mode(&details); + VkExtent2D extent = swap_chain_get_best_extent(&details, width, height); + + self->image_cnt = details.capabilities.minImageCount + 1; + + VkSwapchainCreateInfoKHR swapchain_info = { + .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, + .surface = self->surface, + .minImageCount = self->image_cnt, + .imageFormat = surface_format.format, + .imageColorSpace = surface_format.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + .preTransform = details.capabilities.currentTransform, + .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, + .presentMode = present_mode, + .clipped = VK_TRUE, + .oldSwapchain = VK_NULL_HANDLE, + }; + + QueueFamilyIndices indices = vulkan_pick_queue_family(self); + uint32_t queueFamilyIndices[] = {indices.family_idx, indices.present_family}; + + if (indices.family_idx != indices.present_family) + { + swapchain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + swapchain_info.queueFamilyIndexCount = 2; + swapchain_info.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + swapchain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + swapchain_info.queueFamilyIndexCount = 0; // Optional + swapchain_info.pQueueFamilyIndices = NULL; // Optional + } + + vulkan_assert_success$(vkCreateSwapchainKHR(self->logical_device, &swapchain_info, NULL, &self->swapchain)); + + swap_chain_support_deinit(&details); +} + +void vulkan_swapchain_deinit(VulkanCtx *self) +{ + vkDestroySwapchainKHR(self->logical_device, self->swapchain, NULL); +} diff --git a/src/render/vulkan/swapchain.h b/src/render/vulkan/swapchain.h new file mode 100644 index 0000000..b17c113 --- /dev/null +++ b/src/render/vulkan/swapchain.h @@ -0,0 +1,30 @@ +#pragma once +#include +#include +#include + +// the swapchain is like a collection of framebuffers + +typedef vec_t(VkSurfaceFormatKHR) VulkanFormats; +typedef vec_t(VkPresentModeKHR) VulkanPresentModes; + +typedef struct +{ + VkSurfaceCapabilitiesKHR capabilities; + VulkanFormats formats; + VulkanPresentModes modes; +} SwapChainSupportDetails; + +void swap_chain_support_deinit(SwapChainSupportDetails *self); + +SwapChainSupportDetails swap_chain_support_query(VulkanCtx *self, VkPhysicalDevice device); + +VkSurfaceFormatKHR swap_chain_get_best_format(SwapChainSupportDetails *self); + +VkPresentModeKHR swap_chain_get_best_present_mode(SwapChainSupportDetails *self); + +VkExtent2D swap_chain_get_best_extent(SwapChainSupportDetails *self, int width, int height); + +void vulkan_swapchain_init(VulkanCtx *self, int width, int height); + +void vulkan_swapchain_deinit(VulkanCtx *self); diff --git a/src/render/vulkan/vulkan.c b/src/render/vulkan/vulkan.c index f219562..e60c968 100644 --- a/src/render/vulkan/vulkan.c +++ b/src/render/vulkan/vulkan.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -47,6 +50,7 @@ static int vulkan_query_extension(VulkanCtx *self, VkInstanceCreateInfo *info) { vec_push(&self->exts, VK_EXT_DEBUG_UTILS_EXTENSION_NAME); } + vec_push(&self->exts, "VK_KHR_xlib_surface"); info->enabledExtensionCount = self->exts.length; info->ppEnabledExtensionNames = self->exts.data; @@ -85,7 +89,22 @@ int vulkan_create_instance(VulkanCtx *self) return 0; } -int vulkan_init(VulkanCtx *self) +static int vulkan_device_init(VulkanCtx *self) +{ + + if (ENABLE_VALIDATION_LAYERS) + { + + vulkan_debug_init(self); + } + + vulkan_pick_physical_device(self); + + vulkan_logical_device_init(self); + return 0; +} + +int vulkan_init(VulkanCtx *self, uintptr_t window_handle) { *self = (VulkanCtx){ .app_info = (VkApplicationInfo){ @@ -93,8 +112,8 @@ int vulkan_init(VulkanCtx *self) .pApplicationName = "compute-tracer", .applicationVersion = VK_MAKE_VERSION(1, 0, 0), .pEngineName = "none", - .engineVersion = VK_MAKE_VERSION(1, 0, 3), - .apiVersion = VK_MAKE_VERSION(1, 0, 3), + .engineVersion = VK_MAKE_VERSION(1, 0, 0), + .apiVersion = VK_MAKE_VERSION(1, 0, 0), .pNext = NULL, }, .instance = 0, @@ -104,22 +123,29 @@ int vulkan_init(VulkanCtx *self) vulkan_create_instance(self); - if (ENABLE_VALIDATION_LAYERS) - { + vulkan_render_surface_init(self, window_handle); - vulkan_debug_init(self); - } + vulkan_device_init(self); + + int width, height; + vulkan_render_surface_target_size(self, window_handle, &width, &height); + vulkan_swapchain_init(self, width, height); - vulkan_pick_physical_device(self); return 0; } int vulkan_deinit(VulkanCtx *self) { + vulkan_swapchain_deinit(self); + + vulkan_render_surface_deinit(self); + + vulkan_logical_device_deinit(self); if (ENABLE_VALIDATION_LAYERS) { vulkan_debug_deinit(self); } + vkDestroyInstance(self->instance, NULL); vec_deinit(&self->exts); return 0; diff --git a/src/render/vulkan/vulkan.h b/src/render/vulkan/vulkan.h index 455c4b2..cb480d4 100644 --- a/src/render/vulkan/vulkan.h +++ b/src/render/vulkan/vulkan.h @@ -3,26 +3,44 @@ #define GLFW_INCLUDE_VULKAN #include #include +#include +#include typedef vec_t(const char *) VulkanExts; +// I may split this structure in multiple one, like one for the device etc... But I'm not really trying to make a game engine, so for the moment I don't see the point of doing it. +// Just keep in mind that this structure should be reworked. + typedef struct { VkApplicationInfo app_info; VkInstance instance; - VkPhysicalDevice device; + VkPhysicalDevice physical_device; + VkDevice logical_device; + VkQueue gfx_queue; + VkQueue present_queue; VulkanExts exts; - + VkSwapchainKHR swapchain; VkDebugUtilsMessengerEXT debug_messenger; + + VkSurfaceKHR surface; + + uint32_t image_cnt; + } VulkanCtx; -int vulkan_init(VulkanCtx *self); +int vulkan_init(VulkanCtx *self, uintptr_t window_handle); int vulkan_deinit(VulkanCtx *self); -#define vulkan_assert_success$(X) \ - if ((X) != VK_SUCCESS) \ - { \ - printf(#X "was not successful ! \n"); \ - abort(); \ - } +#define vulkan_assert_success$(X) \ + ({ \ + __auto_type r = (X); \ + if ((r) != VK_SUCCESS) \ + { \ + printf(__FILE__ " %i " \ + " " #X " was not successful (error: %i) ! \n", \ + __LINE__, r); \ + abort(); \ + } \ + }) diff --git a/src/utils.h b/src/utils.h index bc66fd8..5ea9c73 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,3 +1,13 @@ -#pragma once +#pragma once #define MAYBE_UNUSED [[maybe_unused]] + +#define clamp(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x))) + +#define clamp_s(x, min, max) ({ \ + __auto_type __x_val = (x); \ + __auto_type __min_val = (min); \ + __auto_type __max_val = (max); \ + __auto_type r = clamp(__x_val, __min_val, __max_val); \ + r; \ +}) diff --git a/src/window/glfw_window.c b/src/window/glfw_window.c index 05b2a89..e608466 100644 --- a/src/window/glfw_window.c +++ b/src/window/glfw_window.c @@ -1,7 +1,7 @@ - #include #include #include +#include #include #include #include @@ -13,7 +13,7 @@ typedef struct GLFWwindow *window; } WindowImpl; -vec_t(WindowImpl) windows; +vec_t(WindowImpl) windows = {}; int window_engine_init(void) { @@ -49,6 +49,25 @@ int window_engine_deinit(void) return 0; } +int window_surface_init(Window *self, Render *render) +{ + render_surface_init(render, (uintptr_t)windows.data[self->window_id].window); + + return 0; +} + +int window_surface_deinit(Window *self, Render *render) +{ + render_surface_deinit(render, (uintptr_t)windows.data[self->window_id].window); + + return 0; +} + +uintptr_t window_raw_handle(Window *self) +{ + return (uintptr_t)windows.data[self->window_id].window; +} + /* int window_width(Window *self) { diff --git a/src/window/surface.h b/src/window/surface.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/src/window/surface.h @@ -0,0 +1 @@ +#pragma once diff --git a/src/window/window.h b/src/window/window.h index e55eb9e..57f3c14 100644 --- a/src/window/window.h +++ b/src/window/window.h @@ -1,8 +1,7 @@ #pragma once -#include #include - +#include typedef struct { uint8_t window_id; @@ -20,6 +19,8 @@ int window_width(Window *self); int window_height(Window *self); -bool window_should_close(Window* self); +bool window_should_close(Window *self); + +int window_update(Window *self); -int window_update(Window* self); +uintptr_t window_raw_handle(Window *self);