nu simplified; working swapchain, queue, and validators.

it compiles, but initialization is not done

create debug messenger

Use proxies

wip swapchain

wip swapchain - stub usage

get device queue

wip swapchain - scaffolded with segfault

wip swapchain - fix segfault

wip swapchain - working, but resize broken. semaphore issue with naive handling

satisfy validation
This commit is contained in:
2024-11-21 23:03:08 -05:00
parent 9150224734
commit ccee3733b0
10 changed files with 890 additions and 137 deletions

298
src/nu/Render/ctx.zig Normal file
View File

@@ -0,0 +1,298 @@
const std = @import("std");
const builtin = @import("builtin");
const vk = @import("vk");
const nu = @import("../../nu.zig");
const Debug = @import("Debug.zig");
const config = nu.config.render;
pub const versions: []const vk.ApiInfo = &.{
vk.features.version_1_0,
vk.features.version_1_1,
vk.features.version_1_2,
vk.features.version_1_3,
};
pub const instance_exts: []const vk.ApiInfo = if (config.use_debug_messenger) &.{
vk.extensions.ext_debug_utils,
vk.extensions.khr_surface,
} else &.{};
pub const device_exts: []const vk.ApiInfo = &.{
vk.extensions.khr_swapchain,
vk.extensions.khr_dynamic_rendering,
vk.extensions.khr_timeline_semaphore,
};
pub const apis = versions ++ instance_exts ++ device_exts;
pub const layers: []const [*:0]const u8 =
if (config.use_debug_messenger) &.{
"VK_LAYER_KHRONOS_validation",
} else &.{};
pub const BaseWrapper = vk.BaseWrapper(apis);
pub const InstanceWrapper = vk.InstanceWrapper(apis);
pub const DeviceWrapper = vk.DeviceWrapper(apis);
pub const InstanceProxy = vk.InstanceProxy(apis);
pub const DeviceProxy = vk.DeviceProxy(apis);
pub const QueueProxy = vk.QueueProxy(apis);
pub const CommandBufferProxy = vk.CommandBufferProxy(apis);
var _iw: InstanceWrapper = undefined;
pub const iw: *const InstanceWrapper = &_iw;
var _dw: DeviceWrapper = undefined;
pub const dw: *const DeviceWrapper = &_dw;
var _B: BaseWrapper = undefined;
pub const B: *const BaseWrapper = &_B;
var _I: InstanceProxy = undefined;
pub const I: *const InstanceProxy = &_I;
var _D: DeviceProxy = undefined;
pub const D: *const DeviceProxy = &_D;
var _Q: QueueProxy = undefined;
pub const Q: *const QueueProxy = &_Q;
var _instance: vk.Instance = undefined;
pub const instance: *const vk.Instance = &_instance;
var _messenger: if (config.use_debug_messenger) vk.DebugUtilsMessengerEXT else void = undefined;
pub const messenger: *const if (config.use_debug_messenger) vk.DebugUtilsMessengerEXT else void = &_messenger;
var _surface: vk.SurfaceKHR = undefined;
pub const surface: *const vk.SurfaceKHR = &_surface;
var _pdevice: vk.PhysicalDevice = undefined;
pub const pdevice: *const vk.PhysicalDevice = &_pdevice;
var _device: vk.Device = undefined;
pub const device: *const vk.Device = &_device;
var _family: u32 = undefined;
pub const family: *const u32 = &_family;
var _queue: vk.Queue = undefined;
pub const queue: *const vk.Queue = &_queue;
pub fn init(alloc: std.mem.Allocator) !void {
_B = try BaseWrapper.load(glfwGetInstanceProcAddress);
_instance = try _create_instance(alloc);
_iw = try InstanceWrapper.load(_instance, glfwGetInstanceProcAddress);
errdefer _destroy_instance();
_I = InstanceProxy.init(_instance, iw);
if (config.use_debug_messenger) _messenger = try _create_messenger();
errdefer if (config.use_debug_messenger) _destroy_messenger();
_surface = try _create_surface();
errdefer _destroy_surface();
_pdevice = try _select_pdevice(alloc);
_family = try _select_queue_family_index(alloc); // only one queue supported
_device = try _create_device(alloc);
_dw = try DeviceWrapper.load(_device, iw.dispatch.vkGetDeviceProcAddr);
errdefer _destroy_device();
_D = DeviceProxy.init(_device, dw);
_queue = D.getDeviceQueue(_family, 0); // only one queue supported
_Q = QueueProxy.init(_queue, dw);
}
pub fn deinit() void {
_destroy_device();
_destroy_surface();
if (config.use_debug_messenger) _destroy_messenger();
_destroy_instance();
}
fn _create_instance(alloc: std.mem.Allocator) !vk.Instance {
var extnames = std.ArrayList([*:0]const u8).init(alloc);
defer extnames.deinit();
for (instance_exts) |ext|
try extnames.append(ext.name);
var glfw_exts_count: u32 = 0;
const glfw_exts: [*]const [*:0]const u8 =
glfwGetRequiredInstanceExtensions(&glfw_exts_count);
try extnames.appendSlice(glfw_exts[0..glfw_exts_count]);
var ci: vk.InstanceCreateInfo = .{
.p_application_info = &vk.ApplicationInfo{
.p_application_name = config.app_name,
.application_version = vk.makeApiVersion(
config.app_version.variant,
config.app_version.major,
config.app_version.minor,
config.app_version.patch,
),
.p_engine_name = config.engine_name,
.engine_version = vk.makeApiVersion(
config.engine_version.variant,
config.engine_version.major,
config.engine_version.minor,
config.engine_version.patch,
),
.api_version = vk.features.version_1_3.version,
},
.enabled_extension_count = @intCast(extnames.items.len),
.pp_enabled_extension_names = extnames.items.ptr,
.enabled_layer_count = @intCast(layers.len),
.pp_enabled_layer_names = layers.ptr,
};
if (config.use_debug_messenger) ci.p_next = &Debug.ci;
return try B.createInstance(&ci, null);
}
fn _destroy_instance() void {
I.destroyInstance(null);
}
fn _create_messenger() !vk.DebugUtilsMessengerEXT {
return try I.createDebugUtilsMessengerEXT(&Debug.ci, null);
}
fn _destroy_messenger() void {
I.destroyDebugUtilsMessengerEXT(_messenger, null);
}
fn _create_surface() !vk.SurfaceKHR {
var res: vk.SurfaceKHR = undefined;
if (glfwCreateWindowSurface(
_instance,
nu.Window.handle,
null,
&res,
) != .success) {
return error.CreateWindowSurfaceFailed;
}
return res;
}
fn _destroy_surface() void {
I.destroySurfaceKHR(_surface, null);
}
fn _select_pdevice(alloc: std.mem.Allocator) !vk.PhysicalDevice {
var count: u32 = undefined;
_ = try I.enumeratePhysicalDevices(
&count,
null,
);
const pdevs = try alloc.alloc(vk.PhysicalDevice, count);
defer alloc.free(pdevs);
_ = try I.enumeratePhysicalDevices(
&count,
pdevs.ptr,
);
const scores = try alloc.alloc(i32, count);
@memset(scores, 0);
defer alloc.free(scores);
for (pdevs, scores) |pdev, *score| {
const props = I.getPhysicalDeviceProperties(pdev);
score.* += switch (props.device_type) {
.discrete_gpu => 1000,
.integrated_gpu => 500,
else => 0,
};
}
const idx = std.mem.indexOfMax(i32, scores);
return pdevs[idx];
}
fn _select_queue_family_index(alloc: std.mem.Allocator) !u32 {
var count: u32 = undefined;
I.getPhysicalDeviceQueueFamilyProperties(
_pdevice,
&count,
null,
);
const families = try alloc.alloc(vk.QueueFamilyProperties, count);
defer alloc.free(families);
I.getPhysicalDeviceQueueFamilyProperties(
_pdevice,
&count,
families.ptr,
);
for (families, 0..) |prop, idx| {
if (!prop.queue_flags.graphics_bit) continue;
if (!prop.queue_flags.transfer_bit) continue;
if (try I.getPhysicalDeviceSurfaceSupportKHR(
_pdevice,
@intCast(idx),
_surface,
) != vk.TRUE) continue;
return @intCast(idx);
}
return error.NoSuitableQueueFamily;
}
fn _create_device(alloc: std.mem.Allocator) !vk.Device {
const qci: []const vk.DeviceQueueCreateInfo = &.{
vk.DeviceQueueCreateInfo{
.queue_count = 1,
.queue_family_index = @intCast(_family),
.p_queue_priorities = &[_]f32{1.0},
},
};
var extnames = std.ArrayList([*:0]const u8).init(alloc);
defer extnames.deinit();
for (device_exts) |ext|
try extnames.append(ext.name);
const ci: vk.DeviceCreateInfo = .{
.queue_create_info_count = @intCast(qci.len),
.p_queue_create_infos = qci.ptr,
.enabled_extension_count = @intCast(extnames.items.len),
.pp_enabled_extension_names = extnames.items.ptr,
.p_next = &vk.PhysicalDeviceDynamicRenderingFeaturesKHR{
.dynamic_rendering = vk.TRUE,
},
};
return try I.createDevice(_pdevice, &ci, null);
}
fn _destroy_device() void {
D.deviceWaitIdle() catch |err| switch (err) {
error.OutOfHostMemory,
error.OutOfDeviceMemory,
error.DeviceLost,
=> {
// In these cases we would destroy the device anyway, so just fall through. Note any child objects must
// already be destroyed. This assumes normal cleanup has been done before _destroy_device was called.
},
else => unreachable,
};
D.destroyDevice(null);
}
pub extern fn glfwGetInstanceProcAddress(
instance: vk.Instance,
procname: [*:0]const u8,
) vk.PfnVoidFunction;
pub extern fn glfwGetPhysicalDevicePresentationSupport(
instance: vk.Instance,
pdev: vk.PhysicalDevice,
queuefamily: u32,
) c_int;
pub extern fn glfwCreateWindowSurface(
instance: vk.Instance,
window: *nu.Window.c.GLFWwindow,
allocation_callbacks: ?*const vk.AllocationCallbacks,
surface: *vk.SurfaceKHR,
) vk.Result;
pub extern fn glfwGetRequiredInstanceExtensions(
count: *u32,
) [*][*:0]const u8;