Introduce "Enumeration" type for vk.enumerate* results
This commit is contained in:
24
build.zig
24
build.zig
@@ -25,12 +25,24 @@ pub fn build(b: *std.Build) void {
|
|||||||
.use_pkg_config = .force,
|
.use_pkg_config = .force,
|
||||||
});
|
});
|
||||||
exe.linkLibC();
|
exe.linkLibC();
|
||||||
|
|
||||||
b.installArtifact(exe);
|
|
||||||
exe.root_module.addImport("vk", vkmod);
|
exe.root_module.addImport("vk", vkmod);
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
b.installArtifact(exe);
|
||||||
|
|
||||||
|
var docs_dir: std.Build.GeneratedFile = .{
|
||||||
|
.path = "docs",
|
||||||
|
.step = &exe.step,
|
||||||
|
};
|
||||||
|
exe.generated_docs = &docs_dir;
|
||||||
|
const docs = b.addInstallDirectory(.{
|
||||||
|
.source_dir = .{ .generated = &docs_dir },
|
||||||
|
.install_dir = .{ .custom = "docs" },
|
||||||
|
.install_subdir = "",
|
||||||
|
});
|
||||||
|
const docs_step = b.step("docs", "Build the docs");
|
||||||
|
docs_step.dependOn(&docs.step);
|
||||||
|
|
||||||
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
run_cmd.step.dependOn(b.getInstallStep());
|
run_cmd.step.dependOn(b.getInstallStep());
|
||||||
|
|
||||||
if (b.args) |args| {
|
if (b.args) |args| {
|
||||||
@@ -45,6 +57,12 @@ pub fn build(b: *std.Build) void {
|
|||||||
.target = target,
|
.target = target,
|
||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
});
|
});
|
||||||
|
exe_unit_tests.linkSystemLibrary2("glfw3", .{
|
||||||
|
.needed = true,
|
||||||
|
.preferred_link_mode = .static,
|
||||||
|
.use_pkg_config = .force,
|
||||||
|
});
|
||||||
|
exe_unit_tests.linkLibC();
|
||||||
|
|
||||||
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
const run_exe_unit_tests = b.addRunArtifact(exe_unit_tests);
|
||||||
|
|
||||||
|
163
src/Context.zig
163
src/Context.zig
@@ -10,7 +10,10 @@ const USE_DEBUG_LAYERS = switch (builtin.mode) {
|
|||||||
.ReleaseSmall, .ReleaseFast => false,
|
.ReleaseSmall, .ReleaseFast => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
const MAX_DEVICES = 16;
|
||||||
|
const MAX_DEVICE_EXTENSIONS = 512;
|
||||||
|
const MAX_INSTANCE_EXTENSIONS = 64;
|
||||||
|
const MAX_LAYERS = 512;
|
||||||
|
|
||||||
vkb: BaseDispatch,
|
vkb: BaseDispatch,
|
||||||
vki: InstanceDispatch,
|
vki: InstanceDispatch,
|
||||||
@@ -28,52 +31,79 @@ 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, window: *c.GLFWwindow) !Self {
|
fn Enumeration(comptime T: type, comptime cap: u32) type {
|
||||||
|
return struct {
|
||||||
|
buf: [cap]T = undefined,
|
||||||
|
len: u32 = 0,
|
||||||
|
|
||||||
|
const FULL: @This() = .{ .len = cap };
|
||||||
|
const EMPTY: @This() = .{ .len = 0 };
|
||||||
|
|
||||||
|
pub fn slice(self: anytype) switch (@TypeOf(&self.buf)) {
|
||||||
|
*[cap]T => []T,
|
||||||
|
*const [cap]T => []const T,
|
||||||
|
else => unreachable,
|
||||||
|
} {
|
||||||
|
return self.buf[0..self.len];
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn appendSlice(self: *@This(), source: []const T) !void {
|
||||||
|
if (self.len + source.len > cap) return error.Overflow;
|
||||||
|
@memcpy(self.buf[self.len..][0..source.len], source);
|
||||||
|
self.len += @intCast(source.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn append(self: *@This(), val: T) !void {
|
||||||
|
if (self.len + 1 > cap) return error.Overflow;
|
||||||
|
self.buf[self.len] = val;
|
||||||
|
self.len += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init(window: *c.GLFWwindow) !Self {
|
||||||
var self: Self = undefined;
|
var self: Self = undefined;
|
||||||
self.allocator = allocator;
|
|
||||||
|
|
||||||
self.vkb = try BaseDispatch.load(&c.glfwGetInstanceProcAddress);
|
self.vkb = try BaseDispatch.load(&c.glfwGetInstanceProcAddress);
|
||||||
const vkb = self.vkb;
|
const vkb = self.vkb;
|
||||||
|
|
||||||
var req_exts = std.ArrayList([*:0]const u8).init(allocator);
|
var req_exts = Enumeration([*:0]const u8, MAX_INSTANCE_EXTENSIONS).EMPTY;
|
||||||
defer req_exts.deinit();
|
var req_layers = Enumeration([*:0]const u8, MAX_LAYERS).EMPTY;
|
||||||
|
var req_dev_exts = Enumeration([*:0]const u8, MAX_DEVICE_EXTENSIONS).EMPTY;
|
||||||
|
|
||||||
var req_layers = std.ArrayList([*:0]const u8).init(allocator);
|
try req_dev_exts.append("VK_KHR_swapchain");
|
||||||
defer req_layers.deinit();
|
|
||||||
|
|
||||||
var req_device_exts = std.ArrayList([*:0]const u8).init(allocator);
|
|
||||||
defer req_device_exts.deinit();
|
|
||||||
|
|
||||||
if (USE_DEBUG_LAYERS) {
|
if (USE_DEBUG_LAYERS) {
|
||||||
try req_layers.append("VK_LAYER_KHRONOS_validation");
|
try req_layers.append("VK_LAYER_KHRONOS_validation");
|
||||||
try req_exts.append("VK_EXT_debug_utils");
|
try req_exts.append("VK_EXT_debug_utils");
|
||||||
}
|
}
|
||||||
|
|
||||||
try req_device_exts.append("VK_KHR_swapchain");
|
{
|
||||||
|
var glfw_ext_count: u32 = 0;
|
||||||
|
const glfw_exts: [*][*:0]const u8 = @ptrCast(c.glfwGetRequiredInstanceExtensions(&glfw_ext_count));
|
||||||
|
try req_exts.appendSlice(glfw_exts[0..glfw_ext_count]);
|
||||||
|
}
|
||||||
|
|
||||||
var glfw_ext_count: u32 = 0;
|
std.log.debug("requesting extensions: {s}", .{req_exts.slice()});
|
||||||
const glfw_exts: [*][*:0]const u8 = @ptrCast(c.glfwGetRequiredInstanceExtensions(&glfw_ext_count));
|
std.log.debug("requesting layers: {s}", .{req_layers.slice()});
|
||||||
try req_exts.appendSlice(glfw_exts[0..glfw_ext_count]);
|
std.log.debug("requesting device extensions: {s}", .{req_dev_exts.slice()});
|
||||||
|
|
||||||
std.log.debug("requesting extensions: {s}", .{req_exts.items});
|
var available_exts = Enumeration(vk.ExtensionProperties, MAX_INSTANCE_EXTENSIONS).FULL;
|
||||||
std.log.debug("requesting layers: {s}", .{req_layers.items});
|
_ = try vkb.enumerateInstanceExtensionProperties(
|
||||||
std.log.debug("requesting device extensions: {s}", .{req_device_exts.items});
|
null,
|
||||||
|
&available_exts.len,
|
||||||
|
&available_exts.buf,
|
||||||
|
);
|
||||||
|
|
||||||
var available_ext_count: u32 = 0;
|
var available_layers = Enumeration(vk.LayerProperties, MAX_LAYERS).FULL;
|
||||||
_ = try vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, null);
|
_ = try vkb.enumerateInstanceLayerProperties(
|
||||||
const available_exts = try allocator.alloc(vk.ExtensionProperties, available_ext_count);
|
&available_layers.len,
|
||||||
defer allocator.free(available_exts);
|
&available_layers.buf,
|
||||||
_ = try vkb.enumerateInstanceExtensionProperties(null, &available_ext_count, available_exts.ptr);
|
);
|
||||||
|
|
||||||
var available_layer_count: u32 = 0;
|
for (req_exts.slice()) |name| {
|
||||||
_ = try vkb.enumerateInstanceLayerProperties(&available_layer_count, null);
|
|
||||||
const available_layers = try allocator.alloc(vk.LayerProperties, available_layer_count);
|
|
||||||
defer allocator.free(available_layers);
|
|
||||||
_ = try vkb.enumerateInstanceLayerProperties(&available_layer_count, available_layers.ptr);
|
|
||||||
|
|
||||||
for (req_exts.items) |name| {
|
|
||||||
const required_name = std.mem.sliceTo(name, 0);
|
const required_name = std.mem.sliceTo(name, 0);
|
||||||
for (available_exts) |prop| {
|
for (available_exts.slice()) |prop| {
|
||||||
const available_name = std.mem.sliceTo(&prop.extension_name, 0);
|
const available_name = std.mem.sliceTo(&prop.extension_name, 0);
|
||||||
if (std.mem.eql(u8, required_name, available_name)) break;
|
if (std.mem.eql(u8, required_name, available_name)) break;
|
||||||
} else {
|
} else {
|
||||||
@@ -81,9 +111,9 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (req_layers.items) |name| {
|
for (req_layers.slice()) |name| {
|
||||||
const required_name = std.mem.sliceTo(name, 0);
|
const required_name = std.mem.sliceTo(name, 0);
|
||||||
for (available_layers) |prop| {
|
for (available_layers.slice()) |prop| {
|
||||||
const available_name = std.mem.sliceTo(&prop.layer_name, 0);
|
const available_name = std.mem.sliceTo(&prop.layer_name, 0);
|
||||||
if (std.mem.eql(u8, required_name, available_name)) break;
|
if (std.mem.eql(u8, required_name, available_name)) break;
|
||||||
} else {
|
} else {
|
||||||
@@ -118,10 +148,10 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
|
|
||||||
const instance_create_info = vk.InstanceCreateInfo{
|
const instance_create_info = vk.InstanceCreateInfo{
|
||||||
.p_application_info = &app_info,
|
.p_application_info = &app_info,
|
||||||
.enabled_extension_count = @intCast(req_exts.items.len),
|
.enabled_extension_count = req_exts.len,
|
||||||
.pp_enabled_extension_names = req_exts.items.ptr,
|
.pp_enabled_extension_names = &req_exts.buf,
|
||||||
.enabled_layer_count = @intCast(req_layers.items.len),
|
.enabled_layer_count = req_layers.len,
|
||||||
.pp_enabled_layer_names = req_layers.items.ptr,
|
.pp_enabled_layer_names = &req_layers.buf,
|
||||||
.p_next = if (USE_DEBUG_LAYERS) &debug_create_info else null,
|
.p_next = if (USE_DEBUG_LAYERS) &debug_create_info else null,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -155,15 +185,12 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
}
|
}
|
||||||
errdefer vki.destroySurfaceKHR(self.instance, self.surface, null);
|
errdefer vki.destroySurfaceKHR(self.instance, self.surface, null);
|
||||||
|
|
||||||
var device_count: u32 = 0;
|
var devices = Enumeration(vk.PhysicalDevice, MAX_DEVICES).FULL;
|
||||||
_ = try vki.enumeratePhysicalDevices(self.instance, &device_count, null);
|
_ = try vki.enumeratePhysicalDevices(
|
||||||
const devices = try allocator.alloc(vk.PhysicalDevice, device_count);
|
self.instance,
|
||||||
defer allocator.free(devices);
|
&devices.len,
|
||||||
_ = try vki.enumeratePhysicalDevices(self.instance, &device_count, devices.ptr);
|
&devices.buf,
|
||||||
|
);
|
||||||
var available_device_exts_count: u32 = 0;
|
|
||||||
var available_device_exts = std.ArrayList(vk.ExtensionProperties).init(allocator);
|
|
||||||
defer available_device_exts.deinit();
|
|
||||||
|
|
||||||
// todo some ranking strategy to find the most-suitable device
|
// todo some ranking strategy to find the most-suitable device
|
||||||
const Selection = struct {
|
const Selection = struct {
|
||||||
@@ -171,7 +198,7 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
props: vk.PhysicalDeviceProperties,
|
props: vk.PhysicalDeviceProperties,
|
||||||
feats: vk.PhysicalDeviceFeatures,
|
feats: vk.PhysicalDeviceFeatures,
|
||||||
};
|
};
|
||||||
const selected: Selection = find_device: for (devices) |device| {
|
const selected: Selection = find_device: for (devices.slice()) |device| {
|
||||||
const props = vki.getPhysicalDeviceProperties(device);
|
const props = vki.getPhysicalDeviceProperties(device);
|
||||||
const feats = vki.getPhysicalDeviceFeatures(device);
|
const feats = vki.getPhysicalDeviceFeatures(device);
|
||||||
|
|
||||||
@@ -179,23 +206,17 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
|
|
||||||
// if (feats.geometry_shader == vk.FALSE) continue;
|
// if (feats.geometry_shader == vk.FALSE) continue;
|
||||||
|
|
||||||
|
var available_dev_exts = Enumeration(vk.ExtensionProperties, MAX_DEVICE_EXTENSIONS).FULL;
|
||||||
_ = try vki.enumerateDeviceExtensionProperties(
|
_ = try vki.enumerateDeviceExtensionProperties(
|
||||||
device,
|
device,
|
||||||
null,
|
null,
|
||||||
&available_device_exts_count,
|
&available_dev_exts.len,
|
||||||
null,
|
&available_dev_exts.buf,
|
||||||
);
|
|
||||||
try available_device_exts.resize(available_device_exts_count);
|
|
||||||
_ = try vki.enumerateDeviceExtensionProperties(
|
|
||||||
device,
|
|
||||||
null,
|
|
||||||
&available_device_exts_count,
|
|
||||||
available_device_exts.items.ptr,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
for (req_device_exts.items) |name| {
|
for (req_dev_exts.slice()) |name| {
|
||||||
const required_name = std.mem.sliceTo(name, 0);
|
const required_name = std.mem.sliceTo(name, 0);
|
||||||
for (available_device_exts.items) |prop| {
|
for (available_dev_exts.slice()) |prop| {
|
||||||
const available_name = std.mem.sliceTo(&prop.extension_name, 0);
|
const available_name = std.mem.sliceTo(&prop.extension_name, 0);
|
||||||
if (std.mem.eql(u8, required_name, available_name)) break;
|
if (std.mem.eql(u8, required_name, available_name)) break;
|
||||||
} else {
|
} else {
|
||||||
@@ -213,11 +234,12 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
return error.NoSuitablePhysicalDevice;
|
return error.NoSuitablePhysicalDevice;
|
||||||
};
|
};
|
||||||
|
|
||||||
var queue_family_count: u32 = 0;
|
var queue_families = Enumeration(vk.QueueFamilyProperties, 64).FULL;
|
||||||
vki.getPhysicalDeviceQueueFamilyProperties(selected.device, &queue_family_count, null);
|
vki.getPhysicalDeviceQueueFamilyProperties(
|
||||||
const queue_family_properties = try allocator.alloc(vk.QueueFamilyProperties, queue_family_count);
|
selected.device,
|
||||||
defer allocator.free(queue_family_properties);
|
&queue_families.len,
|
||||||
vki.getPhysicalDeviceQueueFamilyProperties(selected.device, &queue_family_count, queue_family_properties.ptr);
|
&queue_families.buf,
|
||||||
|
);
|
||||||
|
|
||||||
// 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 {
|
||||||
@@ -228,7 +250,7 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
var graphics: ?u32 = null;
|
var graphics: ?u32 = null;
|
||||||
var present: ?u32 = null;
|
var present: ?u32 = null;
|
||||||
|
|
||||||
for (queue_family_properties, 0..) |prop, idx| {
|
for (queue_families.slice(), 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
|
// continue; // forces distinct queue families
|
||||||
@@ -258,8 +280,7 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
|
|
||||||
const gp_priorities = [_]f32{ 1.0, 1.0 };
|
const gp_priorities = [_]f32{ 1.0, 1.0 };
|
||||||
|
|
||||||
var queue_create_infos = std.ArrayList(vk.DeviceQueueCreateInfo).init(allocator);
|
var queue_create_infos = Enumeration(vk.DeviceQueueCreateInfo, 2).EMPTY;
|
||||||
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
|
// 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
|
// in the same family. otherwise create queues in separate families. there should probably be some general way to
|
||||||
@@ -288,13 +309,13 @@ pub fn init(allocator: std.mem.Allocator, window: *c.GLFWwindow) !Self {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const device_create_info = vk.DeviceCreateInfo{
|
const device_create_info = vk.DeviceCreateInfo{
|
||||||
.queue_create_info_count = @intCast(queue_create_infos.items.len),
|
.queue_create_info_count = queue_create_infos.len,
|
||||||
.p_queue_create_infos = queue_create_infos.items.ptr,
|
.p_queue_create_infos = &queue_create_infos.buf,
|
||||||
.p_enabled_features = &selected.feats,
|
.p_enabled_features = &selected.feats,
|
||||||
.enabled_extension_count = @intCast(req_device_exts.items.len),
|
.enabled_extension_count = req_dev_exts.len,
|
||||||
.pp_enabled_extension_names = req_device_exts.items.ptr,
|
.pp_enabled_extension_names = &req_dev_exts.buf,
|
||||||
.enabled_layer_count = @intCast(req_layers.items.len),
|
.enabled_layer_count = req_layers.len,
|
||||||
.pp_enabled_layer_names = req_layers.items.ptr,
|
.pp_enabled_layer_names = &req_layers.buf,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.device = try vki.createDevice(
|
self.device = try vki.createDevice(
|
||||||
|
@@ -5,10 +5,6 @@ const vk = @import("vk");
|
|||||||
const Context = @import("Context.zig");
|
const Context = @import("Context.zig");
|
||||||
|
|
||||||
pub fn main() !void {
|
pub fn main() !void {
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
||||||
const allocator = gpa.allocator();
|
|
||||||
defer _ = gpa.detectLeaks();
|
|
||||||
|
|
||||||
if (c.glfwInit() != c.GLFW_TRUE) {
|
if (c.glfwInit() != c.GLFW_TRUE) {
|
||||||
return error.GlfwInitFailed;
|
return error.GlfwInitFailed;
|
||||||
}
|
}
|
||||||
@@ -24,7 +20,7 @@ pub fn main() !void {
|
|||||||
) orelse return error.glfwCreateWindowFailed;
|
) orelse return error.glfwCreateWindowFailed;
|
||||||
defer c.glfwDestroyWindow(window);
|
defer c.glfwDestroyWindow(window);
|
||||||
|
|
||||||
const ctx = try Context.init(allocator, window);
|
const ctx = try Context.init(window);
|
||||||
defer ctx.deinit();
|
defer ctx.deinit();
|
||||||
|
|
||||||
while (c.glfwWindowShouldClose(window) == 0) : (c.glfwPollEvents()) {
|
while (c.glfwWindowShouldClose(window) == 0) : (c.glfwPollEvents()) {
|
||||||
|
Reference in New Issue
Block a user