diff --git a/build.zig b/build.zig index 3b3f3c2..3ea2aa8 100644 --- a/build.zig +++ b/build.zig @@ -143,6 +143,7 @@ fn import (builder: *std.Build, exe: *std.Build.Step.Compile, profile: *const Pr }); imgui.addImport ("c", c); imgui.addImport ("glfw", glfw_module); + imgui.addImport ("vk", vk_module); const build_options = profile.variables.createModule (); const logger = builder.createModule (.{ diff --git a/src/binding/glfw/glfw.zig b/src/binding/glfw/glfw.zig index 9029c42..1b1dd4f 100644 --- a/src/binding/glfw/glfw.zig +++ b/src/binding/glfw/glfw.zig @@ -17,6 +17,11 @@ pub const Events = struct { c.glfwWaitEvents (); } + + pub fn poll () void + { + c.glfwPollEvents (); + } }; pub const Monitor = struct diff --git a/src/binding/glfw/window.zig b/src/binding/glfw/window.zig index 737d121..59457ad 100644 --- a/src/binding/glfw/window.zig +++ b/src/binding/glfw/window.zig @@ -7,11 +7,6 @@ pub const Window = struct { handle: *c.GLFWwindow, - pub fn from (handle: *anyopaque) @This () - { - return .{ .handle = @as (*c.GLFWwindow, @ptrCast (@alignCast (handle))), }; - } - const Tag = enum { resizable, @@ -86,22 +81,6 @@ pub const Window = struct } }; - pub fn create (width: u32, height: u32, title: [*:0] const u8, - monitor: ?glfw.Monitor, share: ?@This (), hints: [] const glfw.Window.Hint) !@This () - { - for (hints) |hint| c.glfwWindowHint (hint.tag (), @intFromEnum (std.meta.activeTag (hint))); - if (c.glfwCreateWindow (@as (c_int, @intCast (width)), @as (c_int, @intCast (height)), - &title [0], if (monitor) |m| m.handle else null, if (share) |w| w.handle else null)) |handle| - return from (handle); - - return error.WindowInitFailed; - } - - pub fn destroy (self: @This ()) void - { - c.glfwDestroyWindow (self.handle); - } - pub const UserPointer = struct { pub fn get (comptime T: type) !?*T @@ -156,4 +135,30 @@ pub const Window = struct }; }; }; + + pub fn create (width: u32, height: u32, title: [*:0] const u8, + monitor: ?glfw.Monitor, share: ?@This (), hints: [] const glfw.Window.Hint) !@This () + { + for (hints) |hint| c.glfwWindowHint (hint.tag (), @intFromEnum (std.meta.activeTag (hint))); + if (c.glfwCreateWindow (@as (c_int, @intCast (width)), @as (c_int, @intCast (height)), + &title [0], if (monitor) |m| m.handle else null, if (share) |w| w.handle else null)) |handle| + return from (handle); + + return error.WindowInitFailed; + } + + pub fn destroy (self: @This ()) void + { + c.glfwDestroyWindow (self.handle); + } + + pub fn from (handle: *anyopaque) @This () + { + return .{ .handle = @as (*c.GLFWwindow, @ptrCast (@alignCast (handle))), }; + } + + pub fn shouldClose (self: @This ()) bool + { + return c.glfwWindowShouldClose (self.handle) == c.GLFW_TRUE; + } }; diff --git a/src/binding/imgui.zig b/src/binding/imgui.zig index eab380d..f486d1e 100644 --- a/src/binding/imgui.zig +++ b/src/binding/imgui.zig @@ -11,6 +11,33 @@ const imgui = @This (); pub const vk = struct { + pub const DrawData = struct + { + pub const Ex = struct + { + pub fn render (draw_data: *const c.ImGui_DrawData, command_buffer: binding.vk.Command.Buffer, pipeline: binding.vk.Pipeline) void + { + c.cImGui_ImplVulkan_RenderDrawDataEx (draw_data, @ptrFromInt (@intFromEnum (command_buffer)), @ptrFromInt (@intFromEnum (pipeline))); + } + }; + }; + + pub const FontsTexture = struct + { + pub fn create () !void + { + if (!c.cImGui_ImplVulkan_CreateFontsTexture ()) return error.ImGuiVulkanCreateFontsTexture; + } + }; + + pub const Frame = struct + { + pub fn new () void + { + c.cImGui_ImplVulkan_NewFrame (); + } + }; + pub const InitInfo = struct { Instance: binding.vk.Instance, @@ -18,8 +45,8 @@ pub const vk = struct Device: binding.vk.Device, QueueFamily: u32, Queue: binding.vk.Queue, - PipelineCache: binding.vk.PipelineCache, - DescriptorPool: binding.vk.DescriptorPool, + PipelineCache: binding.vk.Pipeline.Cache, + DescriptorPool: binding.vk.Descriptor.Pool, Subpass: u32, MinImageCount: u32, ImageCount: u32, @@ -29,23 +56,63 @@ pub const vk = struct Allocator: [*c] const binding.vk.AllocationCallbacks, CheckVkResultFn: ?*const fn (c_int) callconv (binding.vk.call_conv) void, }; + + fn loader (function_name: [*c] const u8, instance: ?*anyopaque) callconv (binding.vk.call_conv) ?*const fn () callconv (binding.vk.call_conv) void + { + return c.vkGetInstanceProcAddr (if (instance) |v| @as (c.VkInstance, @ptrCast (v)) else null, function_name); + } + + pub fn load () !void + { + if (!c.cImGui_ImplVulkan_LoadFunctions (loader)) return error.ImGuiVulkanLoadFunctionsFailure; + } + + pub fn init (init_info: *imgui.vk.InitInfo) !void + { + if (!c.cImGui_ImplVulkan_Init (@ptrCast (init_info))) return error.ImGuiVulkanInitFailure; + } + + pub fn shutdown () void + { + imgui.cImGui_ImplVulkan_Shutdown (); + } }; pub const glfw = struct { + pub const Frame = struct + { + pub fn new () void + { + c.cImGui_ImplGlfw_NewFrame (); + } + }; + pub fn init () !void { const window = try binding.glfw.Context.get (); if (!c.cImGui_ImplGlfw_InitForVulkan (@ptrCast (window), true)) return error.ImGuiGlfwInitForVulkanFailure; } + + pub fn shutdown () void + { + imgui.cImGui_ImplGlfw_Shutdown (); + } }; +pub const Cond = c.ImGuiCond; + pub const Context = struct { pub fn create () !void { if (c.ImGui_CreateContext (null) == null) return error.ImGuiCreateContextFailure; } + + pub fn destroy () void + { + c.ImGui_DestroyContext (null); + } }; pub const Col = struct @@ -53,6 +120,65 @@ pub const Col = struct pub const WindowBg = c.ImGuiCol_WindowBg; }; +pub const DrawData = struct +{ + pub fn get () *const c.ImDrawData + { + return &(c.ImGui_GetDrawData ().*); + } +}; + +pub const Ex = struct +{ + pub fn button (label: [] const u8, size: imgui.Vec2) bool + { + return c.ImGui_ButtonEx (label, size); + } + + pub fn sameline (offset_from_start_x: f32, spacing: f32) void + { + c.ImGui_SameLineEx (offset_from_start_x, spacing); + } +}; + +pub const Frame = struct +{ + pub fn new () void + { + c.ImGui_NewFrame (); + } +}; + +pub const IO = struct +{ + pub fn get () *const c.ImGuiIO + { + return &(c.ImGui_GetIO ().*); + } +}; + +pub const NextWindow = struct +{ + pub const Pos = struct + { + pub const Ex = struct + { + pub fn set (pos: imgui.Vec2, cond: imgui.Cond, pivot: imgui.Vec2) void + { + c.ImGui_SetNextWindowPosEx (pos, cond, pivot); + } + }; + }; + + pub const Size = struct + { + pub fn set (size: imgui.Vec2, cond: imgui.Cond) void + { + c.ImGui_SetNextWindowSize (size, cond); + } + }; +}; + pub const Style = struct { pub fn colorsDark () void @@ -95,3 +221,38 @@ pub const Style = struct } } }; + +pub const Vec2 = c.ImVec2; + +pub const Window = struct +{ + pub const Flags = c.ImGuiWindowFlags_; + + pub const Bit = enum (imgui.Window.Flags) + { + NO_COLLAPSE = c.ImGuiWindowFlags_NoCollapse, + NO_MOVE = c.ImGuiWindowFlags_NoMove, + NO_RESIZE = c.ImGuiWindowFlags_NoResize, + NO_TITLE_BAR = c.ImGuiWindowFlags_NoTitleBar, + }; +}; + +pub fn begin (name: [] const u8, p_open: ?*bool, flags: imgui.Window.Flags) !void +{ + if (!imgui.ImGui_Begin (name, p_open, flags)) return error.ImGuiBeginFailure; +} + +pub fn end () void +{ + imgui.ImGui_End (); +} + +pub fn render () void +{ + imgui.ImGui_Render (); +} + +pub fn text (comptime fmt: [] const u8, args: anytype) void +{ + c.ImGui_Text (std.debug.comptimePrint (fmt, args)); +} diff --git a/src/binding/vk/command.zig b/src/binding/vk/command.zig index e5ee7f2..b21f026 100644 --- a/src/binding/vk/command.zig +++ b/src/binding/vk/command.zig @@ -130,6 +130,11 @@ pub const Command = extern struct }; }; + pub const Reset = extern struct + { + pub const Flags = u32; + }; + pub fn create (device: vk.Device, p_create_info: *const vk.Command.Pool.Create.Info, p_allocator: ?*const vk.AllocationCallbacks) !@This () { var command_pool: @This () = undefined; @@ -146,5 +151,15 @@ pub const Command = extern struct { raw.prototypes.device.vkDestroyCommandPool (device, command_pool, p_allocator); } + + pub fn reset (command_pool: @This (), device: vk.Device, flags: vk.Command.Pool.Reset.Flags) !void + { + const result = raw.prototypes.device.vkResetCommandPool (device, command_pool, flags); + if (result > 0) + { + std.debug.print ("{s} failed with {} status code\n", .{ @typeName (@This ()) ++ "." ++ @src ().fn_name, result, }); + return error.UnexpectedResult; + } + } }; }; diff --git a/src/binding/vk/device.zig b/src/binding/vk/device.zig index 7b98c73..7e4358a 100644 --- a/src/binding/vk/device.zig +++ b/src/binding/vk/device.zig @@ -72,6 +72,16 @@ pub const Device = enum (usize) return device; } + pub fn waitIdle (device: @This ()) !void + { + const result = raw.prototypes.device.vkDeviceWaitIdle (device); + if (result > 0) + { + std.debug.print ("{s} failed with {} status code\n", .{ @typeName (@This ()) ++ "." ++ @src ().fn_name, result, }); + return error.UnexpectedResult; + } + } + pub fn destroy (self: @This (), p_allocator: ?*const vk.AllocationCallbacks) void { raw.prototypes.device.vkDestroyDevice (self, p_allocator); diff --git a/src/binding/vk/format.zig b/src/binding/vk/format.zig index 47722f4..5ab3a30 100644 --- a/src/binding/vk/format.zig +++ b/src/binding/vk/format.zig @@ -12,6 +12,7 @@ pub const Format = enum (u32) R8G8B8_UNORM = c.VK_FORMAT_R8G8B8_UNORM, R8G8B8A8_UNORM = c.VK_FORMAT_R8G8B8A8_UNORM, R32G32_SFLOAT = c.VK_FORMAT_R32G32_SFLOAT, + UNDEFINED = c.VK_FORMAT_UNDEFINED, _, pub const Feature = extern struct diff --git a/src/context.zig b/src/context.zig index 0c557ff..9953965 100644 --- a/src/context.zig +++ b/src/context.zig @@ -30,7 +30,7 @@ pub const Context = struct const framebuffer = try self.glfw.get_framebuffer_size (); try self.vk.init (self.imgui, .{ .width = framebuffer.width, .height = framebuffer.height, }); - try self.logger.app ("init OK", .DEBUG, .{}); + try self.logger.app (.DEBUG, "init OK", .{}); return self; } @@ -45,7 +45,7 @@ pub const Context = struct const framebuffer = self.glfw.get_framebuffer_size (); try self.vk.loop (&(self.imgui), .{ .resized = framebuffer.resized, .width = framebuffer.width, .height = framebuffer.height, }, &arena, &allocator, options); } - try self.logger.app ("loop OK", .DEBUG, .{}); + try self.logger.app (.DEBUG, "loop OK", .{}); } pub fn cleanup (self: @This ()) !void @@ -53,6 +53,6 @@ pub const Context = struct self.imgui.cleanup (); try self.vk.cleanup (); try self.glfw.cleanup (); - try self.logger.app ("cleanup OK", .DEBUG, .{}); + try self.logger.app (.DEBUG, "cleanup OK", .{}); } }; diff --git a/src/glfw/context.zig b/src/glfw/context.zig index f7dfee3..1132a2b 100644 --- a/src/glfw/context.zig +++ b/src/glfw/context.zig @@ -123,8 +123,7 @@ pub const Context = struct pub fn looping (self: @This ()) bool { - const close_window = self.window.shouldClose (); - return !close_window; + return !self.window.shouldClose (); } pub fn loop (self: @This ()) !void diff --git a/src/imgui/context.zig b/src/imgui/context.zig index d4018ef..d52db44 100644 --- a/src/imgui/context.zig +++ b/src/imgui/context.zig @@ -9,23 +9,23 @@ const imgui = @import ("imgui"); pub const Context = struct { const Renderer = struct - { - instance: vk.Instance, - physical_device: vk.PhysicalDevice, - logical_device: vk.Device, - graphics_family: u32, - graphics_queue: vk.Queue, - descriptor_pool: vk.DescriptorPool, - render_pass: vk.RenderPass, - command_pool: vk.CommandPool, - command_buffer: vk.CommandBuffer, - }; + { + instance: vk.Instance, + physical_device: vk.PhysicalDevice, + logical_device: vk.Device, + graphics_family: u32, + graphics_queue: vk.Queue, + descriptor_pool: vk.Descriptor.Pool, + render_pass: vk.RenderPass, + command_pool: vk.Command.Pool, + command_buffer: vk.Command.Buffer, + }; pub const ImguiPrepare = enum - { - Nothing, - Screenshot, - }; + { + Nothing, + Screenshot, + }; glfw_win_size: glfw.Window.Size = undefined, init_window: bool = false, @@ -70,43 +70,39 @@ pub const Context = struct fn upload_fonts (self: @This (), renderer: Renderer) !void { - try renderer.device_dispatch.resetCommandPool (renderer.logical_device, renderer.command_pool, vk.CommandPoolResetFlags {}); - const begin_info = vk.CommandBufferBeginInfo + try renderer.command_pool.reset (renderer.logical_device, 0); + const begin_info = vk.Command.Buffer.Begin.Info { - .flags = vk.CommandBufferUsageFlags { .one_time_submit_bit = true, }, + .flags = @intFromEnum (vk.Command.Buffer.Usage.Bit.ONE_TIME_SUBMIT), }; - const command_buffers = [_] vk.CommandBuffer + const command_buffers = [_] vk.Command.Buffer { renderer.command_buffer, }; - try renderer.device_dispatch.beginCommandBuffer (command_buffers [0], &begin_info); + try command_buffers [0].begin (&begin_info); - if (!imgui.cImGui_ImplVulkan_CreateFontsTexture (@ptrFromInt (@intFromEnum (renderer.command_buffer)))) return error.ImGuiVulkanCreateFontsTextureFailure; + try imgui.vk.FontsTexture.create (); - const submit_info = [_] vk.SubmitInfo + const submit_info = [_] vk.Submit.Info { - vk.SubmitInfo - { - .command_buffer_count = command_buffers.len, - .p_command_buffers = &command_buffers, - }, + .{ + .command_buffer_count = command_buffers.len, + .p_command_buffers = &command_buffers, + }, }; - try renderer.device_dispatch.endCommandBuffer (command_buffers [0]); - try renderer.device_dispatch.queueSubmit (renderer.graphics_queue, 1, &submit_info, vk.Fence.null_handle); + try command_buffers [0].end (); + try renderer.graphics_queue.submit (1, &submit_info, .NULL_HANDLE); - try renderer.device_dispatch.deviceWaitIdle (renderer.logical_device); - imgui.cImGui_ImplVulkan_DestroyFontUploadObjects (); + try renderer.logical_device.waitIdle (); try self.logger.app (.DEBUG, "upload Imgui fonts OK", .{}); } pub fn init_vk (self: @This (), renderer: Renderer) !void { - const sample = vk.SampleCountFlags { .@"1_bit" = true, }; - const format = vk.Format.undefined; var init_info = imgui.vk.InitInfo { .Instance = renderer.instance, @@ -114,20 +110,20 @@ pub const Context = struct .Device = renderer.logical_device, .QueueFamily = renderer.graphics_family, .Queue = renderer.graphics_queue, - .PipelineCache = vk.PipelineCache.null_handle, + .PipelineCache = .NULL_HANDLE, .DescriptorPool = renderer.descriptor_pool, .Subpass = 0, .MinImageCount = 2, .ImageCount = 2, - .MSAASamples = sample.toInt (), + .MSAASamples = @intFromEnum (vk.Sample.Count.Bit.@"1"), .UseDynamicRendering = false, - .ColorAttachmentFormat = @intFromEnum (format), + .ColorAttachmentFormat = @intFromEnum (vk.Format.UNDEFINED), .Allocator = null, .CheckVkResultFn = check_vk_result, }; - if (!imgui.cImGui_ImplVulkan_LoadFunctions ()) return error.ImGuiVulkanLoadFunctionsFailure; - if (!imgui.cImGui_ImplVulkan_Init (@ptrCast (&init_info), @ptrFromInt (@intFromEnum (renderer.render_pass)))) return error.ImGuiVulkanInitFailure; + try imgui.vk.load (); + try imgui.vk.init (&init_info); try self.upload_fonts (renderer); @@ -139,18 +135,18 @@ pub const Context = struct if (framebuffer.height != self.glfw_win_size.height) { self.glfw_win_size.height = framebuffer.height; - const window_size = imgui.ImVec2 { .x = 0.0, .y = @floatFromInt (self.glfw_win_size.height), }; - imgui.ImGui_SetNextWindowSize (window_size, 0); + const window_size = imgui.Vec2 { .x = 0.0, .y = @floatFromInt (self.glfw_win_size.height), }; + imgui.NextWindow.Size.set (window_size, 0); } if (!self.init_window) { - const window_pos = imgui.ImVec2 { .x = 0.0, .y = 0.0, }; - const window_pivot = imgui.ImVec2 { .x = 0.0, .y = 0.0, }; - imgui.ImGui_SetNextWindowPosEx (window_pos, 0, window_pivot); + const window_pos = imgui.Vec2 { .x = 0.0, .y = 0.0, }; + const window_pivot = imgui.Vec2 { .x = 0.0, .y = 0.0, }; + imgui.NextWindow.Pos.Ex.set (window_pos, 0, window_pivot); - const window_size = imgui.ImVec2 { .x = 0.0, .y = @floatFromInt (self.glfw_win_size.height), }; - imgui.ImGui_SetNextWindowSize (window_size, 0); + const window_size = imgui.Vec2 { .x = 0.0, .y = @floatFromInt (self.glfw_win_size.height), }; + imgui.NextWindow.Size.set (window_size, 0); self.init_window = true; } @@ -160,45 +156,48 @@ pub const Context = struct { if (last_displayed_fps.* == null or (try std.time.Instant.now ()).since (last_displayed_fps.*.?) > std.time.ns_per_s) { - fps.* = imgui.ImGui_GetIO ().*.Framerate; + fps.* = imgui.IO.get ().Framerate; last_displayed_fps.* = try std.time.Instant.now (); } - imgui.ImGui_Text ("Average %.3f ms/frame (%.1f FPS)", 1000.0 / fps.*, fps.*); + imgui.text ("Average {d:.3} ms/frame ({d:.1} FPS)", .{ 1000.0 / fps.*, fps.*, }); } fn prepare_seed (tweak_me: anytype) void { - const button_size = imgui.ImVec2 { .x = 0, .y = 0, }; + const button_size = imgui.Vec2 { .x = 0, .y = 0, }; - if (imgui.ImGui_ButtonEx ("New seed", button_size)) tweak_me.seed.* = @intCast (@mod (std.time.milliTimestamp (), @as (i64, @intCast (std.math.maxInt (u32))))); + if (imgui.Ex.button ("New seed", button_size)) tweak_me.seed.* = @intCast (@mod (std.time.milliTimestamp (), @as (i64, @intCast (std.math.maxInt (u32))))); if (Logger.build.profile.eql (.DEFAULT)) { - imgui.ImGui_SameLineEx (0.0, -1.0); - imgui.ImGui_Text ("%u", tweak_me.seed.*); + imgui.Ex.sameline (0.0, -1.0); + imgui.text ("{}", .{ tweak_me.seed.*, }); } } fn prepare_screenshot (self: *@This ()) void { - const button_size = imgui.ImVec2 { .x = 0, .y = 0, }; + const button_size = imgui.Vec2 { .x = 0, .y = 0, }; // TODO: display window size - self.screenshot = imgui.ImGui_ButtonEx ("Take a screenshot", button_size); + self.screenshot = imgui.Ex.button ("Take a screenshot", button_size); } pub fn prepare (self: *@This (), last_displayed_fps: *?std.time.Instant, fps: *f32, framebuffer: struct { width: u32, height: u32, }, tweak_me: anytype) !ImguiPrepare { - imgui.cImGui_ImplVulkan_NewFrame (); - imgui.cImGui_ImplGlfw_NewFrame (); - imgui.ImGui_NewFrame (); + imgui.vk.Frame.new (); + imgui.glfw.Frame.new (); + imgui.Frame.new (); try self.prepare_pane (.{ .width = framebuffer.width, .height = framebuffer.height, }); - const window_flags = imgui.ImGuiWindowFlags_NoTitleBar | imgui.ImGuiWindowFlags_NoCollapse | imgui.ImGuiWindowFlags_NoResize | imgui.ImGuiWindowFlags_NoMove; + const window_flags = @intFromEnum (imgui.Window.Bit.NO_TITLE_BAR) | + @intFromEnum (imgui.Window.Bit.NO_COLLAPSE) | + @intFromEnum (imgui.Window.Bit.NO_RESIZE) | + @intFromEnum (imgui.Window.Bit.NO_MOVE); - if (!imgui.ImGui_Begin ("Tweaker", null, window_flags)) return error.ImGuiBeginFailure; + try imgui.begin ("Tweaker", null, window_flags); try self.prepare_fps (last_displayed_fps, fps); self.prepare_seed (tweak_me); @@ -207,26 +206,26 @@ pub const Context = struct // Return a boolean depending on the fact that the value of the variable changed or not //_ = imgui.ImGui_SliderFloat ("Float", tweak_me.f, 0.0, 1.0, "%.3f", 0); - imgui.ImGui_End (); - imgui.ImGui_Render (); + imgui.end (); + imgui.render (); try self.logger.app (.DEBUG, "start render Imgui OK", .{}); return if (self.screenshot) ImguiPrepare.Screenshot else ImguiPrepare.Nothing; } - pub fn render (self: @This (), command_buffer: vk.CommandBuffer) !void + pub fn render (self: @This (), command_buffer: vk.Command.Buffer) !void { - const pipeline = vk.Pipeline.null_handle; - imgui.cImGui_ImplVulkan_RenderDrawDataEx (imgui.ImGui_GetDrawData (), @ptrFromInt (@intFromEnum (command_buffer)), @ptrFromInt (@intFromEnum (pipeline))); + const pipeline: vk.Pipeline = .NULL_HANDLE; + imgui.vk.DrawData.Ex.render (imgui.DrawData.get (), command_buffer, pipeline); try self.logger.app (.DEBUG, "end render Imgui OK", .{}); } pub fn cleanup (self: @This ()) void { - imgui.cImGui_ImplVulkan_Shutdown (); - imgui.cImGui_ImplGlfw_Shutdown (); - imgui.ImGui_DestroyContext (null); + imgui.vk.shutdown (); + imgui.glfw.shutdown (); + imgui.Context.destroy (); try self.logger.app (.DEBUG, "cleanup Imgui OK", .{}); } diff --git a/src/vk/context.zig b/src/vk/context.zig index f5a5872..e7335c1 100644 --- a/src/vk/context.zig +++ b/src/vk/context.zig @@ -1619,7 +1619,6 @@ pub const Context = struct try self.init_sync_objects (); try imgui.init_vk (.{ - .device_dispatch = self.device_dispatch, .instance = self.instance.instance, .physical_device = self.physical_device.?, .logical_device = self.logical_device,