From 200e91c1f00243fcedd706deb64ba06fa0417b99 Mon Sep 17 00:00:00 2001 From: Vivianne Langdon Date: Fri, 15 Jul 2022 23:07:31 -0700 Subject: [PATCH] we got to the render loop, huzzah. --- build.zig | 13 +++--- src/main.zig | 13 +----- src/rendering/vulkan/Command.zig | 2 - src/rendering/vulkan/Extensions.zig | 26 +++++++++-- src/rendering/vulkan/Renderer.zig | 2 +- src/rendering/vulkan/device.zig | 33 +++++--------- src/rendering/vulkan/display.zig | 5 --- src/rendering/vulkan/image.zig | 8 ++-- src/rendering/vulkan/instance.zig | 68 ++++++++++++++--------------- src/rendering/vulkan/memory.zig | 8 +++- src/rendering/vulkan/queues.zig | 18 +++++--- src/rendering/vulkan/settings.zig | 2 +- src/rendering/vulkan/swapchain.zig | 30 +++++++------ 13 files changed, 115 insertions(+), 113 deletions(-) diff --git a/build.zig b/build.zig index abb6a8e..84eb4d8 100644 --- a/build.zig +++ b/build.zig @@ -86,11 +86,17 @@ pub fn build(b: *std.build.Builder) void { const exe = b.addExecutable("efemra", "src/main.zig"); exe.setTarget(target); exe.setBuildMode(mode); + exe.install(); const gen = vkgen.VkGenerateStep.init(b, "etc/vk.xml", "vk.zig"); - exe.addPackage(pkgs.glfw); + exe.addPackage(gen.package); + + exe.addPackage(pkgs.glfw); + build_glfw.link(b, exe, .{}); + build_vma.link(exe, gen.output_file.getPath(), mode, target); + build_imgui.link(exe); const res = ResourceGenStep.init(b, "resources.zig"); res.addShader("test_frag", "src/shaders/test.frag"); @@ -98,11 +104,6 @@ pub fn build(b: *std.build.Builder) void { res.addShader("triangle_frag", "src/shaders/triangle.frag"); exe.addPackage(res.package); - build_vma.link(exe, gen.output_file.getPath(), mode, target); - build_imgui.link(exe); - - exe.install(); - const run_cmd = exe.run(); run_cmd.step.dependOn(b.getInstallStep()); if (b.args) |args| { diff --git a/src/main.zig b/src/main.zig index 27f3904..3245b37 100644 --- a/src/main.zig +++ b/src/main.zig @@ -13,16 +13,6 @@ pub fn main() !void { try glfw.init(.{}); defer glfw.terminate(); - var extent = vk.Extent2D{ .width = 1280, .height = 720 }; - - var window = try glfw.Window.create(extent.width, extent.height, app_name, null, null, .{ .client_api = .no_api }); - defer window.destroy(); - - // temp allocator - //var gpa = std.heap.GeneralPurposeAllocator(.{}){}; - //defer _ = gpa.deinit(); - //const allocator = gpa.allocator(); - var renderer = try Renderer.init(); defer renderer.deinit(); @@ -30,8 +20,7 @@ pub fn main() !void { defer renderer.deinit(); - while (!window.shouldClose()) { - std.debug.print("hi", .{}); + while (!renderer.window.handle.shouldClose()) { try renderer.update(); try glfw.pollEvents(); } diff --git a/src/rendering/vulkan/Command.zig b/src/rendering/vulkan/Command.zig index e8752df..7511f4a 100644 --- a/src/rendering/vulkan/Command.zig +++ b/src/rendering/vulkan/Command.zig @@ -51,8 +51,6 @@ pub fn init(device: *const Device, queue: *queues.Queue, id: queues.QueueId) !vo pm_init.begin(); defer pm_init.end(); - assert(queue == queues.get(id)); - queue.index = id; queue.cmd_pool = try Pool.init(device, queue.family, .{ .reset_command_buffer_bit = true }); errdefer queue.cmd_pool.deinit(device); diff --git a/src/rendering/vulkan/Extensions.zig b/src/rendering/vulkan/Extensions.zig index d46efef..8767fce 100644 --- a/src/rendering/vulkan/Extensions.zig +++ b/src/rendering/vulkan/Extensions.zig @@ -25,9 +25,27 @@ pub const Device = struct { return getExtensions(@This(), props); } - pub fn toArray(allocator: std.mem.Allocator) [][*:0]const u8 { + pub fn toArray(allocator: std.mem.Allocator) ![][*:0]const u8 { return extToArray(@This(), allocator); } + + pub fn enabledToArray(self: *Device, allocator: std.mem.Allocator) ![][*:0]const u8 { + const arr = try allocator.alloc([*:0]const u8, @typeInfo(Device).Struct.fields.len); + var i: u32 = 0; + inline for (@typeInfo(Device).Struct.fields) |field| { + if (field.field_type == void) { + continue; + } + + if (@field(self, field.name)) { + const name_info = @field(vk.extension_info, field.name); + arr[i] = name_info.name; + i += 1; + } + } + + return arr[0..i]; + } }; pub const Instance = struct { @@ -39,7 +57,7 @@ pub const Instance = struct { return getExtensions(@This(), props); } - pub fn toArray(allocator: std.mem.Allocator) [][*:0]const u8 { + pub fn toArray(allocator: std.mem.Allocator) ![][*:0]const u8 { return extToArray(@This(), allocator); } }; @@ -62,8 +80,8 @@ fn getExtensions(comptime T: type, props: []vk.ExtensionProperties) T { return ext; } -pub fn extToArray(comptime T: type, allocator: std.mem.Allocator) [][*:0]const u8 { - const arr = allocator.alloc([*:0]const u8, @typeInfo(T).Struct.fields.len) catch unreachable; +pub fn extToArray(comptime T: type, allocator: std.mem.Allocator) ![][*:0]const u8 { + const arr = try allocator.alloc([*:0]const u8, @typeInfo(T).Struct.fields.len); comptime for (@typeInfo(T).Struct.fields) |field, i| { const name_info = @field(vk.extension_info, field.name); arr[i] = name_info.name; diff --git a/src/rendering/vulkan/Renderer.zig b/src/rendering/vulkan/Renderer.zig index dc4f3a3..f956eac 100644 --- a/src/rendering/vulkan/Renderer.zig +++ b/src/rendering/vulkan/Renderer.zig @@ -29,7 +29,7 @@ const Self = @This(); pub fn init() !Self { errdefer { - std.debug.print("failed to init VulkanRenderer", .{}); + std.debug.print("failed to init VulkanRenderer\n", .{}); } try Base.init(); diff --git a/src/rendering/vulkan/device.zig b/src/rendering/vulkan/device.zig index 5360f56..8d32b48 100644 --- a/src/rendering/vulkan/device.zig +++ b/src/rendering/vulkan/device.zig @@ -18,6 +18,7 @@ const std = @import("std"); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); +// TODO: filter by settings! const DeviceDispatch = vk.DeviceWrapper(.{ .destroyDevice = true, .getDeviceQueue = true, @@ -178,6 +179,11 @@ pub const Device = struct { defer allocator.free(feats_list); for (feats_list) |*feat, i| { + feat.* = .{ + .phdev = .{ + .features = .{}, + }, + }; feat.phdev.s_type = .physical_device_features_2; if (settings.rt_on) { feat.phdev.p_next = &feat.accstr; @@ -267,11 +273,11 @@ pub const Device = struct { self.feats = feats_list[chosen]; self.exts = exts_list[chosen]; self.physical_device = pdevs[chosen]; - } else unreachable; + } else return error.NoDeviceChosen; } fn hasRequired(exts: *Extensions.Device) bool { - var has_all = false; + var has_all = true; has_all = has_all and exts.khr_swapchain; return has_all; } @@ -441,6 +447,7 @@ pub const Device = struct { defer queue_support.deinit(); var families = std.AutoArrayHashMap(u32, i32).init(allocator); + try families.ensureTotalCapacity(queue_support.families.len); defer families.deinit(); for (queue_support.families) |f| { if (f) |family| { @@ -520,10 +527,10 @@ pub const Device = struct { self.props.rtpipe.p_next = &self.props.rquery; } - const ext_arr = Extensions.Device.toArray(allocator); + const ext_arr = try self.exts.enabledToArray(allocator); defer allocator.free(ext_arr); - _ = try instance.dispatch.createDevice(self.physical_device, &.{ + self.handle = try instance.dispatch.createDevice(self.physical_device, &.{ .flags = .{}, .p_next = &self.props.phdev, .queue_create_info_count = @intCast(u32, families.count()), @@ -535,22 +542,4 @@ pub const Device = struct { .pp_enabled_extension_names = ext_arr.ptr, }, null); } - - fn getExtensions(avail_exts: *std.StringArrayHashMap) !std.ArrayList([][*:0]const u8) { - const list = try std.ArrayList([*:0]const u8).init(allocator); - - for (try glfw.getRequiredDeviceExtensions()) |ext| { - if (avail_exts.contains(ext)) { - list.append(ext); - } - } - - for (Extensions.dev) |ext| { - if (avail_exts.contains(ext)) { - list.append(ext); - } - } - - return list; - } }; diff --git a/src/rendering/vulkan/display.zig b/src/rendering/vulkan/display.zig index ec74cc1..15e3ac4 100644 --- a/src/rendering/vulkan/display.zig +++ b/src/rendering/vulkan/display.zig @@ -10,8 +10,6 @@ const allocator = gpa.allocator(); pub const Display = struct { pub fn getWorkSize() !glfw.Window.Size { - try glfw.init(.{}); - const monitor = try glfw.Monitor.getPrimary() orelse error.NoPrimaryMonitor; const work_area = try monitor.getWorkarea(); @@ -26,8 +24,6 @@ pub const Display = struct { } pub fn getFullSize() !glfw.Window.Size { - try glfw.init(.{}); - const monitor = try glfw.Monitor.getPrimary() orelse error.NoPrimaryMonitor; const modes = try monitor.getVideoModes(allocator); defer allocator.free(modes); @@ -69,7 +65,6 @@ pub const Window = struct { surface: vk.SurfaceKHR, pub fn init(instance: *const Instance, title: [*:0]const u8, width: u32, height: u32, fullscreen: bool) !Self { - try glfw.init(.{}); const handle = try glfw.Window.create(width, height, title, try glfw.Monitor.getPrimary() orelse error.NoPrimaryMonitor, null, .{ .client_api = .no_api, .srgb_capable = true, diff --git a/src/rendering/vulkan/image.zig b/src/rendering/vulkan/image.zig index f303ab8..8b43939 100644 --- a/src/rendering/vulkan/image.zig +++ b/src/rendering/vulkan/image.zig @@ -43,7 +43,7 @@ pub const Image = struct { } /// import vk.Image handle into an existing Image object. - pub fn import(self: *Image, device: *const Device, info: *const vk.ImageCreateInfo, handle: vk.Image) !void { + pub fn import(self: *Image, device: *const Device, info: vk.ImageCreateInfo, handle: vk.Image) !void { self.handle = handle; self.image_type = info.image_type; self.format = info.format; @@ -56,7 +56,7 @@ pub const Image = struct { self.array_layers = @intCast(u8, info.array_layers); self.imported = true; - var view_info = try infoToViewInfo(info); + var view_info = try infoToViewInfo(&info); view_info.image = self.handle; self.view = try device.dispatch.createImageView(device.handle, &view_info, null); @@ -148,8 +148,8 @@ pub fn infoToViewInfo(info: *const vk.ImageCreateInfo) !vk.ImageViewCreateInfo { .flags = .{}, .format = info.format, .view_type = infoToViewType(info), - .image = undefined, - .components = undefined, + .image = .null_handle, + .components = .{ .r = .identity, .g = .identity, .b = .identity, .a = .identity }, .subresource_range = .{ .aspect_mask = infoToAspects(info), .base_mip_level = 0, diff --git a/src/rendering/vulkan/instance.zig b/src/rendering/vulkan/instance.zig index 03eaab4..53969e9 100644 --- a/src/rendering/vulkan/instance.zig +++ b/src/rendering/vulkan/instance.zig @@ -13,13 +13,14 @@ const DebugMessenger = @import("DebugMessenger.zig"); var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); +// TODO: filter by settings! const InstanceDispatch = vk.InstanceWrapper(.{ .destroyInstance = true, .createDevice = true, .destroySurfaceKHR = true, .enumeratePhysicalDevices = true, - .createDebugUtilsMessengerEXT = true, - .destroyDebugUtilsMessengerEXT = true, + .createDebugUtilsMessengerEXT = settings.messenger_on, + .destroyDebugUtilsMessengerEXT = settings.messenger_on, .getPhysicalDeviceProperties2 = true, .getPhysicalDeviceFeatures2 = true, .enumerateDeviceExtensionProperties = true, @@ -45,12 +46,12 @@ pub const Instance = struct { pub fn init() !Self { // TODO: do we absolutely need volk rn? Don't think so? volk init here var avail_layers = try getAvailableLayers(); - defer avail_layers.deinit(); + defer allocator.free(avail_layers); var avail_exts = try getAvailableExtensions(); - defer avail_exts.deinit(); + defer allocator.free(avail_exts); - const layers_to_load = try getLayers(&avail_layers); - const extensions = try getExtensions(&avail_exts); + const layers_to_load = try getLayers(avail_layers); + const extensions = try getExtensions(avail_exts); const app_info = vk.ApplicationInfo{ .p_application_name = settings.app_name, @@ -78,7 +79,7 @@ pub const Instance = struct { .extensions = extensions, .handle = handle, }; - self.messenger = try DebugMessenger.init(&self); + self.messenger = if (settings.messenger_on) try DebugMessenger.init(&self) else undefined; return self; } @@ -91,34 +92,32 @@ pub const Instance = struct { } /// list all available layers - fn getAvailableLayers() !std.StringArrayHashMap(void) { + fn getAvailableLayers() ![]vk.LayerProperties { var count: u32 = undefined; _ = try Base.dispatch.enumerateInstanceLayerProperties(&count, null); const list = try allocator.alloc(vk.LayerProperties, count); - defer allocator.free(list); _ = try Base.dispatch.enumerateInstanceLayerProperties(&count, list.ptr); - var hash_map = std.StringArrayHashMap(void).init(allocator); - try hash_map.ensureTotalCapacity(count); - // TODO log - std.debug.print("{} available instance layers", .{count}); + std.debug.print("{} available instance layers\n", .{count}); for (list) |layer| { const layer_name = std.mem.sliceTo(&layer.layer_name, 0); - std.debug.print("{s}", .{layer_name}); - hash_map.putAssumeCapacity(layer_name, {}); + std.debug.print("\t{s}\n", .{layer_name}); } - return hash_map; + return list; } - fn getLayers(avail_layers: *std.StringArrayHashMap(void)) !std.ArrayList([*:0]const u8) { + fn getLayers(avail_layers: []vk.LayerProperties) !std.ArrayList([*:0]const u8) { var list = std.ArrayList([*:0]const u8).init(allocator); for (enabled_layers) |layer| { const layer_name = std.mem.sliceTo(layer, 0); - if (avail_layers.contains(layer_name)) { - try list.append(layer); + for (avail_layers) |avail_layer| { + const avail_layer_name = std.mem.sliceTo(&avail_layer.layer_name, 0); + if (std.mem.eql(u8, layer_name, avail_layer_name)) { + try list.append(layer); + } } } @@ -126,43 +125,44 @@ pub const Instance = struct { } /// list all available extensions - fn getAvailableExtensions() !std.StringArrayHashMap(void) { + fn getAvailableExtensions() ![]vk.ExtensionProperties { var count: u32 = undefined; _ = try Base.dispatch.enumerateInstanceExtensionProperties(null, &count, null); const list = try allocator.alloc(vk.ExtensionProperties, count); - defer allocator.free(list); _ = try Base.dispatch.enumerateInstanceExtensionProperties(null, &count, list.ptr); - var hash_map = std.StringArrayHashMap(void).init(allocator); - try hash_map.ensureTotalCapacity(count); - // TODO log - std.debug.print("{} available instance extensions", .{count}); + std.debug.print("{} available instance extensions\n", .{count}); for (list) |ext| { const extension_name = std.mem.sliceTo(&ext.extension_name, 0); - std.debug.print("{s}", .{extension_name}); - hash_map.putAssumeCapacity(extension_name, {}); + std.debug.print("\t{s}\n", .{extension_name}); } - return hash_map; + return list; } - fn getExtensions(avail_exts: *std.StringArrayHashMap(void)) !std.ArrayList([*:0]const u8) { + fn getExtensions(avail_exts: []vk.ExtensionProperties) !std.ArrayList([*:0]const u8) { var list = std.ArrayList([*:0]const u8).init(allocator); for (try glfw.getRequiredInstanceExtensions()) |ext| { const extension_name = std.mem.sliceTo(ext, 0); - if (avail_exts.contains(extension_name)) { - try list.append(extension_name); + for (avail_exts) |avail_ext| { + const avail_ext_name = std.mem.sliceTo(&avail_ext.extension_name, 0); + if (std.mem.eql(u8, extension_name, avail_ext_name)) { + try list.append(extension_name); + } } } - const instExts = Extensions.Instance.toArray(allocator); + const instExts = try Extensions.Instance.toArray(allocator); defer allocator.free(instExts); for (instExts) |ext| { const extension_name = std.mem.sliceTo(ext, 0); - if (avail_exts.contains(extension_name)) { - try list.append(ext); + for (avail_exts) |avail_ext| { + const avail_ext_name = std.mem.sliceTo(&avail_ext.extension_name, 0); + if (std.mem.eql(u8, extension_name, avail_ext_name)) { + try list.append(ext); + } } } diff --git a/src/rendering/vulkan/memory.zig b/src/rendering/vulkan/memory.zig index 2eee51c..09d13db 100644 --- a/src/rendering/vulkan/memory.zig +++ b/src/rendering/vulkan/memory.zig @@ -1,6 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); const framebuffer = @import("framebuffer.zig"); +const Base = @import("Base.zig"); const Device = @import("device.zig").Device; const Instance = @import("instance.zig").Instance; const SubmitId = @import("swapchain.zig").SubmitId; @@ -270,11 +271,13 @@ const Allocator = struct { device_buffer_pool: Pool, dynamic_buffer_pool: Pool, device_texture_pool: Pool, - releasables: []Releasable = undefined, + releasables: []Releasable = &[_]Releasable{}, pub fn init(instance: *const Instance, device: *const Device) !Self { + const funcs = vma.VulkanFunctions.init(instance.handle, device.handle, Base.vk_proc); + const handle = try vma.Allocator.create(.{ - .vulkanApiVersion = vk.API_VERSION_1_3, + .vulkanApiVersion = vk.API_VERSION_1_1, // LIES .flags = .{ .memoryBudgetEXT = true, .externallySynchronized = true, @@ -282,6 +285,7 @@ const Allocator = struct { .instance = instance.handle, .physicalDevice = device.physical_device, .device = device.handle, + .pVulkanFunctions = &funcs, .pAllocationCallbacks = null, .frameInUseCount = settings.resource_sets, }); diff --git a/src/rendering/vulkan/queues.zig b/src/rendering/vulkan/queues.zig index c85c7df..5cf2f91 100644 --- a/src/rendering/vulkan/queues.zig +++ b/src/rendering/vulkan/queues.zig @@ -147,16 +147,20 @@ pub const Support = struct { var count: u32 = undefined; instance.dispatch.getPhysicalDeviceQueueFamilyProperties(physical_device, &count, null); - self.properties = try allocator.alloc(vk.QueueFamilyProperties, count); - instance.dispatch.getPhysicalDeviceQueueFamilyProperties(physical_device, &count, self.properties.ptr); + // self.properties = + const props = try allocator.alloc(vk.QueueFamilyProperties, count); + instance.dispatch.getPhysicalDeviceQueueFamilyProperties(physical_device, &count, props.ptr); - self.families[@enumToInt(QueueId.graphics)] = selectGfxFamily(self.properties); - self.families[@enumToInt(QueueId.compute)] = selectCompFamily(self.properties); - self.families[@enumToInt(QueueId.transfer)] = selectXferFamily(self.properties); - self.families[@enumToInt(QueueId.present)] = try selectPresFamily(instance, physical_device, window.surface, self.properties); + self.families[@enumToInt(QueueId.graphics)] = selectGfxFamily(props); + self.families[@enumToInt(QueueId.compute)] = selectCompFamily(props); + self.families[@enumToInt(QueueId.transfer)] = selectXferFamily(props); + self.families[@enumToInt(QueueId.present)] = try selectPresFamily(instance, physical_device, window.surface, props); + + self.properties = props; // TODO: don't understand the purpose of 'indices' yet... const choice_counts = try allocator.alloc(u32, count); + std.mem.set(u32, choice_counts, 0); defer allocator.free(choice_counts); for (self.families) |family, i| { if (family) |f| { @@ -294,7 +298,7 @@ pub const Queue = struct { }; const pres_family = support.families[@enumToInt(QueueId.present)]; - const queue_flags = support.properties[@enumToInt(QueueId.present)].queue_flags; + const queue_flags = support.properties[0].queue_flags; // ? if (queue_flags.graphics_bit) { self.gfx = true; diff --git a/src/rendering/vulkan/settings.zig b/src/rendering/vulkan/settings.zig index 57a22d9..3667254 100644 --- a/src/rendering/vulkan/settings.zig +++ b/src/rendering/vulkan/settings.zig @@ -5,7 +5,7 @@ pub const engine_name = "efemra"; pub const khronos_layer_on = true; pub const assist_layer_on = true; -pub const messenger_on = true; +pub const messenger_on = false; // fixme! pub const rt_on = false; pub const hdr_on = true; diff --git a/src/rendering/vulkan/swapchain.zig b/src/rendering/vulkan/swapchain.zig index 95ed967..de8a62e 100644 --- a/src/rendering/vulkan/swapchain.zig +++ b/src/rendering/vulkan/swapchain.zig @@ -70,7 +70,7 @@ const Support = struct { } pub fn selectSwapFormat(self: *const Self) !vk.SurfaceFormatKHR { - if (self.formats.len > 0) { + if (self.formats.len <= 0) { return error.NoSurfaceFormats; } @@ -168,6 +168,8 @@ pub const Swapchain = struct { const queue_support = try queues.Support.init(instance, device.physical_device, window); defer queue_support.deinit(); + _ = previous; + const format = try support.selectSwapFormat(); const mode = try support.selectSwapMode(); const ext = support.selectSwapExtent(window); @@ -182,13 +184,15 @@ pub const Swapchain = struct { const usage: vk.ImageUsageFlags = .{ .color_attachment_bit = true }; + const image_format = .r5g6b5_unorm_pack16; + const swap_info = vk.SwapchainCreateInfoKHR{ .s_type = .swapchain_create_info_khr, .flags = .{}, .surface = window.surface, .present_mode = mode, .min_image_count = img_count, - .image_format = format.format, + .image_format = image_format, .image_color_space = format.color_space, .image_extent = ext, .image_array_layers = 1, @@ -209,12 +213,12 @@ pub const Swapchain = struct { errdefer device.dispatch.destroySwapchainKHR(device.handle, handle, null); if (previous == null) { - std.debug.print("Present mode: '{s}'", .{@tagName(mode)}); - std.debug.print("Present extent: '{} x {}'", .{ ext.width, ext.height }); - std.debug.print("Present images: '{}'", .{img_count}); - std.debug.print("Present sharing mode: '{s}'", .{if (concurrent) @as([]const u8, "Concurrent") else "Exclusive"}); - std.debug.print("Color space: '{s}'", .{@tagName(format.color_space)}); - std.debug.print("Format: '{s}'", .{@tagName(format.format)}); + std.debug.print("Present mode: '{s}'\n", .{@tagName(mode)}); + std.debug.print("Present extent: '{} x {}'\n", .{ ext.width, ext.height }); + std.debug.print("Present images: '{}'\n", .{img_count}); + std.debug.print("Present sharing mode: '{s}'\n", .{if (concurrent) @as([]const u8, "Concurrent") else "Exclusive"}); + std.debug.print("Color space: '{s}'\n", .{@tagName(format.color_space)}); + std.debug.print("Format: '{s}'\n", .{@tagName(image_format)}); } var images: [settings.max_swapchain_len]vk.Image = undefined; @@ -225,20 +229,20 @@ pub const Swapchain = struct { _ = try device.dispatch.getSwapchainImagesKHR(device.handle, handle, &img_count, &images); + const color_format = .r5g6b5_unorm_pack16; + var self = Self{ .handle = handle, .mode = mode, - .color_format = format.format, + .color_format = color_format, .color_space = format.color_space, .width = ext.width, .height = ext.height, .length = img_count, }; - const color_format = format.format; - - for (images) |img, i| { - try self.images[i].import(device, &.{ + for (images[0..img_count]) |img, i| { + try self.images[i].import(device, .{ .s_type = .image_create_info, .flags = .{}, .image_type = .@"2d",