diff --git a/src/Uber.zig b/src/Uber.zig index b1f59f8..702aa3c 100644 --- a/src/Uber.zig +++ b/src/Uber.zig @@ -1,5 +1,4 @@ const std = @import("std"); -const au = @import("au.zig"); const vk = @import("vk"); const shaders = @import("shaders"); diff --git a/src/nu/Render/au.zig b/src/nu/Render/au.zig deleted file mode 100644 index e12cbf5..0000000 --- a/src/nu/Render/au.zig +++ /dev/null @@ -1,395 +0,0 @@ -const std = @import("std"); -const builtin = @import("builtin"); - -const vk = @import("vk"); -const nu = @import("../../nu.zig"); - -pub const SwapChain = @import("au/SwapChain.zig"); -pub const Flights = @import("au/Flights.zig"); -pub const VkAllocator = @import("au/VkAllocator.zig"); - -const config = nu.config.render; - -pub const apis: []const vk.ApiInfo = &.{ - vk.features.version_1_0, - vk.features.version_1_1, - vk.features.version_1_2, - vk.features.version_1_3, - vk.extensions.khr_surface, - vk.extensions.khr_swapchain, - vk.extensions.khr_dynamic_rendering, - if (config.use_debug_messenger) vk.extensions.ext_debug_utils else .{}, -}; - -pub const device_extensions: []const [*:0]const u8 = &.{ - // todo somehow sync this with APIs above? - vk.extensions.khr_swapchain.name, - vk.extensions.khr_dynamic_rendering.name, -}; - -pub const BaseWrapper = vk.BaseWrapper(apis); -pub const InstanceWrapper = vk.InstanceWrapper(apis); -pub const DeviceWrapper = vk.DeviceWrapper(apis); - -pub const InstanceProxy = vk.InstanceProxy(apis); -pub const DeviceProxy = vk.DeviceProxy(apis); -pub const QueueProxy = vk.QueueProxy(apis); -pub const CommandBufferProxy = vk.CommandBufferProxy(apis); - -pub const B: *const BaseWrapper = &_bw; -pub const I: *const InstanceProxy = &_ip; -pub const D: *const DeviceProxy = &_dp; -pub const Q: *const QueueProxy = &_qp; -pub const S: *const vk.SurfaceKHR = &_surface; - -pub const device_config: *const CandidateDeviceInfo = &_dconfig; - -var _bw: BaseWrapper = undefined; -var _iw: InstanceWrapper = undefined; -var _dw: DeviceWrapper = undefined; - -var _ip: InstanceProxy = undefined; -var _dp: DeviceProxy = undefined; -var _qp: QueueProxy = undefined; - -var _instance: vk.Instance = undefined; -var _surface: vk.SurfaceKHR = undefined; -var _device: vk.Device = undefined; -var _dconfig: CandidateDeviceInfo = undefined; -var _queue: vk.Queue = undefined; - -pub fn init(alloc: std.mem.Allocator) !void { - try init_base(); - errdefer deinit_base(); - - try init_instance(alloc); - errdefer deinit_instance(); - - try init_device(alloc); - errdefer deinit_device(); -} - -pub fn deinit() void { - deinit_device(); - deinit_instance(); - deinit_base(); -} - -fn init_base() !void { - if (glfwVulkanSupported() != nu.Window.c.GLFW_TRUE) - return error.glfwNoVulkan; - - if (config.use_debug_messenger) { - _bw = try BaseWrapper.load(glfwGetInstanceProcAddress); - } else { - _bw = BaseWrapper.loadNoFail(glfwGetInstanceProcAddress); - } -} - -fn deinit_base() void {} - -fn init_instance(alloc: std.mem.Allocator) !void { - var extensions = std.ArrayList([*:0]const u8).init(alloc); - defer extensions.deinit(); - - var layers = std.ArrayList([*:0]const u8).init(alloc); - defer layers.deinit(); - - if (config.use_debug_messenger) { - try extensions.appendSlice(&.{ - vk.extensions.ext_debug_utils.name, - }); - - try layers.appendSlice(&.{ - "VK_LAYER_KHRONOS_validation", - }); - } - - var glfw_exts_count: u32 = 0; - const glfw_exts: [*]const [*:0]const u8 = - @ptrCast(glfwGetRequiredInstanceExtensions(&glfw_exts_count)); - try extensions.appendSlice(glfw_exts[0..glfw_exts_count]); - - const mci: vk.DebugUtilsMessengerCreateInfoEXT = .{ - .message_severity = .{ - .error_bit_ext = true, - .info_bit_ext = true, - .verbose_bit_ext = true, - .warning_bit_ext = true, - }, - .message_type = .{ - .device_address_binding_bit_ext = true, - .general_bit_ext = false, - .performance_bit_ext = true, - .validation_bit_ext = true, - }, - .pfn_user_callback = &debug_callback, - .p_user_data = null, - }; - - _instance = try B.createInstance(&.{ - .p_application_info = &.{ - .p_application_name = config.app_name, - .application_version = vk.makeApiVersion( - config.app_version.variant, - config.app_version.major, - config.app_version.minor, - config.app_version.patch, - ), - .p_engine_name = config.engine_name, - .engine_version = vk.makeApiVersion( - config.engine_version.variant, - config.engine_version.major, - config.engine_version.minor, - config.engine_version.patch, - ), - .api_version = vk.API_VERSION_1_3, - }, - .enabled_extension_count = @intCast(extensions.items.len), - .pp_enabled_extension_names = extensions.items.ptr, - .enabled_layer_count = @intCast(layers.items.len), - .pp_enabled_layer_names = layers.items.ptr, - .p_next = if (config.use_debug_messenger) &mci else null, - }, null); - - if (config.use_debug_messenger) { - _iw = try InstanceWrapper.load(_instance, _bw.dispatch.vkGetInstanceProcAddr); - } else { - _iw = InstanceWrapper.loadNoFail(_instance, _bw.dispatch.vkGetInstanceProcAddr); - } - - _ip = InstanceProxy.init(_instance, &_iw); - - if (glfwCreateWindowSurface(_instance, nu.Window.handle, null, &_surface) != .success) { - return error.glfwCreateWindowSurfaceFailed; - } -} - -fn deinit_instance() void { - _ip.destroySurfaceKHR(_surface, null); - _ip.destroyInstance(null); -} - -const CandidateDeviceInfo = struct { - pdev: vk.PhysicalDevice, - format: vk.SurfaceFormatKHR, - mode: vk.PresentModeKHR, - family: u32, // must support graphics and present for now - - fn init(alloc: std.mem.Allocator, pdev: vk.PhysicalDevice) !struct { i32, CandidateDeviceInfo } { - var score: i32 = 0; - var res: CandidateDeviceInfo = undefined; - - res.pdev = pdev; - - const props = I.getPhysicalDeviceProperties(pdev); - score += switch (props.device_type) { - vk.PhysicalDeviceType.discrete_gpu => 1000, - vk.PhysicalDeviceType.integrated_gpu => 500, - else => 0, - }; - - var format_count: u32 = undefined; - _ = try I.getPhysicalDeviceSurfaceFormatsKHR(pdev, _surface, &format_count, null); - if (format_count == 0) return error.NoSurfaceFormats; - const formats = try alloc.alloc(vk.SurfaceFormatKHR, format_count); - defer alloc.free(formats); - _ = try I.getPhysicalDeviceSurfaceFormatsKHR(pdev, _surface, &format_count, formats.ptr); - - for (formats) |fmt| { - if (fmt.color_space == .srgb_nonlinear_khr) { - res.format = fmt; - break; - } - } else { - res.format = formats[0]; - score -= 100; - } - - var mode_count: u32 = undefined; - _ = try I.getPhysicalDeviceSurfacePresentModesKHR(pdev, _surface, &mode_count, null); - if (mode_count == 0) return error.NoSurfacePresentModes; - const modes = try alloc.alloc(vk.PresentModeKHR, mode_count); - defer alloc.free(modes); - _ = try I.getPhysicalDeviceSurfacePresentModesKHR(pdev, _surface, &mode_count, modes.ptr); - - if (std.mem.indexOfAny(vk.PresentModeKHR, modes, &.{ - vk.PresentModeKHR.mailbox_khr, - vk.PresentModeKHR.immediate_khr, - })) |idx| { - res.mode = modes[idx]; - } else { - score -= 50; - res.mode = .fifo_khr; // this is guaranteed - } - - var ext_count: u32 = undefined; - _ = try I.enumerateDeviceExtensionProperties(pdev, null, &ext_count, null); - const exts = try alloc.alloc(vk.ExtensionProperties, ext_count); - defer alloc.free(exts); - _ = try I.enumerateDeviceExtensionProperties(pdev, null, &ext_count, exts.ptr); - - for (device_extensions) |needle| { - for (exts) |ext| { - if (std.mem.eql( - u8, - std.mem.span(needle), - std.mem.sliceTo(&ext.extension_name, 0), - )) - break; - } else { - return error.MissingDeviceExtension; - } - } - - var family_count: u32 = undefined; - I.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, null); - const families = try alloc.alloc(vk.QueueFamilyProperties, family_count); - defer alloc.free(families); - I.getPhysicalDeviceQueueFamilyProperties(pdev, &family_count, families.ptr); - - for (families, 0..) |prop, idx| { - const graphics_support = prop.queue_flags.graphics_bit; - const present_support = try I.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(idx), _surface) == vk.TRUE; - - if (graphics_support and present_support) { - res.family = @intCast(idx); - break; - } - } else { - return error.NoSuitableFamily; - } - - return .{ score, res }; - } -}; - -fn init_device(alloc: std.mem.Allocator) !void { - var pdev_count: u32 = undefined; - _ = try I.enumeratePhysicalDevices(&pdev_count, null); - if (pdev_count == 0) return error.NoDevice; - const pdevs = try alloc.alloc(vk.PhysicalDevice, pdev_count); - defer alloc.free(pdevs); - _ = try I.enumeratePhysicalDevices(&pdev_count, pdevs.ptr); - - // const scores = std.ArrayList(i32). - var scores: std.MultiArrayList(struct { score: i32, ci: CandidateDeviceInfo }) = .{}; - defer scores.deinit(alloc); - - for (pdevs) |pdev| { - const score, const ci = CandidateDeviceInfo.init(alloc, pdev) catch continue; - try scores.append(alloc, .{ .score = score, .ci = ci }); - } - - const idx = std.sort.argMax(i32, scores.items(.score), {}, std.sort.asc(i32)) orelse - return error.NoSuitableDevice; - _dconfig = scores.get(idx).ci; - - const qci: []const vk.DeviceQueueCreateInfo = &.{ - vk.DeviceQueueCreateInfo{ - .queue_family_index = _dconfig.family, - .queue_count = 1, - .p_queue_priorities = &[_]f32{1.0}, - }, - }; - - _device = try I.createDevice(_dconfig.pdev, &.{ - .queue_create_info_count = @intCast(qci.len), - .p_queue_create_infos = qci.ptr, - .enabled_extension_count = @intCast(device_extensions.len), - .pp_enabled_extension_names = device_extensions.ptr, - .p_next = &vk.PhysicalDeviceDynamicRenderingFeaturesKHR{ - .dynamic_rendering = vk.TRUE, - }, - }, null); - - if (config.use_debug_messenger) { - _dw = try DeviceWrapper.load(_device, _iw.dispatch.vkGetDeviceProcAddr); - } else { - _dw = DeviceWrapper.loadNoFail(_device, _iw.dispatch.vkGetDeviceProcAddr); - } - _dp = DeviceProxy.init(_device, &_dw); - errdefer D.destroyDevice(null); - - _queue = D.getDeviceQueue(_dconfig.family, 0); - - _qp = QueueProxy.init(_queue, &_dw); - - // todo i'm thinking this needs to be a more complex pointer structure... i'm making assumptions here about how the - // command pools are meant to work. probably I am cooking too much. -} - -fn deinit_device() void { - D.destroyDevice(null); -} - -pub fn debug_callback( - msg_severity: vk.DebugUtilsMessageSeverityFlagsEXT, - msg_type: vk.DebugUtilsMessageTypeFlagsEXT, - p_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, - _: ?*anyopaque, -) callconv(vk.vulkan_call_conv) vk.Bool32 { - // ripped from std.log.defaultLog - - const data = p_data orelse return vk.FALSE; - const message = data.p_message orelse return vk.FALSE; - - const severity_prefix = if (msg_severity.verbose_bit_ext) - "verbose:" - else if (msg_severity.info_bit_ext) - "info:" - else if (msg_severity.warning_bit_ext) - "warning:" - else if (msg_severity.error_bit_ext) - "error:" - else - "?:"; - - const type_prefix = if (msg_type.general_bit_ext) - "" - else if (msg_type.validation_bit_ext) - "validation:" - else if (msg_type.performance_bit_ext) - "performance:" - else if (msg_type.device_address_binding_bit_ext) - "device_address_binding:" - else - "?:"; - - const stderr = std.io.getStdErr().writer(); - var bw = std.io.bufferedWriter(stderr); - const writer = bw.writer(); - - std.debug.lockStdErr(); - defer std.debug.unlockStdErr(); - nosuspend { - writer.print("vk-{s}{s} {s}\n", .{ severity_prefix, type_prefix, message }) catch return vk.FALSE; - bw.flush() catch return vk.FALSE; - } - - return vk.FALSE; -} - -pub extern fn glfwVulkanSupported() c_int; - -pub extern fn glfwGetInstanceProcAddress( - instance: vk.Instance, - procname: [*:0]const u8, -) vk.PfnVoidFunction; - -pub extern fn glfwGetPhysicalDevicePresentationSupport( - instance: vk.Instance, - pdev: vk.PhysicalDevice, - queuefamily: u32, -) c_int; - -pub extern fn glfwCreateWindowSurface( - instance: vk.Instance, - window: *nu.Window.c.GLFWwindow, - allocation_callbacks: ?*const vk.AllocationCallbacks, - surface: *vk.SurfaceKHR, -) vk.Result; - -pub extern fn glfwGetRequiredInstanceExtensions( - count: *u32, -) [*][*:0]const u8; diff --git a/src/nu/Render/au/Flights.zig b/src/nu/Render/au/Flights.zig deleted file mode 100644 index 4662e08..0000000 --- a/src/nu/Render/au/Flights.zig +++ /dev/null @@ -1,62 +0,0 @@ -const std = @import("std"); -const vk = @import("vk"); -const au = @import("../au.zig"); - -const Self = @This(); - -pub const Flight = struct { - acquire: vk.Semaphore = .null_handle, - complete: vk.Semaphore = .null_handle, - fence: vk.Fence = .null_handle, - pool: vk.CommandPool = .null_handle, - cmd: vk.CommandBuffer = .null_handle, - - pub fn wait(self: Flight) !void { - _ = try au.D.waitForFences(1, &.{self.fence}, vk.TRUE, std.math.maxInt(u64)); - try au.D.resetFences(1, &.{self.fence}); - } -}; - -alloc: std.mem.Allocator, -flights: []Flight, -idx: usize, - -pub fn init(alloc: std.mem.Allocator, n: usize) !Self { - var self: Self = .{ - .alloc = alloc, - .flights = try alloc.alloc(Flight, n), - .idx = 0, - }; - errdefer self.deinit(); - - for (self.flights) |*flight| { - flight.acquire = try au.D.createSemaphore(&.{}, null); - flight.complete = try au.D.createSemaphore(&.{}, null); - flight.fence = try au.D.createFence(&.{ .flags = .{ .signaled_bit = true } }, null); - flight.pool = try au.D.createCommandPool(&.{ .queue_family_index = au.device_config.family }, null); - try au.D.allocateCommandBuffers(&vk.CommandBufferAllocateInfo{ - .command_buffer_count = 1, - .command_pool = flight.pool, - .level = .primary, - }, @ptrCast(&flight.cmd)); - } - - return self; -} - -pub fn deinit(self: Self) void { - for (self.flights) |flight| { - au.D.destroySemaphore(flight.acquire, null); - au.D.destroySemaphore(flight.complete, null); - au.D.destroyFence(flight.fence, null); - au.D.freeCommandBuffers(flight.pool, 1, &.{flight.cmd}); - au.D.destroyCommandPool(flight.pool, null); - } - self.alloc.free(self.flights); -} - -pub fn next(self: *Self) Flight { - const idx = self.idx; - self.idx = (self.idx + 1) % self.flights.len; - return self.flights[idx]; -} diff --git a/src/nu/Render/au/VkAllocator.zig b/src/nu/Render/au/VkAllocator.zig index 0533c65..de51884 100644 --- a/src/nu/Render/au/VkAllocator.zig +++ b/src/nu/Render/au/VkAllocator.zig @@ -1,3 +1,5 @@ +// todo look into Vulkan Memory Allocator + const std = @import("std"); const vk = @import("vk"); const au = @import("../au.zig"); diff --git a/src/nu/Render/swap_chain.zig b/src/nu/Render/swap_chain.zig deleted file mode 100644 index c87f665..0000000 --- a/src/nu/Render/swap_chain.zig +++ /dev/null @@ -1,283 +0,0 @@ -const std = @import("std"); -const vk = @import("vk"); -const ctx = @import("ctx.zig"); - -fn _choose_format(alloc: std.mem.Allocator) !vk.SurfaceFormatKHR { - var count: u32 = undefined; - std.debug.assert(.success == try ctx.I.getPhysicalDeviceSurfaceFormatsKHR( - ctx.pdevice.*, - ctx.surface.*, - &count, - null, - )); - const formats = try alloc.alloc(vk.SurfaceFormatKHR, count); - defer alloc.free(formats); - std.debug.assert(.success == try ctx.I.getPhysicalDeviceSurfaceFormatsKHR( - ctx.pdevice.*, - ctx.surface.*, - &count, - formats.ptr, - )); - - for (formats) |format| { - if (format.color_space == .srgb_nonlinear_khr) return format; - } else { - return formats[0]; - } -} - -fn _choose_mode(alloc: std.mem.Allocator) !vk.PresentModeKHR { - _ = ctx; - _ = alloc; - - return .fifo_khr; -} - -pub fn SwapChain(F: type) type { - return struct { - const Self = @This(); - - pub const Target = struct { - image_index: u32, - flight_index: u32, - image: vk.Image, - view: vk.ImageView, - flight: *F, - acquired: vk.Semaphore, // this semaphore will be signaled when the target is acquired - complete: vk.Semaphore, // this semaphore should be signaled when the render is complete - available: vk.Fence, // this fence should be signaled when the target flight is available - }; - - alloc: std.mem.Allocator, - - cur: u8 = 0, - flights: []F, - acquired_sems: []vk.Semaphore, - complete_sems: []vk.Semaphore, - available_fncs: []vk.Fence, - - cinfo: vk.SwapchainCreateInfoKHR, - handle: vk.SwapchainKHR, - - images: std.ArrayListUnmanaged(vk.Image), - views: std.ArrayListUnmanaged(vk.ImageView), - - pub fn init(alloc: std.mem.Allocator, flights: []F) !Self { - const acquired_sems = try alloc.alloc(vk.Semaphore, flights.len); - errdefer alloc.free(acquired_sems); - @memset(acquired_sems, .null_handle); - errdefer for (acquired_sems) |semaphore| ctx.D.destroySemaphore(semaphore, null); - for (acquired_sems) |*sem| { - sem.* = try ctx.D.createSemaphore(&vk.SemaphoreCreateInfo{}, null); - } - - const complete_sems = try alloc.alloc(vk.Semaphore, flights.len); - errdefer alloc.free(complete_sems); - @memset(complete_sems, .null_handle); - errdefer for (complete_sems) |semaphore| ctx.D.destroySemaphore(semaphore, null); - for (complete_sems) |*sem| { - sem.* = try ctx.D.createSemaphore(&vk.SemaphoreCreateInfo{}, null); - } - - const available_fncs = try alloc.alloc(vk.Fence, flights.len); - errdefer alloc.free(available_fncs); - @memset(available_fncs, .null_handle); - errdefer for (available_fncs) |fence| ctx.D.destroyFence(fence, null); - for (available_fncs) |*fnc| { - fnc.* = try ctx.D.createFence(&vk.FenceCreateInfo{ .flags = .{ .signaled_bit = true } }, null); - } - - const capabilities = try ctx.I.getPhysicalDeviceSurfaceCapabilitiesKHR(ctx.pdevice.*, ctx.surface.*); - const format = try _choose_format(alloc); - const mode = try _choose_mode(alloc); - - var min_image_count = @min(3, capabilities.min_image_count + 1); - if (capabilities.max_image_count > 0) { - min_image_count = @min(min_image_count, capabilities.max_image_count); - } - - const cinfo: vk.SwapchainCreateInfoKHR = .{ - .surface = ctx.surface.*, - .min_image_count = min_image_count, - .image_format = format.format, - .image_color_space = format.color_space, - .image_extent = undefined, // set in rebuild - .image_array_layers = 1, - .image_usage = .{ .color_attachment_bit = true }, - .image_sharing_mode = .exclusive, - .pre_transform = .{ .identity_bit_khr = true }, - .composite_alpha = .{ .opaque_bit_khr = true }, - .present_mode = mode, - .clipped = vk.TRUE, - .old_swapchain = .null_handle, - }; - - return .{ - .alloc = alloc, - .flights = flights, - .acquired_sems = acquired_sems, - .complete_sems = complete_sems, - .available_fncs = available_fncs, - .cinfo = cinfo, - .handle = .null_handle, - .images = .{}, - .views = .{}, - }; - } - - pub fn deinit(self: *Self) void { - for (self.views.items) |view| ctx.D.destroyImageView(view, null); - self.views.deinit(self.alloc); - - // images are owned by swapchain and not explicitly destroyed - self.images.deinit(self.alloc); - - ctx.D.destroySwapchainKHR(self.handle, null); - - // The easiest way to ensure fences and semaphores are not in use for deletion. - ctx.D.deviceWaitIdle() catch |err| switch (err) { - error.OutOfHostMemory, - error.OutOfDeviceMemory, - => {}, - error.DeviceLost, - => return, // If the devices is lost there isn't much I know to do. I guess deinit is not needed? - else => unreachable, - }; - - for (self.available_fncs) |fnc| ctx.D.destroyFence(fnc, null); - self.alloc.free(self.available_fncs); - - for (self.complete_sems) |sem| ctx.D.destroySemaphore(sem, null); - self.alloc.free(self.complete_sems); - - for (self.acquired_sems) |sem| ctx.D.destroySemaphore(sem, null); - self.alloc.free(self.acquired_sems); - } - - pub fn acquire(self: *Self) !Target { - const flight_index = self.cur; - const acquired = self.acquired_sems[flight_index]; - const complete = self.complete_sems[flight_index]; - const available = self.available_fncs[flight_index]; - - const timeout = std.math.maxInt(u64); - - for (0..5) |_| { - if (self.handle == .null_handle) { - try self.rebuild(); - std.debug.assert(self.handle != .null_handle); - } - - const fences: [1]vk.Fence = .{available}; - std.debug.assert(.success == try ctx.D.waitForFences( - 1, - &fences, - vk.TRUE, - std.math.maxInt(u64), - )); - - if (ctx.D.acquireNextImageKHR( - self.handle, - timeout, - acquired, - .null_handle, - )) |res| { - switch (res.result) { - .success, .suboptimal_khr => {}, - else => unreachable, - } - - try ctx.D.resetFences(1, &.{available}); - self.cur = @intCast(@mod(self.cur + 1, self.flights.len)); - - return Target{ - .image_index = res.image_index, - .flight_index = flight_index, - .image = self.images.items[res.image_index], - .view = self.views.items[res.image_index], - .flight = &self.flights[flight_index], - .acquired = acquired, - .complete = complete, - .available = available, - }; - } else |err| switch (err) { - error.OutOfDateKHR => { - self.handle = .null_handle; - continue; - }, - else => return err, - } - } else { - return error.CannotRecreateSwapchain; - } - } - - pub fn present(self: *Self, target: Target) !void { - if (ctx.Q.presentKHR(&vk.PresentInfoKHR{ - .wait_semaphore_count = 1, // todo extra semaphores? - .p_wait_semaphores = &.{target.complete}, - .swapchain_count = 1, - .p_swapchains = &.{self.handle}, - .p_image_indices = &.{target.image_index}, - .p_results = null, - })) |res| { - switch (res) { - .success => {}, - .suboptimal_khr => { - self.handle = .null_handle; - return; - }, - else => unreachable, - } - } else |err| switch (err) { - error.OutOfDateKHR => { - self.handle = .null_handle; - std.log.debug("Dropped frame", .{}); - return; - }, - else => return err, - } - } - - fn rebuild(self: *Self) !void { - std.debug.assert(self.handle == .null_handle); - - const capabilities = try ctx.I.getPhysicalDeviceSurfaceCapabilitiesKHR( - ctx.pdevice.*, - ctx.surface.*, - ); - self.cinfo.image_extent = capabilities.current_extent; - self.handle = try ctx.D.createSwapchainKHR(&self.cinfo, null); - ctx.D.destroySwapchainKHR(self.cinfo.old_swapchain, null); - errdefer ctx.D.destroySwapchainKHR(self.handle, null); - self.cinfo.old_swapchain = self.handle; - - for (self.views.items) |view| ctx.D.destroyImageView(view, null); - - var count: u32 = undefined; - std.debug.assert(.success == try ctx.D.getSwapchainImagesKHR(self.handle, &count, null)); - try self.images.resize(self.alloc, count); - try self.views.resize(self.alloc, count); - std.debug.assert(.success == try ctx.D.getSwapchainImagesKHR(self.handle, &count, self.images.items.ptr)); - - @memset(self.views.items, .null_handle); - errdefer for (self.views.items) |view| ctx.D.destroyImageView(view, null); - - for (self.images.items, self.views.items) |image, *view| { - view.* = try ctx.D.createImageView(&vk.ImageViewCreateInfo{ - .image = image, - .view_type = .@"2d", - .format = self.cinfo.image_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, - }, - }, null); - } - } - }; -}