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 { queues: struct {
graphics: vk.Queue, graphics: vk.Queue,
present: vk.Queue,
}, },
surface: vk.SurfaceKHR,
messenger: if (USE_DEBUG_LAYERS) vk.DebugUtilsMessengerEXT else void, 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; var self: Self = undefined;
self.allocator = allocator; self.allocator = allocator;
@@ -107,7 +110,7 @@ pub fn init(allocator: std.mem.Allocator) !Self {
.api_version = vk.API_VERSION_1_3, .api_version = vk.API_VERSION_1_3,
}; };
const create_info = vk.InstanceCreateInfo{ const instance_create_info = vk.InstanceCreateInfo{
.p_application_info = &app_info, .p_application_info = &app_info,
.enabled_extension_count = @intCast(exts.items.len), .enabled_extension_count = @intCast(exts.items.len),
.pp_enabled_extension_names = exts.items.ptr, .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, .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); self.vki = try InstanceDispatch.load(self.instance, vkb.dispatch.vkGetInstanceProcAddr);
const vki = self.vki; const vki = self.vki;
errdefer vki.destroyInstance(self.instance, null); errdefer vki.destroyInstance(self.instance, null);
@@ -132,6 +135,20 @@ pub fn init(allocator: std.mem.Allocator) !Self {
null, 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; var device_count: u32 = 0;
_ = try vki.enumeratePhysicalDevices(self.instance, &device_count, null); _ = try vki.enumeratePhysicalDevices(self.instance, &device_count, null);
const devices = try allocator.alloc(vk.PhysicalDevice, device_count); 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. // todo this should be incorporated with physical device selection/ranking.
const Indices = struct { const Indices = struct {
graphics: u32, graphics: u32,
present: u32,
}; };
const indices: Indices = find_index: { const indices: Indices = find_index: {
var graphics: ?u32 = null; var graphics: ?u32 = null;
var present: ?u32 = null;
for (queue_family_properties, 0..) |prop, idx| { for (queue_family_properties, 0..) |prop, idx| {
if (graphics == null and prop.queue_flags.graphics_bit) { if (graphics == null and prop.queue_flags.graphics_bit) {
graphics = @intCast(idx); graphics = @intCast(idx);
// continue; // forces distinct queue families
} }
if (graphics != null) { if (present == null) {
break :find_index .{ .graphics = graphics.? }; 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; return error.IncompatibleDeviceQueues;
}; };
const priorities = [_]f32{1.0}; const gp_priorities = [_]f32{ 1.0, 1.0 };
const queue_create_infos = [_]vk.DeviceQueueCreateInfo{
.{ 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_family_index = indices.graphics,
.queue_count = priorities.len, .queue_count = @intCast(gp_slice.len),
.p_queue_priorities = &priorities, .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{ const device_create_info = vk.DeviceCreateInfo{
.queue_create_info_count = queue_create_infos.len, .queue_create_info_count = @intCast(queue_create_infos.items.len),
.p_queue_create_infos = &queue_create_infos, .p_queue_create_infos = queue_create_infos.items.ptr,
.p_enabled_features = &selected.feats, .p_enabled_features = &selected.feats,
// .enabled_extension_count = @intCast(exts.items.len), // .enabled_extension_count = @intCast(exts.items.len),
// .pp_enabled_extension_names = exts.items.ptr, // .pp_enabled_extension_names = exts.items.ptr,
@@ -215,14 +273,25 @@ pub fn init(allocator: std.mem.Allocator) !Self {
const vkd = self.vkd; const vkd = self.vkd;
errdefer vkd.destroyDevice(self.device, null); errdefer vkd.destroyDevice(self.device, null);
if (indices.graphics == indices.present) {
// two queues in the same family
self.queues = .{ self.queues = .{
.graphics = vkd.getDeviceQueue(self.device, indices.graphics, 0), .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; return self;
} }
pub fn deinit(self: Self) void { pub fn deinit(self: Self) void {
self.vki.destroySurfaceKHR(self.instance, self.surface, null);
self.vkd.destroyDevice(self.device, null); self.vkd.destroyDevice(self.device, null);
if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT( if (USE_DEBUG_LAYERS) self.vki.destroyDebugUtilsMessengerEXT(
self.instance, self.instance,
@@ -305,6 +374,8 @@ const InstanceDispatch = vk.InstanceWrapper(.{
.getPhysicalDeviceQueueFamilyProperties = true, .getPhysicalDeviceQueueFamilyProperties = true,
.createDevice = true, .createDevice = true,
.getDeviceProcAddr = true, .getDeviceProcAddr = true,
.destroySurfaceKHR = true,
.getPhysicalDeviceSurfaceSupportKHR = true,
}); });
const DeviceDispatch = vk.DeviceWrapper(.{ 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 c = @import("c.zig");
const vk = @import("vk"); const vk = @import("vk");
const Window = @import("Window.zig");
const Context = @import("Context.zig"); const Context = @import("Context.zig");
pub fn main() !void { pub fn main() !void {
@@ -15,16 +14,20 @@ pub fn main() !void {
} }
defer c.glfwTerminate(); 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(); defer ctx.deinit();
const window = try Window.init( while (c.glfwWindowShouldClose(window) == 0) : (c.glfwPollEvents()) {
allocator, c.glfwSwapBuffers(window);
1280, }
720,
"Hello World",
);
defer window.deinit();
window.mainLoop();
} }