move au into nu/render

This commit is contained in:
David Allemang
2024-07-09 15:17:26 -04:00
parent 1613b90ac5
commit 4f9a154176
10 changed files with 53 additions and 517 deletions

View File

@@ -6,17 +6,17 @@ const std = @import("std");
const builtin = @import("builtin");
const vk = @import("vk");
const ctx = @import("Render/Context.zig");
const au = @import("Render/au.zig");
pub const Options = struct {
app_name: []const u8 = "nu-au-app",
app_name: [*:0]const u8 = "nu-au-app",
app_version: struct {
variant: u3 = 0,
major: u7 = 0,
minor: u10 = 0,
patch: u12 = 0,
} = .{},
engine_name: []const u8 = "nu-au",
engine_name: [*:0]const u8 = "nu-au",
engine_version: struct {
variant: u3 = 0,
major: u7 = 0,
@@ -29,12 +29,12 @@ pub const Options = struct {
pub fn init(alloc: std.mem.Allocator) !void {
// todo make ctx not globals
try ctx.init(alloc);
errdefer ctx.deinit();
try au.init(alloc);
errdefer au.deinit();
}
pub fn frame() void {}
pub fn deinit() void {
ctx.deinit();
au.deinit();
}

View File

@@ -1,9 +1,12 @@
const std = @import("std");
const builtin = @import("builtin");
const vk = @import("vk");
const vk = @import("vk");
const nu = @import("../../nu.zig");
const Window = @import("../Window.zig");
pub const SwapChain = @import("au/SwapChain.zig");
pub const Flights = @import("au/Flights.zig");
pub const VkAllocator = @import("au/VkAllocator.zig");
pub const use_debug_messenger = switch (builtin.mode) {
.Debug, .ReleaseSafe => true,
@@ -27,24 +30,6 @@ pub const device_extensions: []const [*:0]const u8 = &.{
vk.extensions.khr_dynamic_rendering.name,
};
pub const app_info: vk.ApplicationInfo = .{
.p_application_name = nu.options.render.app_name,
.application_version = vk.makeApiVersion(
nu.options.render.app_version.variant,
nu.options.render.app_version.major,
nu.options.render.app_version.minor,
nu.options.render.app_version.patch,
),
.p_engine_name = nu.options.render.engine_name,
.engine_version = vk.makeApiVersion(
nu.options.render.engine_version.variant,
nu.options.render.engine_version.major,
nu.options.render.engine_version.minor,
nu.options.render.engine_version.patch,
),
.api_version = vk.API_VERSION_1_3,
};
pub const BaseWrapper = vk.BaseWrapper(apis);
pub const InstanceWrapper = vk.InstanceWrapper(apis);
pub const DeviceWrapper = vk.DeviceWrapper(apis);
@@ -58,6 +43,7 @@ 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;
@@ -70,14 +56,12 @@ 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;
var _surface: vk.SurfaceKHR = undefined;
pub fn init(
alloc: std.mem.Allocator,
) !void {
pub fn init(alloc: std.mem.Allocator) !void {
try init_base();
errdefer deinit_base();
@@ -95,6 +79,9 @@ pub fn deinit() void {
}
fn init_base() !void {
if (glfwVulkanSupported() != nu.Window.c.GLFW_TRUE)
return error.glfwNoVulkan;
if (use_debug_messenger) {
_bw = try BaseWrapper.load(glfwGetInstanceProcAddress);
} else {
@@ -145,10 +132,20 @@ fn init_instance(alloc: std.mem.Allocator) !void {
_instance = try B.createInstance(&.{
.p_application_info = &.{
.p_application_name = "zig-glfw-vulkan", // todo RenderOptions
.application_version = vk.makeApiVersion(0, 0, 0, 0),
.p_engine_name = "nu-au", // todo RenderOptions
.engine_version = vk.makeApiVersion(0, 0, 0, 0),
.p_application_name = nu.options.render.app_name,
.application_version = vk.makeApiVersion(
nu.options.render.app_version.variant,
nu.options.render.app_version.major,
nu.options.render.app_version.minor,
nu.options.render.app_version.patch,
),
.p_engine_name = nu.options.render.engine_name,
.engine_version = vk.makeApiVersion(
nu.options.render.engine_version.variant,
nu.options.render.engine_version.major,
nu.options.render.engine_version.minor,
nu.options.render.engine_version.patch,
),
.api_version = vk.API_VERSION_1_3,
},
.enabled_extension_count = @intCast(extensions.items.len),
@@ -166,7 +163,7 @@ fn init_instance(alloc: std.mem.Allocator) !void {
_ip = InstanceProxy.init(_instance, &_iw);
if (glfwCreateWindowSurface(_instance, Window.handle, null, &_surface) != .success) {
if (glfwCreateWindowSurface(_instance, nu.Window.handle, null, &_surface) != .success) {
return error.glfwCreateWindowSurfaceFailed;
}
}
@@ -376,13 +373,26 @@ pub fn debug_callback(
return vk.FALSE;
}
extern fn glfwGetInstanceProcAddress(instance: vk.Instance, procname: [*:0]const u8) vk.PfnVoidFunction;
extern fn glfwVulkanSupported() c_int;
extern fn glfwGetRequiredInstanceExtensions(count: *u32) [*]const [*:0]const u8;
extern fn glfwGetInstanceProcAddress(
instance: vk.Instance,
procname: [*:0]const u8,
) vk.PfnVoidFunction;
extern fn glfwGetPhysicalDevicePresentationSupport(
instance: vk.Instance,
pdev: vk.PhysicalDevice,
queuefamily: u32,
) c_int;
extern fn glfwCreateWindowSurface(
instance: vk.Instance,
window: *Window.c.GLFWwindow,
window: *nu.Window.c.GLFWwindow,
allocation_callbacks: ?*const vk.AllocationCallbacks,
surface: *vk.SurfaceKHR,
) vk.Result;
extern fn glfwGetRequiredInstanceExtensions(
count: *u32,
) [*][*:0]const u8;

293
src/nu/Render/au/Bus.zig Normal file
View File

@@ -0,0 +1,293 @@
const std = @import("std");
const vk = @import("vk");
const c = @import("../c.zig");
const Window = @import("../au.zig").Window;
const Self = @This();
alloc: std.mem.Allocator,
events: std.ArrayListUnmanaged(Event) = .{}, // todo bounded array?
drops: std.ArrayListUnmanaged([][]const u8) = .{}, // todo bounded array?
pub fn init(alloc: std.mem.Allocator) Self {
return .{
.alloc = alloc,
};
}
pub fn deinit(self: *Self) void {
self.clear();
self.events.deinit(self.alloc);
self.drops.deinit(self.alloc);
}
pub fn connect(self: *Self, window: *Window) !void {
// todo somehow prevent double-connect?
c.glfwSetWindowUserPointer(window.handle, self);
_ = c.glfwSetWindowPosCallback(window.handle, onWindowPos);
_ = c.glfwSetWindowSizeCallback(window.handle, onWindowSize);
_ = c.glfwSetWindowCloseCallback(window.handle, onWindowClose);
_ = c.glfwSetWindowRefreshCallback(window.handle, onWindowRefresh);
_ = c.glfwSetWindowFocusCallback(window.handle, onWindowFocus);
_ = c.glfwSetWindowIconifyCallback(window.handle, onWindowIconify);
_ = c.glfwSetWindowMaximizeCallback(window.handle, onWindowMaximize);
_ = c.glfwSetFramebufferSizeCallback(window.handle, onFramebufferSize);
_ = c.glfwSetWindowContentScaleCallback(window.handle, onWindowContentScale);
_ = c.glfwSetMouseButtonCallback(window.handle, onMouseButton);
_ = c.glfwSetCursorPosCallback(window.handle, onCursorPos);
_ = c.glfwSetCursorEnterCallback(window.handle, onCursorEnter);
_ = c.glfwSetScrollCallback(window.handle, onScroll);
_ = c.glfwSetKeyCallback(window.handle, onKey);
_ = c.glfwSetCharModsCallback(window.handle, onCharMods);
_ = c.glfwSetDropCallback(window.handle, onDrop);
}
pub fn disconnect(_: *Self, window: *Window) !void {
// todo somehow prevent double-disconnect?
c.glfwSetWindowUserPointer(window.handle, null);
_ = c.glfwSetWindowPosCallback(window.handle, null);
_ = c.glfwSetWindowSizeCallback(window.handle, null);
_ = c.glfwSetWindowCloseCallback(window.handle, null);
_ = c.glfwSetWindowRefreshCallback(window.handle, null);
_ = c.glfwSetWindowFocusCallback(window.handle, null);
_ = c.glfwSetWindowIconifyCallback(window.handle, null);
_ = c.glfwSetWindowMaximizeCallback(window.handle, null);
_ = c.glfwSetFramebufferSizeCallback(window.handle, null);
_ = c.glfwSetWindowContentScaleCallback(window.handle, null);
_ = c.glfwSetMouseButtonCallback(window.handle, null);
_ = c.glfwSetCursorPosCallback(window.handle, null);
_ = c.glfwSetCursorEnterCallback(window.handle, null);
_ = c.glfwSetScrollCallback(window.handle, null);
_ = c.glfwSetKeyCallback(window.handle, null);
_ = c.glfwSetCharModsCallback(window.handle, null);
_ = c.glfwSetDropCallback(window.handle, null);
}
pub fn clear(self: *Self) void {
for (self.drops.items) |drop| {
for (drop) |path| {
self.alloc.free(path);
}
self.alloc.free(drop);
}
self.drops.clearAndFree(self.alloc);
self.events.clearRetainingCapacity();
}
fn getBus(handle: ?*c.GLFWwindow) *Self {
return @alignCast(@ptrCast(c.glfwGetWindowUserPointer(handle)));
}
pub const Event = union(enum) {
const WindowPos = struct { x: i32, y: i32 };
const WindowSize = struct { x: i32, y: i32 };
const WindowClose = struct {};
const WindowRefresh = struct {};
const WindowFocus = struct { focused: bool };
const WindowIconify = struct { iconified: bool };
const WindowMaximize = struct { maximized: bool };
const FramebufferSize = struct { extent: vk.Extent2D };
const WindowContentScale = struct { x: f32, y: f32 };
const MouseButton = struct {
button: c_int, // todo enum
action: c_int, // todo enum
mods: c_int, // todo bitmask
};
const CursorPos = struct { x: f64, y: f64 };
const CursorEnter = struct { entered: bool };
const Scroll = struct { dx: f64, dy: f64 };
const Key = struct {
key: c_int, // todo enum
scan: c_int, // todo ???
action: c_int, // todo enum
mods: c_int, // todo bitmask
};
const Char = struct {
code: u21,
};
const CharMods = struct {
code: u21,
mods: c_int, // todo bitmask
};
const Drop = struct {
paths: []const []const u8,
};
windowPos: WindowPos,
windowSize: WindowSize,
windowClose: WindowClose,
windowRefresh: WindowRefresh,
windowFocus: WindowFocus,
windowIconify: WindowIconify,
windowMaximize: WindowMaximize,
framebufferSize: FramebufferSize,
windowContentScale: WindowContentScale,
mouseButton: MouseButton,
cursorPos: CursorPos,
cursorEnter: CursorEnter,
scroll: Scroll,
key: Key,
char: Char,
charMods: CharMods,
drop: Drop,
};
fn onWindowPos(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowPos = .{
.x = @intCast(x),
.y = @intCast(y),
},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowSize(handle: ?*c.GLFWwindow, x: c_int, y: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowSize = .{
.x = @intCast(x),
.y = @intCast(y),
},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowClose(handle: ?*c.GLFWwindow) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowClose = .{},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowRefresh(handle: ?*c.GLFWwindow) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowRefresh = .{},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowFocus(handle: ?*c.GLFWwindow, focused: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowFocus = .{
.focused = focused == c.GLFW_TRUE,
},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowIconify(handle: ?*c.GLFWwindow, iconified: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowIconify = .{
.iconified = iconified == c.GLFW_TRUE,
},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowMaximize(handle: ?*c.GLFWwindow, maximized: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowMaximize = .{
.maximized = maximized == c.GLFW_TRUE,
},
}) catch unreachable; // todo circular queue; warn
}
fn onFramebufferSize(handle: ?*c.GLFWwindow, width: c_int, height: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.framebufferSize = .{
.extent = .{
.width = @intCast(width),
.height = @intCast(height),
},
},
}) catch unreachable; // todo circular queue; warn
}
fn onWindowContentScale(handle: ?*c.GLFWwindow, x: f32, y: f32) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.windowContentScale = .{
.x = x,
.y = y,
},
}) catch unreachable; // todo circular queue; warn
}
fn onMouseButton(handle: ?*c.GLFWwindow, button: c_int, action: c_int, mods: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.mouseButton = .{
.button = button,
.action = action,
.mods = mods,
},
}) catch unreachable; // todo circular queue; warn
}
fn onCursorPos(handle: ?*c.GLFWwindow, x: f64, y: f64) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.cursorPos = .{
.x = x,
.y = y,
},
}) catch unreachable; // todo circular queue; warn
}
fn onCursorEnter(handle: ?*c.GLFWwindow, entered: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.cursorEnter = .{
.entered = entered == c.GLFW_TRUE,
},
}) catch unreachable; // todo circular queue; warn
}
fn onScroll(handle: ?*c.GLFWwindow, dx: f64, dy: f64) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.scroll = .{
.dx = dx,
.dy = dy,
},
}) catch unreachable; // todo circular queue; warn
}
fn onKey(handle: ?*c.GLFWwindow, key: c_int, scan: c_int, action: c_int, mods: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.key = .{
.key = key,
.scan = scan,
.action = action,
.mods = mods,
},
}) catch unreachable; // todo circular queue; warn
}
fn onCharMods(handle: ?*c.GLFWwindow, code: c_uint, mods: c_int) callconv(.C) void {
const bus = getBus(handle);
bus.events.append(bus.alloc, .{
.charMods = .{
.code = @intCast(code),
.mods = mods,
},
}) catch unreachable; // todo circular queue; warn
}
fn onDrop(handle: ?*c.GLFWwindow, count: c_int, paths: [*c][*c]const u8) callconv(.C) void {
const bus = getBus(handle);
const drops = bus.alloc.alloc([]const u8, @intCast(count)) catch unreachable; // todo warn
for (drops, paths) |*dst, src| {
dst.* = bus.alloc.dupe(u8, std.mem.sliceTo(src, 0)) catch unreachable; // todo warn
}
bus.drops.append(bus.alloc, drops) catch unreachable; // todo warn
bus.events.append(bus.alloc, .{
.drop = .{ .paths = drops },
}) catch unreachable; // todo circular queue; warn
}

