const std = @import("std"); const sdl = @import("sdl2"); const vk = @import("vulkan"); const apis: []const vk.ApiInfo = &.{ // You can either add invidiual functions by manually creating an 'api' .{ .base_commands = .{ .createInstance = true, }, .instance_commands = .{ .createDevice = true, }, }, // Or you can add entire feature sets or extensions vk.features.version_1_0, vk.extensions.khr_surface, vk.extensions.khr_swapchain, }; const BaseDispatch = vk.BaseWrapper(apis); const InstanceDispatch = vk.InstanceWrapper(apis); const Instance = vk.InstanceProxy(apis); pub const VulkanRenderer = struct { const Self = @This(); allocator: std.mem.Allocator, vkb: BaseDispatch, window: sdl.Window, instance: Instance, surface: vk.SurfaceKHR, pub fn init(window: sdl.Window, allocator: std.mem.Allocator) !Self { const vkb = try BaseDispatch.load(try sdl.vulkan.getVkGetInstanceProcAddr()); const extensions = try sdl.vulkan.getInstanceExtensionsAlloc(window, allocator); defer allocator.free(extensions); std.debug.print("[Required instance extensions]\n", .{}); for (extensions) |ext| { std.debug.print("\t- {s}\n", .{ext}); } if (!try checkExtensions(vkb, &extensions, allocator)) { return error.ExtensionNotPresent; } const app_info = vk.ApplicationInfo{ .p_application_name = "Vulkan SDL Test", .application_version = vk.makeApiVersion(0, 0, 1, 0), .p_engine_name = "Vulkan SDL Test", .engine_version = vk.makeApiVersion(0, 0, 1, 0), .api_version = vk.API_VERSION_1_3, }; const inst = try vkb.createInstance(&.{ .p_application_info = &app_info, .enabled_extension_count = @intCast(extensions.len), .pp_enabled_extension_names = @ptrCast(extensions), }, null); const vki = try allocator.create(InstanceDispatch); defer allocator.destroy(vki); vki.* = try InstanceDispatch.load(inst, vkb.dispatch.vkGetInstanceProcAddr); var instance = Instance.init(inst, vki); errdefer instance.destroyInstance(null); const surface = try sdl.vulkan.createSurface(window, instance.handle); var physical_device_count: u32 = 0; _ = try instance.enumeratePhysicalDevices(&physical_device_count, null); std.debug.print("Physical devices: {d}\n", .{physical_device_count}); return .{ .allocator = allocator, .window = window, .vkb = vkb, .instance = instance, .surface = surface, }; } pub fn deinit(self: *Self) void { self.instance.destroySurfaceKHR(self.surface, null); self.instance.destroyInstance(null); self.allocator.destroy(self.instance.wrapper); } }; fn checkExtensions(vkb: BaseDispatch, required_extensions: *const [][*:0]const u8, allocator: std.mem.Allocator) !bool { var prop_count: u32 = 0; _ = try vkb.enumerateInstanceExtensionProperties(null, &prop_count, null); const props = try allocator.alloc(vk.ExtensionProperties, prop_count); defer allocator.free(props); _ = try vkb.enumerateInstanceExtensionProperties(null, &prop_count, props.ptr); for (required_extensions.*) |required_extension| { var found = false; for (props) |prop| { if (std.mem.eql(u8, std.mem.sliceTo(&prop.extension_name, 0), std.mem.span(required_extension))) { found = true; } } if (!found) { return false; } } return true; }