const std = @import("std"); const glfw = @import("zglfw"); const vk = @import("vulkan"); const context = @import("context.zig"); const device = @import("device.zig"); pub const SwapchainContext = struct { swapchain: vk.SwapchainKHR, images: []vk.Image, image_views: []vk.ImageView, format: vk.SurfaceFormatKHR, present_mode: vk.PresentModeKHR, extent: vk.Extent2D, image_count: u32, allocator: std.mem.Allocator, pub fn destroy(self: *const SwapchainContext, ldc: *const device.LogicalDeviceContext) void { for (self.image_views) |image_view| { ldc.vkd.destroyImageView(ldc.device, image_view, null); } self.allocator.free(self.image_views); self.allocator.free(self.images); ldc.vkd.destroySwapchainKHR(ldc.device, self.swapchain, null); } }; pub fn initSwapchain( vc: context.VulkanContext, ldc: device.LogicalDeviceContext, surface: vk.SurfaceKHR, window: *glfw.Window, allocator: std.mem.Allocator, ) !SwapchainContext { const surface_caps = try vc.vki.getPhysicalDeviceSurfaceCapabilitiesKHR( ldc.physical_device, surface, ); std.debug.print( "surface current extent: {}x{}\n", .{ surface_caps.current_extent.width, surface_caps.current_extent.height, }, ); std.debug.print( "surface min/max image count: {}/{}\n", .{ surface_caps.min_image_count, surface_caps.max_image_count, }, ); const surface_formats = try vc.vki.getPhysicalDeviceSurfaceFormatsAllocKHR( ldc.physical_device, surface, allocator, ); defer allocator.free(surface_formats); const present_modes = try vc.vki.getPhysicalDeviceSurfacePresentModesAllocKHR( ldc.physical_device, surface, allocator, ); defer allocator.free(present_modes); var chosen_surface_format = surface_formats[0]; for (surface_formats) |format| { if (format.format == .b8g8r8a8_srgb and format.color_space == .srgb_nonlinear_khr) { chosen_surface_format = format; break; } } var chosen_present_mode: vk.PresentModeKHR = .fifo_khr; for (present_modes) |mode| { if (mode == .fifo_khr) { chosen_present_mode = mode; break; } } const framebuffer_size = window.getFramebufferSize(); const chosen_extent = if (surface_caps.current_extent.width != std.math.maxInt(u32)) surface_caps.current_extent else vk.Extent2D{ .width = @intCast(framebuffer_size[0]), .height = @intCast(framebuffer_size[1]), }; var chosen_image_count = surface_caps.min_image_count + 1; if (surface_caps.max_image_count != 0 and chosen_image_count > surface_caps.max_image_count) { chosen_image_count = surface_caps.max_image_count; } std.debug.print( "chosen swapchain format={any}, color_space={any}\n", .{ chosen_surface_format.format, chosen_surface_format.color_space }, ); std.debug.print("chosen present mode={any}\n", .{chosen_present_mode}); std.debug.print( "chosen extent={}x{}\n", .{ chosen_extent.width, chosen_extent.height }, ); std.debug.print("chosen image count={}\n", .{chosen_image_count}); const swapchain_create_info = vk.SwapchainCreateInfoKHR{ .surface = surface, .min_image_count = chosen_image_count, .image_format = chosen_surface_format.format, .image_color_space = chosen_surface_format.color_space, .image_extent = chosen_extent, .image_array_layers = 1, .image_usage = .{ .color_attachment_bit = true, }, .image_sharing_mode = .exclusive, .pre_transform = surface_caps.current_transform, .composite_alpha = .{ .opaque_bit_khr = true, }, .present_mode = chosen_present_mode, .clipped = .true, }; const swapchain = try ldc.vkd.createSwapchainKHR(ldc.device, &swapchain_create_info, null); errdefer ldc.vkd.destroySwapchainKHR(ldc.device, swapchain, null); std.debug.print("created swapchain\n", .{}); const swapchain_images = try ldc.vkd.getSwapchainImagesAllocKHR( ldc.device, swapchain, allocator, ); errdefer allocator.free(swapchain_images); std.debug.print("swapchain images: {}\n", .{swapchain_images.len}); const swapchain_image_views = try allocator.alloc(vk.ImageView, swapchain_images.len); errdefer allocator.free(swapchain_image_views); var created_image_view_count: usize = 0; errdefer { for (swapchain_image_views[0..created_image_view_count]) |image_view| { ldc.vkd.destroyImageView(ldc.device, image_view, null); } } for (swapchain_images, 0..) |image, i| { const image_view_create_info = vk.ImageViewCreateInfo{ .image = image, .view_type = .@"2d", .format = chosen_surface_format.format, .components = .{ .r = .identity, .g = .identity, .b = .identity, .a = .identity, }, .subresource_range = .{ .aspect_mask = .{ .color_bit = true, }, .base_mip_level = 0, .level_count = 1, .base_array_layer = 0, .layer_count = 1, }, }; swapchain_image_views[i] = try ldc.vkd.createImageView( ldc.device, &image_view_create_info, null, ); created_image_view_count += 1; } std.debug.print("created swapchain image views: {}\n", .{swapchain_image_views.len}); return .{ .swapchain = swapchain, .images = swapchain_images, .image_views = swapchain_image_views, .format = chosen_surface_format, .present_mode = chosen_present_mode, .extent = chosen_extent, .image_count = chosen_image_count, .allocator = allocator, }; }