View File

@@ -0,0 +1,57 @@
const std = @import("std");
const vk = @import("vk");
const au = @import("../au.zig");
const Self = @This();
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,
};
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];
}

View File

@@ -0,0 +1,208 @@
const std = @import("std");
const au = @import("../au.zig");
const vk = @import("vk");
const Self = @This();
alloc: std.mem.Allocator,
cinfo: vk.SwapchainCreateInfoKHR,
handle: vk.SwapchainKHR = .null_handle,
images: std.ArrayListUnmanaged(vk.Image) = .{},
views: std.ArrayListUnmanaged(vk.ImageView) = .{},
pub fn init(alloc: std.mem.Allocator) !Self {
const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, au.W.surface);
var min_image_count = @max(3, caps.min_image_count + 1); // todo magic numbers
if (caps.max_image_count > 0) {
min_image_count = @min(min_image_count, caps.max_image_count);
}
// determine format
const format = au.device_config.format;
return .{
.alloc = alloc,
.cinfo = .{
.surface = au.W.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 = au.device_config.mode,
.clipped = vk.TRUE,
.old_swapchain = .null_handle,
},
};
}
pub fn deinit(self: *Self) void {
for (self.views.items) |view| {
au.D.destroyImageView(view, null);
}
self.views.deinit(self.alloc);
self.images.deinit(self.alloc);
au.D.destroySwapchainKHR(self.handle, null);
}
/// mark that the swapchain _should_ be rebuilt with the given extent
/// this function is reentrant, so the swapchain can be marked multiple times
/// and only one rebuild occur
pub fn mark(self: *Self) void {
self.handle = .null_handle;
}
/// rebuild the swapchain only if it is marked. return true if the swapchain was rebuilt.
pub fn rebuild(self: *Self) !bool {
if (self.handle != .null_handle) return false;
const caps = try au.I.getPhysicalDeviceSurfaceCapabilitiesKHR(au.device_config.pdev, self.cinfo.surface);
self.cinfo.image_extent = caps.current_extent;
self.handle = try au.D.createSwapchainKHR(&self.cinfo, null);
au.D.destroySwapchainKHR(self.cinfo.old_swapchain, null);
self.cinfo.old_swapchain = self.handle;
var count: u32 = undefined;
_ = try au.D.getSwapchainImagesKHR(self.handle, &count, null);
try self.images.resize(self.alloc, count);
_ = try au.D.getSwapchainImagesKHR(self.handle, &count, self.images.items.ptr);
for (self.views.items) |view| {
au.D.destroyImageView(view, null);
}
try self.views.resize(self.alloc, count);
for (self.images.items, self.views.items) |image, *view| {
view.* = try au.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);
}
return true;
}
pub fn acquire(self: Self, semaphore: vk.Semaphore, fence: vk.Fence) !Target {
const acq = try au.D.acquireNextImageKHR(self.handle, std.math.maxInt(u64), semaphore, fence);
return .{
.idx = acq.image_index,
.image = self.images.items[acq.image_index],
.view = self.views.items[acq.image_index],
};
}
const Target = struct {
idx: u32,
image: vk.Image,
view: vk.ImageView,
pub fn begin_rendering(self: Target, cmd: au.CommandBufferProxy, area: vk.Rect2D) void {
cmd.pipelineBarrier(
.{ .top_of_pipe_bit = true },
.{ .color_attachment_output_bit = true },
.{},
0,
null,
0,
null,
1,
&.{
vk.ImageMemoryBarrier{
.src_access_mask = .{},
.dst_access_mask = .{ .color_attachment_write_bit = true },
.old_layout = .undefined,
.new_layout = .color_attachment_optimal,
.src_queue_family_index = 0,
.dst_queue_family_index = 0,
.image = self.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
},
},
);
cmd.beginRendering(&vk.RenderingInfo{
.render_area = area,
.layer_count = 1,
.view_mask = 0,
.color_attachment_count = 1,
.p_color_attachments = &.{
vk.RenderingAttachmentInfo{
.image_view = self.view,
.image_layout = .color_attachment_optimal,
.resolve_mode = .{},
.resolve_image_view = .null_handle,
.resolve_image_layout = .undefined,
.load_op = .clear,
.store_op = .store,
.clear_value = .{ .color = .{ .float_32 = .{ 0, 0, 0, 1 } } },
},
},
});
}
pub fn end_rendering(self: Target, cmd: au.CommandBufferProxy) void {
cmd.endRendering();
cmd.pipelineBarrier(
.{ .color_attachment_output_bit = true },
.{ .bottom_of_pipe_bit = true },
.{},
0,
null,
0,
null,
1,
&.{
vk.ImageMemoryBarrier{
.src_access_mask = .{ .color_attachment_write_bit = true },
.dst_access_mask = .{},
.old_layout = .color_attachment_optimal,
.new_layout = .present_src_khr,
.src_queue_family_index = 0,
.dst_queue_family_index = 0,
.image = self.image,
.subresource_range = .{
.aspect_mask = .{ .color_bit = true },
.base_mip_level = 0,
.level_count = 1,
.base_array_layer = 0,
.layer_count = 1,
},
},
},
);
}
};
pub fn present(self: Self, wait_semaphores: []const vk.Semaphore, target: Target) !vk.Result {
return try au.Q.presentKHR(&vk.PresentInfoKHR{
.wait_semaphore_count = @intCast(wait_semaphores.len),
.p_wait_semaphores = wait_semaphores.ptr,
.swapchain_count = 1,
.p_swapchains = &.{self.handle},
.p_image_indices = &.{target.idx},
.p_results = null,
});
}

