1 #include <kiba/gpu/vulkan/surface.h>
3 #include <kiba/containers/array.h>
4 #include <kiba/gpu/command.h>
5 #include <kiba/gpu/surface.h>
6 #include <kiba/gpu/vulkan/allocator.h>
7 #include <kiba/gpu/vulkan/conv.h>
8 #include <kiba/gpu/vulkan/device.h>
9 #include <kiba/gpu/vulkan/instance.h>
10 #include <kiba/gpu/vulkan/queue.h>
11 #include <kiba/gpu/vulkan/util.h>
13 void vk_surface_destroy(VkSurfaceKHR *surface) {
14 if (*surface != VK_NULL_HANDLE) {
15 vkDestroySurfaceKHR(vk_instance.raw, *surface, &
vk_alloc.vulkan_callbacks);
16 *surface = VK_NULL_HANDLE;
18 KB_WARN(
"tried to destroy uninitialized surface");
23 return vk_surface_create(&surface->raw, window_data);
26 void gpu_backend_surface_destroy(
struct gpu_backend_surface *surface) { vk_surface_destroy(&surface->raw); }
30 enum gpu_texture_format format) {
31 u32 available_format_count = 0;
32 VK_CALL_B8(vkGetPhysicalDeviceSurfaceFormatsKHR(device.physical, surface->raw, &available_format_count, 0));
33 array_of(VkSurfaceFormatKHR) available_formats =
34 array_create(VkSurfaceFormatKHR, available_format_count, &
vk_alloc.kiba_alloc);
35 array_resize(&available_formats, available_format_count);
36 if (available_formats ==
KB_NULL) {
37 KB_ERROR(
"could not create array to store available swap chain formats");
40 VK_CALL_B8(vkGetPhysicalDeviceSurfaceFormatsKHR(device.physical,
42 &available_format_count,
45 b8 found_format =
false;
46 array_for_each(VkSurfaceFormatKHR, surface_format, available_formats) {
47 if (format == vk_convert_vk_surface_format(*surface_format)) {
53 array_destroy(&available_formats);
57 static b8 vk_verify_swap_chain_present_mode_availability(
struct gpu_backend_surface *surface,
59 enum gpu_present_mode present_mode) {
60 u32 available_present_mode_count = 0;
62 vkGetPhysicalDeviceSurfacePresentModesKHR(device.physical, surface->raw, &available_present_mode_count, 0));
63 array_of(VkPresentModeKHR) available_present_modes =
64 array_create(VkPresentModeKHR, available_present_mode_count, &
vk_alloc.kiba_alloc);
65 array_resize(&available_present_modes, available_present_mode_count);
66 if (available_present_modes ==
KB_NULL) {
67 KB_ERROR(
"could not create array to store available swap chain present modes");
70 VK_CALL_B8(vkGetPhysicalDeviceSurfacePresentModesKHR(device.physical,
72 &available_present_mode_count,
73 available_present_modes));
75 VkPresentModeKHR target = vk_convert_present_mode(present_mode);
76 b8 found_present_mode =
false;
77 array_for_each(VkPresentModeKHR, available_present_mode, available_present_modes) {
78 if (*available_present_mode == target) {
79 found_present_mode =
true;
84 array_destroy(&available_present_modes);
85 return found_present_mode;
91 VkSurfaceCapabilitiesKHR capabilities;
92 VK_CALL_B8(vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device.physical, surface->raw, &capabilities));
93 if (capabilities.currentExtent.width == UINT_MAX) {
94 surface->extent.height =
95 KB_CLAMP(config.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height);
96 surface->extent.width =
97 KB_CLAMP(config.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width);
99 surface->extent = capabilities.currentExtent;
101 u32 image_count = capabilities.minImageCount;
102 if (capabilities.maxImageCount > capabilities.minImageCount) {
105 surface->image_count = image_count;
110 if (surface->swap_chain != VK_NULL_HANDLE) {
111 vkDestroySwapchainKHR(device.logical, surface->swap_chain, &
vk_alloc.vulkan_callbacks);
112 surface->swap_chain = VK_NULL_HANDLE;
114 KB_WARN(
"tried to destroy uninitialized swap chain");
122 if (!vk_verify_swap_chain_format_availability(surface, device, config.format)) {
123 KB_INFO(
"did not find required swap chain format");
126 if (!vk_verify_swap_chain_present_mode_availability(surface, device, config.present_mode)) {
127 KB_INFO(
"did not find required swap chain present mode");
130 if (!vk_query_swap_chain_capabilities(surface, device, config)) {
131 KB_INFO(
"could not query swap chain capabilities");
136 VkSwapchainCreateInfoKHR swap_chain_info = {
137 .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
138 .surface = surface->raw,
139 .imageExtent = surface->extent,
140 .minImageCount = surface->image_count,
141 .imageFormat = vk_convert_texture_format(config.format),
142 .imageColorSpace = config.format == GPU_TEXTURE_FORMAT_RGBA16_FLOAT ? VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT
143 : VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
144 .presentMode = vk_convert_present_mode(config.present_mode),
145 .imageArrayLayers = 1,
146 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
147 .preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
148 .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
150 .oldSwapchain = surface->swap_chain,
152 u32 queue_family_indices[] = {device.graphics_queue.index, device.present_queue.index};
154 if (device.graphics_queue.index != device.present_queue.index) {
155 swap_chain_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
156 swap_chain_info.queueFamilyIndexCount = 2;
157 swap_chain_info.pQueueFamilyIndices = queue_family_indices;
159 swap_chain_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
162 VkSwapchainKHR new_swapchain = VK_NULL_HANDLE;
163 VK_CALL_B8(vkCreateSwapchainKHR(device.logical, &swap_chain_info, &
vk_alloc.vulkan_callbacks, &new_swapchain));
164 if (surface->swap_chain != VK_NULL_HANDLE) {
166 swap_chain_destroy(surface, device);
168 surface->swap_chain = new_swapchain;
172 VK_CALL_B8(vkGetSwapchainImagesKHR(device.logical, surface->swap_chain, &image_count, 0));
173 KB_ASSERT(image_count <= 3,
"address todo of the structure");
174 surface->image_count = image_count;
175 VK_CALL_B8(vkGetSwapchainImagesKHR(device.logical, surface->swap_chain, &image_count, surface->images));
182 vkQueueWaitIdle(device->graphics_queue.queue);
183 if (surface->fc_image_aquire == VK_NULL_HANDLE) {
184 VkFenceCreateInfo fc_create_info = {
185 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
186 .flags = VK_FENCE_CREATE_SIGNALED_BIT,
189 vkCreateFence(device->logical, &fc_create_info, &
vk_alloc.vulkan_callbacks, &surface->fc_image_aquire));
192 return swap_chain_create(surface, *device, config);
197 swap_chain_destroy(surface, *device);
198 if (surface->fc_image_aquire != VK_NULL_HANDLE) {
199 vkDestroyFence(device->logical, surface->fc_image_aquire, &
vk_alloc.vulkan_callbacks);
200 surface->fc_image_aquire = VK_NULL_HANDLE;
209 VK_CALL_ASSERT(vkResetFences(device->logical, 1, &surface->fc_image_aquire));
210 VkResult res = vkAcquireNextImageKHR(device->logical,
214 surface->fc_image_aquire,
216 VK_CALL_ASSERT(vkWaitForFences(device->logical, 1, &surface->fc_image_aquire, VK_TRUE, UINT64_MAX));
217 VK_CALL_ASSERT(vkResetFences(device->logical, 1, &surface->fc_image_aquire));
218 if (res == VK_NOT_READY || res == VK_SUBOPTIMAL_KHR || res == VK_ERROR_OUT_OF_DATE_KHR) {
222 if (res == VK_SUCCESS) {
223 texture->raw = surface->images[image_index];
224 surface->presentation_image_index = image_index;
225 KB_DEBUG(
"using tex {pointer} at index {u32}", texture->raw, surface->presentation_image_index);
236 VkResult res = vk_queue_present_surface(surface, device);
237 if (res == VK_ERROR_OUT_OF_DATE_KHR || res == VK_SUBOPTIMAL_KHR) {
241 return res == VK_SUCCESS;
#define UNUSED(x)
Mark parameter as unused.
#define KB_CLAMP(x, min, max)
Clamp an input value to a certain range.
#define KB_NULL
Value of an invalid ptr (nullptr).
#define KB_DEBUG(...)
Log entry with debug log level.
#define KB_ASSERT(expr,...)
Perform runtime assertion and log failures.
#define KB_WARN(...)
Log entry with warn log level.
#define KB_ERROR(...)
Log entry with error log level.
#define KB_INFO(...)
Log entry with info log level.