move au into nu/render
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
@@ -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
293
src/nu/Render/au/Bus.zig
Normal 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
|
||||
}
|
57
src/nu/Render/au/Flights.zig
Normal file
57
src/nu/Render/au/Flights.zig
Normal 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];
|
||||
}
|
208
src/nu/Render/au/SwapChain.zig
Normal file
208
src/nu/Render/au/SwapChain.zig
Normal 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,
|
||||
});
|
||||
}
|
43
src/nu/Render/au/VkAllocator.zig
Normal file
43
src/nu/Render/au/VkAllocator.zig
Normal 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
90
src/nu/Render/au/ui.zig
Normal 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);
|
||||
}
|
Reference in New Issue
Block a user