View File

@@ -0,0 +1,43 @@
const std = @import("std");
const vk = @import("vk");
const au = @import("../au.zig");
const Self = @This();
props: vk.PhysicalDeviceMemoryProperties,
pub fn init() Self {
return .{
.props = au.I.getPhysicalDeviceMemoryProperties(au.device_config.pdev),
};
}
pub fn heaps(self: Self) []const vk.MemoryHeap {
return self.props.memory_heaps[0..self.props.memory_heap_count];
}
pub fn types(self: Self) []const vk.MemoryType {
return self.props.memory_types[0..self.props.memory_type_count];
}
pub fn alloc(self: Self, reqs: vk.MemoryRequirements, flags: vk.MemoryPropertyFlags) !vk.DeviceMemory {
const memory_type_bits: std.bit_set.IntegerBitSet(vk.MAX_MEMORY_TYPES) = .{
.mask = reqs.memory_type_bits,
};
for (self.types(), 0..) |typ, idx| {
if (!memory_type_bits.isSet(idx)) continue;
if (!typ.property_flags.contains(flags)) continue;
return try au.D.allocateMemory(&.{
.allocation_size = reqs.size,
.memory_type_index = @intCast(idx),
}, null);
}
return error.NoSuitableMemoryType;
}
pub fn free(_: Self, memory: vk.DeviceMemory) void {
au.D.freeMemory(memory, null);
}

