diff --git a/src/main.zig b/src/main.zig index f8b7d8b..aa23371 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,6 +3,7 @@ const UI = @import("./ui/ui.zig").UI; const Vulkan = @import("./vulkan/vulkan.zig").Vulkan; const StateActor = @import("./state_actor.zig").StateActor; const Util = @import("./util.zig"); +const sdl = @import("./ui/sdl.zig"); const PlatformCaptureSetup = @import("./capture/platform_capture_setup.zig").PlatformCaptureSetup; const PlatformVideoCapture = if (Util.isLinux()) @@ -31,10 +32,10 @@ pub fn main() !void { PlatformCaptureSetup.init(); defer PlatformCaptureSetup.deinit(); - var sdl_vulkan_extensions = try UI.getSDLVulkanExtensions(allocator); - defer sdl_vulkan_extensions.deinit(allocator); + var sdl_vulkan_extensions = try sdl.get_sdl_vulkan_extensions(allocator); + defer sdl_vulkan_extensions.deinit(); - const vulkan = try Vulkan.init(allocator, sdl_vulkan_extensions.items); + const vulkan = try Vulkan.init(allocator, sdl_vulkan_extensions.list.items); defer vulkan.deinit(); // TODO: create dropdown selector in UI to select capture method when more are implemented. diff --git a/src/ui/sdl.zig b/src/ui/sdl.zig new file mode 100644 index 0000000..eb54639 --- /dev/null +++ b/src/ui/sdl.zig @@ -0,0 +1,83 @@ +const std = @import("std"); +const util = @import("../util.zig"); +const imguiz = @import("imguiz").imguiz; + +const log = std.log.scoped(.sdl); + +const SDL_INIT_FLAGS = imguiz.SDL_INIT_VIDEO | imguiz.SDL_INIT_GAMEPAD; + +pub const SDLVulkanExtensions = struct { + allocator: std.mem.Allocator, + list: std.ArrayList([*:0]const u8), + + pub fn deinit(self: *SDLVulkanExtensions) void { + for (self.list.items) |extension| { + self.allocator.free(std.mem.span(extension)); + } + self.list.deinit(self.allocator); + } +}; + +/// Caller owns memory +pub fn get_sdl_vulkan_extensions(allocator: std.mem.Allocator) !SDLVulkanExtensions { + try init(); + defer imguiz.SDL_Quit(); + + var extensions = try std.ArrayList([*:0]const u8).initCapacity(allocator, 0); + var extensions_count: u32 = 0; + const sdl_extensions = imguiz.SDL_Vulkan_GetInstanceExtensions(&extensions_count); + if (sdl_extensions == null) { + return error.SDL_Vulkan_GetInstanceExtensionsFailure; + } + errdefer { + for (extensions.items) |extension| allocator.free(std.mem.span(extension)); + extensions.deinit(allocator); + } + for (0..extensions_count) |i| { + const copied = try allocator.dupeZ(u8, std.mem.span(sdl_extensions[i])); + try extensions.append(allocator, copied); + } + + return .{ + .allocator = allocator, + .list = extensions, + }; +} + +/// If Linux, try Wayland, fallback to x11. +pub fn init() !void { + if (util.isLinux()) { + if (try try_sdl_init_with_hint("wayland")) { + log.info("[sdl_init] using wayland", .{}); + return; + } + if (try try_sdl_init_with_hint("x11")) { + log.info("[sdl_init] using x11", .{}); + return; + } + return error.SDL_initFailure; + } + + if (!imguiz.SDL_Init(SDL_INIT_FLAGS)) { + return error.SDL_initFailure; + } +} + +fn try_sdl_init_with_hint(driver_name: [*:0]const u8) !bool { + _ = imguiz.SDL_SetHint(imguiz.SDL_HINT_VIDEO_DRIVER, driver_name); + if (!imguiz.SDL_Init(SDL_INIT_FLAGS)) { + return false; + } + + const actual_driver = imguiz.SDL_GetCurrentVideoDriver() orelse { + imguiz.SDL_Quit(); + return false; + }; + + if (std.mem.eql(u8, std.mem.span(actual_driver), std.mem.span(driver_name))) { + return true; + } + + imguiz.SDL_Quit(); + return false; +} diff --git a/src/ui/ui.zig b/src/ui/ui.zig index 88270ea..cf88d90 100644 --- a/src/ui/ui.zig +++ b/src/ui/ui.zig @@ -3,6 +3,8 @@ const std = @import("std"); const c = @import("imguiz").imguiz; const vk = @import("vulkan"); const rc = @import("zigrc"); +const util = @import("../util.zig"); +const sdl = @import("./sdl.zig"); const CapturePreviewTexture = @import("../vulkan/capture_preview_texture.zig").CapturePreviewTexture; const StateActor = @import("../state_actor.zig").StateActor; @@ -19,8 +21,6 @@ const HEIGHT = 1000; const MIN_IMAGE_COUNT = 2; var g_PipelineCache: c.VkPipelineCache = std.mem.zeroes(c.VkPipelineCache); -const SDL_INIT_FLAGS = c.SDL_INIT_VIDEO | c.SDL_INIT_GAMEPAD; - pub const UI = struct { const log = std.log.scoped(.ui); const Self = @This(); @@ -49,9 +49,7 @@ pub const UI = struct { .vulkan = vulkan, }; - if (!c.SDL_Init(SDL_INIT_FLAGS)) { - return error.SDL_initFailure; - } + try sdl.init(); const version = c.SDL_GetVersion(); std.log.info("SDL version: {}\n", .{version}); @@ -101,22 +99,6 @@ pub const UI = struct { self.allocator.destroy(self); } - /// Caller owns memory - /// TODO: check why not returning "wayland" - pub fn getSDLVulkanExtensions(allocator: std.mem.Allocator) !std.ArrayList([*:0]const u8) { - if (!c.SDL_Init(SDL_INIT_FLAGS)) { - return error.SDL_initFailure; - } - defer c.SDL_Quit(); - - var extensions = try std.ArrayList([*:0]const u8).initCapacity(allocator, 0); - var extensions_count: u32 = 0; - const sdl_extensions = c.SDL_Vulkan_GetInstanceExtensions(&extensions_count); - for (0..extensions_count) |i| try extensions.append(allocator, std.mem.span(sdl_extensions[i])); - - return extensions; - } - fn initVulkan(self: *Self) !void { self.window = c.SDL_CreateWindow("Spacecap", WIDTH, HEIGHT, c.SDL_WINDOW_VULKAN | c.SDL_WINDOW_RESIZABLE | c.SDL_WINDOW_HIGH_PIXEL_DENSITY); if (self.window == null) return error.SDL_CreateWindowFailure;