vulkan-tutorial 06

This commit is contained in:
David Allemang
2024-03-21 15:12:49 -04:00
parent 3bf7c4e61b
commit 02380af6ab
3 changed files with 102 additions and 70 deletions

View File

@@ -21,11 +21,14 @@ device: vk.Device,
queues: struct {
graphics: vk.Queue,
present: vk.Queue,
},
surface: vk.SurfaceKHR,
messenger: if (USE_DEBUG_LAYERS) vk.DebugUtilsMessengerEXT else void,
pub fn init(allocator: std.mem.Allocator) !Self {
pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
var self: Self = undefined;
self.allocator = allocator;
@@ -107,7 +110,7 @@ pub fn init(allocator: std.mem.Allocator) !Self {
.api_version = vk.API_VERSION_1_3,
};
const create_info = vk.InstanceCreateInfo{
const instance_create_info = vk.InstanceCreateInfo{
.p_application_info = &app_info,
.enabled_extension_count = @intCast(exts.items.len),
.pp_enabled_extension_names = exts.items.ptr,
@@ -116,7 +119,7 @@ pub fn init(allocator: std.mem.Allocator) !Self {
.p_next = if (USE_DEBUG_LAYERS) &debug_create_info else null,
};
self.instance = try vkb.createInstance(&create_info, null);
self.instance = try vkb.createInstance(&instance_create_info, null);
self.vki = try InstanceDispatch.load(self.instance, vkb.dispatch.vkGetInstanceProcAddr);
const vki = self.vki;
errdefer vki.destroyInstance(self.instance, null);
@@ -132,6 +135,20 @@ pub fn init(allocator: std.mem.Allocator) !Self {
null,
);
switch (c.glfwCreateWindowSurface(
self.instance,
window,
null,
&self.surface,
)) {
.success => {},
else => |e| {
std.log.err("{}", .{e});
return error.Unknown;
},
}
errdefer vki.destroySurfaceKHR(self.instance, self.surface, null);
var device_count: u32 = 0;
_ = try vki.enumeratePhysicalDevices(self.instance, &device_count, null);
const devices = try allocator.alloc(vk.PhysicalDevice, device_count);
@@ -170,35 +187,76 @@ pub fn init(allocator: std.mem.Allocator) !Self {
// todo this should be incorporated with physical device selection/ranking.
const Indices = struct {
graphics: u32,
present: u32,
};
const indices: Indices = find_index: {
var graphics: ?u32 = null;
var present: ?u32 = null;
for (queue_family_properties, 0..) |prop, idx| {
if (graphics == null and prop.queue_flags.graphics_bit) {
graphics = @intCast(idx);
// continue; // forces distinct queue families
}
if (graphics != null) {
break :find_index .{ .graphics = graphics.? };
if (present == null) {
const present_support = try vki.getPhysicalDeviceSurfaceSupportKHR(
selected.device,
@intCast(idx),
self.surface,
) == vk.TRUE;
if (present_support) {
present = @intCast(idx);
}
}
if (graphics != null and present != null) {
break :find_index .{
.graphics = graphics.?,
.present = present.?,
};
}
}
return error.IncompatibleDeviceQueues;
};
const priorities = [_]f32{1.0};
const queue_create_infos = [_]vk.DeviceQueueCreateInfo{
.{
const gp_priorities = [_]f32{ 1.0, 1.0 };
var queue_create_infos = std.ArrayList(vk.DeviceQueueCreateInfo).init(allocator);
defer queue_create_infos.deinit();
// queue info family indices must be unique. so if the graphics and present queues are the same, create two queues
// in the same family. otherwise create queues in separate families. there should probably be some general way to
// group and unpack the queues, but I'm not bothering with that for now until I restructure this monolithic function
// in general.
if (indices.graphics == indices.present) {
std.log.info("using one queue family", .{});
const gp_slice = gp_priorities[0..2];
try queue_create_infos.append(.{
.queue_family_index = indices.graphics,
.queue_count = priorities.len,
.p_queue_priorities = &priorities,
},
};
.queue_count = @intCast(gp_slice.len),
.p_queue_priorities = gp_slice.ptr,
});
} else {
std.log.info("using two queue families", .{});
const g_slice = gp_priorities[0..1];
const p_slice = gp_priorities[1..2];
try queue_create_infos.append(.{
.queue_family_index = indices.graphics,
.queue_count = @intCast(g_slice.len),
.p_queue_priorities = g_slice.ptr,
});
try queue_create_infos.append(.{
.queue_family_index = indices.present,
.queue_count = @intCast(p_slice.len),
.p_queue_priorities = p_slice.ptr,
});
}
const device_create_info = vk.DeviceCreateInfo{
.queue_create_info_count = queue_create_infos.len,
.p_queue_create_infos = &queue_create_infos,
.queue_create_info_count = @intCast(queue_create_infos.items.len),
.p_queue_create_infos = queue_create_infos.items.ptr,
.p_enabled_features = &selected.feats,
// .enabled_extension_count = @intCast(exts.items.len),
// .pp_enabled_extension_names = exts.items.ptr,
@@ -215,14 +273,25 @@ pub fn init(allocator: std.mem.Allocator) !Self {
const vkd = self.vkd;
errdefer vkd.destroyDevice(self.device, null);
self.queues = .{
.graphics = vkd.getDeviceQueue(self.device, indices.graphics, 0),
};
if (indices.graphics == indices.present) {
// two queues in the same family
self.queues = .{
.graphics = vkd.getDeviceQueue(self.device, indices.graphics, 0),
.present = vkd.getDeviceQueue(self.device, indices.present, 1),
};
} else {
// queues from different families
self.queues = .{
.graphics = vkd.getDeviceQueue(self.device, indices.graphics, 0),
.present = vkd.getDeviceQueue(self.device, indices.present, 0),
};
}
return self;
}
pub fn deinit(self: Self) void {
self.vki.destroySurfaceKHR(self.instance, self.surface, null);
self.vkd.destroyDevice(self.device, null);
if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT(
self.instance,
@@ -305,6 +374,8 @@ const InstanceDispatch = vk.InstanceWrapper(.{
.getPhysicalDeviceQueueFamilyProperties = true,
.createDevice = true,
.getDeviceProcAddr = true,
.destroySurfaceKHR = true,
.getPhysicalDeviceSurfaceSupportKHR = true,
});
const DeviceDispatch = vk.DeviceWrapper(.{

View File

@@ -1,42 +0,0 @@
const Self = @This();
const std = @import("std");
const c = @import("c.zig");
const vk = @import("vk");
const builtin = @import("builtin");
allocator: std.mem.Allocator,
window: *c.GLFWwindow,
pub fn mainLoop(self: Self) void {
while (c.glfwWindowShouldClose(self.window) == 0) : (c.glfwPollEvents()) {
c.glfwSwapBuffers(self.window);
}
}
pub fn init(
allocator: std.mem.Allocator,
width: u32,
height: u32,
title: []const u8,
) !Self {
var self: Self = undefined;
self.allocator = allocator;
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
self.window = c.glfwCreateWindow(
@intCast(width),
@intCast(height),
title.ptr,
null,
null,
) orelse return error.glfwCreateWindowFailed;
errdefer c.glfwDestroyWindow(self.window);
return self;
}
pub fn deinit(self: Self) void {
c.glfwDestroyWindow(self.window);
}

View File

@@ -2,7 +2,6 @@ const std = @import("std");
const c = @import("c.zig");
const vk = @import("vk");
const Window = @import("Window.zig");
const Context = @import("Context.zig");
pub fn main() !void {
@@ -15,16 +14,20 @@ pub fn main() !void {
}
defer c.glfwTerminate();
const ctx = try Context.init(allocator);
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
const window = c.glfwCreateWindow(
720,
1280,
"Hello World!",
null,
null,
) orelse return error.glfwCreateWindowFailed;
defer c.glfwDestroyWindow(window);
const ctx = try Context.init(allocator, window);
defer ctx.deinit();
const window = try Window.init(
allocator,
1280,
720,
"Hello World",
);
defer window.deinit();
window.mainLoop();
while (c.glfwWindowShouldClose(window) == 0) : (c.glfwPollEvents()) {
c.glfwSwapBuffers(window);
}
}