90
src/nu/Render/au/ui.zig Normal file
View File

@@ -0,0 +1,90 @@
const std = @import("std");
const vk = @import("vk");
const im = @import("cimgui");
const au = @import("../au.zig");
const c = @import("../c.zig");
pub usingnamespace im.c;
pub fn loader_wrapper(procname: [*c]const u8, _: ?*anyopaque) callconv(.C) vk.PfnVoidFunction {
return c.glfwGetInstanceProcAddress(au.I.handle, procname);
}
var descriptor_pool: vk.DescriptorPool = undefined;
pub fn init(frames_in_flight: usize) !*im.c.ImGuiContext {
const ctx = im.c.igCreateContext(null) orelse return error.igCreateContextFailed;
errdefer im.c.igDestroyContext(ctx);
if (im.c.ImGui_ImplVulkan_LoadFunctions(loader_wrapper, null) != true) {
return error.igVulkanLoadFunctionsFailed;
}
if (im.c.ImGui_ImplGlfw_InitForVulkan(@ptrCast(au.W.handle), true) != true) {
return error.igGlfwInitFailed;
}
errdefer im.c.ImGui_ImplGlfw_Shutdown();
descriptor_pool = try au.D.createDescriptorPool(&vk.DescriptorPoolCreateInfo{
.flags = .{ .free_descriptor_set_bit = true },
.pool_size_count = 1,
.p_pool_sizes = &.{vk.DescriptorPoolSize{ .descriptor_count = 32, .type = .combined_image_sampler }},
.max_sets = 32,
}, null);
errdefer au.D.destroyDescriptorPool(descriptor_pool, null);
if (im.c.ImGui_ImplVulkan_Init(@constCast(&im.c.ImGui_ImplVulkan_InitInfo{
.Instance = @ptrFromInt(@intFromEnum(au.I.handle)),
.PhysicalDevice = @ptrFromInt(@intFromEnum(au.device_config.pdev)),
.Device = @ptrFromInt(@intFromEnum(au.D.handle)),
.QueueFamily = au.device_config.family,
.Queue = @ptrFromInt(@intFromEnum(au.Q.handle)),
.DescriptorPool = @ptrFromInt(@intFromEnum(descriptor_pool)),
.RenderPass = null,
.MinImageCount = 2,
.ImageCount = @intCast(frames_in_flight),
.PipelineRenderingCreateInfo = @bitCast(vk.PipelineRenderingCreateInfo{
.view_mask = 0,
.depth_attachment_format = .undefined,
.stencil_attachment_format = .undefined,
.color_attachment_count = 1,
.p_color_attachment_formats = &.{au.device_config.format.format},
}),
.MSAASamples = 0,
.PipelineCache = null,
.Subpass = 0,
.UseDynamicRendering = true,
.Allocator = null,
})) != true) {
return error.igVulkanInitFailed;
}
errdefer im.c.ImGui_ImplVulkan_Shutdown();
if (im.c.ImGui_ImplVulkan_CreateFontsTexture() != true) {
return error.igVulkanFontTextureFailed;
}
return ctx;
}
pub fn deinit(ctx: *im.c.ImGuiContext) void {
im.c.ImGui_ImplVulkan_Shutdown();
au.D.destroyDescriptorPool(descriptor_pool, null);
im.c.ImGui_ImplGlfw_Shutdown();
im.c.igDestroyContext(ctx);
}
pub fn NewFrame() void {
im.c.ImGui_ImplGlfw_NewFrame();
im.c.ImGui_ImplVulkan_NewFrame();
im.c.igNewFrame();
}
pub fn EndFrame() void {
im.c.igEndFrame();
im.c.igRender();
}
pub fn Draw(cmd: au.CommandBufferProxy) void {
im.c.ImGui_ImplVulkan_RenderDrawData(im.c.igGetDrawData(), @ptrFromInt(@intFromEnum(cmd.handle)), null);
}