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:
298
src/nu/Render/ctx.zig
Normal file
298
src/nu/Render/ctx.zig
Normal 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;
|
Reference in New Issue
Block a user