graphics_context incremental teardown

This commit is contained in:
David Allemang
2024-03-28 16:06:50 -04:00
parent 0f840a6422
commit 282e85db24
6 changed files with 155 additions and 247 deletions

29
box.zig
View File

@@ -1,29 +0,0 @@
const std = @import("std");
pub fn Box(comptime T: type) type {
return struct {
val: T,
};
}
pub fn AddBoxType(comptime LHS: type, comptime RHS: type) type {
const x = std.mem.zeroes(std.meta.FieldType(LHS, .val));
const y = std.mem.zeroes(std.meta.FieldType(RHS, .val));
return Box(@TypeOf(x + y));
}
pub fn addbox(lhs: anytype, rhs: anytype) AddBoxType(@TypeOf(lhs), @TypeOf(rhs)) {
return .{ .val = lhs.val + rhs.val };
}
test {
std.testing.refAllDecls(@This());
}
test "widen" {
const foo: Box(u8) = .{ .val = 99 };
const bar: Box(u16) = .{ .val = 599 };
const actual = addbox(foo, bar);
const expected: Box(u16) = .{ .val = 698 };
try std.testing.expectEqual(expected, actual);
}

75
src/gfx.zig Normal file
View File

@@ -0,0 +1,75 @@
const vk = @import("vk");
pub const BaseDispatch = vk.BaseWrapper(.{
.createInstance = true,
.getInstanceProcAddr = true,
});
pub const InstanceDispatch = vk.InstanceWrapper(.{
.destroyInstance = true,
.createDevice = true,
.destroySurfaceKHR = true,
.enumeratePhysicalDevices = true,
.getPhysicalDeviceProperties = true,
.enumerateDeviceExtensionProperties = true,
.getPhysicalDeviceSurfaceFormatsKHR = true,
.getPhysicalDeviceSurfacePresentModesKHR = true,
.getPhysicalDeviceSurfaceCapabilitiesKHR = true,
.getPhysicalDeviceQueueFamilyProperties = true,
.getPhysicalDeviceSurfaceSupportKHR = true,
.getPhysicalDeviceMemoryProperties = true,
.getDeviceProcAddr = true,
});
pub const DeviceDispatch = vk.DeviceWrapper(.{
.destroyDevice = true,
.getDeviceQueue = true,
.createSemaphore = true,
.createFence = true,
.createImageView = true,
.destroyImageView = true,
.destroySemaphore = true,
.destroyFence = true,
.getSwapchainImagesKHR = true,
.createSwapchainKHR = true,
.destroySwapchainKHR = true,
.acquireNextImageKHR = true,
.deviceWaitIdle = true,
.waitForFences = true,
.resetFences = true,
.queueSubmit = true,
.queuePresentKHR = true,
.createCommandPool = true,
.destroyCommandPool = true,
.allocateCommandBuffers = true,
.freeCommandBuffers = true,
.queueWaitIdle = true,
.createShaderModule = true,
.destroyShaderModule = true,
.createPipelineLayout = true,
.destroyPipelineLayout = true,
.createGraphicsPipelines = true,
.destroyPipeline = true,
.beginCommandBuffer = true,
.endCommandBuffer = true,
.allocateMemory = true,
.freeMemory = true,
.createBuffer = true,
.destroyBuffer = true,
.getBufferMemoryRequirements = true,
.mapMemory = true,
.unmapMemory = true,
.bindBufferMemory = true,
.cmdBeginRenderPass = true,
.cmdEndRenderPass = true,
.cmdBindPipeline = true,
.cmdDraw = true,
.cmdDrawIndexed = true,
.cmdSetViewport = true,
.cmdSetScissor = true,
.cmdBindVertexBuffers = true,
.cmdBindIndexBuffer = true,
.cmdCopyBuffer = true,
.cmdBeginRenderingKHR = true,
.cmdEndRenderingKHR = true,
});

6
src/gfx/Context.zig Normal file
View File

@@ -0,0 +1,6 @@
const std = @import("std");
const vk = @import("vk");
const d = @import("dispatch.zig");
const Self = @This();

View File

@@ -3,91 +3,21 @@ const vk = @import("vk");
const c = @import("c.zig");
const Allocator = std.mem.Allocator;
const gfx = @import("gfx.zig");
const BaseDispatch = gfx.BaseDispatch;
const InstanceDispatch = gfx.InstanceDispatch;
const DeviceDispatch = gfx.DeviceDispatch;
const required_device_extensions = [_][*:0]const u8{
vk.extension_info.khr_swapchain.name,
vk.extension_info.khr_dynamic_rendering.name,
};
const BaseDispatch = vk.BaseWrapper(.{
.createInstance = true,
.getInstanceProcAddr = true,
});
const InstanceDispatch = vk.InstanceWrapper(.{
.destroyInstance = true,
.createDevice = true,
.destroySurfaceKHR = true,
.enumeratePhysicalDevices = true,
.getPhysicalDeviceProperties = true,
.enumerateDeviceExtensionProperties = true,
.getPhysicalDeviceSurfaceFormatsKHR = true,
.getPhysicalDeviceSurfacePresentModesKHR = true,
.getPhysicalDeviceSurfaceCapabilitiesKHR = true,
.getPhysicalDeviceQueueFamilyProperties = true,
.getPhysicalDeviceSurfaceSupportKHR = true,
.getPhysicalDeviceMemoryProperties = true,
.getDeviceProcAddr = true,
});
const DeviceDispatch = vk.DeviceWrapper(.{
.destroyDevice = true,
.getDeviceQueue = true,
.createSemaphore = true,
.createFence = true,
.createImageView = true,
.destroyImageView = true,
.destroySemaphore = true,
.destroyFence = true,
.getSwapchainImagesKHR = true,
.createSwapchainKHR = true,
.destroySwapchainKHR = true,
.acquireNextImageKHR = true,
.deviceWaitIdle = true,
.waitForFences = true,
.resetFences = true,
.queueSubmit = true,
.queuePresentKHR = true,
.createCommandPool = true,
.destroyCommandPool = true,
.allocateCommandBuffers = true,
.freeCommandBuffers = true,
.queueWaitIdle = true,
.createShaderModule = true,
.destroyShaderModule = true,
.createPipelineLayout = true,
.destroyPipelineLayout = true,
.createGraphicsPipelines = true,
.destroyPipeline = true,
.beginCommandBuffer = true,
.endCommandBuffer = true,
.allocateMemory = true,
.freeMemory = true,
.createBuffer = true,
.destroyBuffer = true,
.getBufferMemoryRequirements = true,
.mapMemory = true,
.unmapMemory = true,
.bindBufferMemory = true,
.cmdBeginRenderPass = true,
.cmdEndRenderPass = true,
.cmdBindPipeline = true,
.cmdDraw = true,
.cmdDrawIndexed = true,
.cmdSetViewport = true,
.cmdSetScissor = true,
.cmdBindVertexBuffers = true,
.cmdBindIndexBuffer = true,
.cmdCopyBuffer = true,
.cmdBeginRenderingKHR = true,
.cmdEndRenderingKHR = true,
});
pub const GraphicsContext = struct {
vkb: BaseDispatch,
vki: InstanceDispatch,
vkd: DeviceDispatch,
instance: vk.Instance,
surface: vk.SurfaceKHR,
pdev: vk.PhysicalDevice,
props: vk.PhysicalDeviceProperties,
@@ -97,52 +27,28 @@ pub const GraphicsContext = struct {
graphics_queue: Queue,
present_queue: Queue,
pub fn init(allocator: Allocator, app_name: [*:0]const u8, window: *c.GLFWwindow) !GraphicsContext {
pub fn init(allocator: Allocator, instance: vk.Instance, surface: vk.SurfaceKHR, vki: InstanceDispatch) !GraphicsContext {
var self: GraphicsContext = undefined;
self.vkb = try BaseDispatch.load(c.glfwGetInstanceProcAddress);
self.vki = vki;
self.surface = surface;
var glfw_exts_count: u32 = 0;
const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count);
const app_info = vk.ApplicationInfo{
.p_application_name = app_name,
.application_version = vk.makeApiVersion(0, 0, 0, 0),
.p_engine_name = app_name,
.engine_version = vk.makeApiVersion(0, 0, 0, 0),
.api_version = vk.API_VERSION_1_3,
};
self.instance = try self.vkb.createInstance(&.{
.p_application_info = &app_info,
.enabled_extension_count = glfw_exts_count,
.pp_enabled_extension_names = @as([*]const [*:0]const u8, @ptrCast(glfw_exts)),
}, null);
self.vki = try InstanceDispatch.load(self.instance, self.vkb.dispatch.vkGetInstanceProcAddr);
errdefer self.vki.destroyInstance(self.instance, null);
self.surface = try createSurface(self.instance, window);
errdefer self.vki.destroySurfaceKHR(self.instance, self.surface, null);
const candidate = try pickPhysicalDevice(self.vki, self.instance, allocator, self.surface);
const candidate = try pickPhysicalDevice(vki, instance, allocator, surface);
self.pdev = candidate.pdev;
self.props = candidate.props;
self.dev = try initializeCandidate(self.vki, candidate);
self.vkd = try DeviceDispatch.load(self.dev, self.vki.dispatch.vkGetDeviceProcAddr);
self.dev = try initializeCandidate(vki, candidate);
self.vkd = try DeviceDispatch.load(self.dev, vki.dispatch.vkGetDeviceProcAddr);
errdefer self.vkd.destroyDevice(self.dev, null);
self.graphics_queue = Queue.init(self.vkd, self.dev, candidate.queues.graphics_family);
self.present_queue = Queue.init(self.vkd, self.dev, candidate.queues.present_family);
self.mem_props = self.vki.getPhysicalDeviceMemoryProperties(self.pdev);
self.mem_props = vki.getPhysicalDeviceMemoryProperties(self.pdev);
return self;
}
pub fn deinit(self: GraphicsContext) void {
self.vkd.destroyDevice(self.dev, null);
self.vki.destroySurfaceKHR(self.instance, self.surface, null);
self.vki.destroyInstance(self.instance, null);
}
pub fn deviceName(self: *const GraphicsContext) []const u8 {

View File

@@ -6,6 +6,8 @@ const GraphicsContext = @import("graphics_context.zig").GraphicsContext;
const Swapchain = @import("swapchain.zig").Swapchain;
const Allocator = std.mem.Allocator;
const gfx = @import("gfx.zig");
const app_name = "vulkan-zig triangle example";
const Vertex = extern struct {
@@ -50,7 +52,57 @@ const vertices = [_]Vertex{
const indices = [_]Index{ 4, 5, 6, 6, 5, 7 };
/// note: destroy with vki.destroyInstance(instance, null)
fn create_instance(vkb: gfx.BaseDispatch) !std.meta.Tuple(&.{ vk.Instance, gfx.InstanceDispatch }) {
var glfw_exts_count: u32 = 0;
const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count);
const instance = try vkb.createInstance(&vk.InstanceCreateInfo{
.p_application_info = &vk.ApplicationInfo{
.p_application_name = app_name,
.application_version = vk.makeApiVersion(0, 0, 0, 0),
.p_engine_name = app_name,
.engine_version = vk.makeApiVersion(0, 0, 0, 0),
.api_version = vk.API_VERSION_1_3,
},
.enabled_extension_count = glfw_exts_count,
.pp_enabled_extension_names = @ptrCast(glfw_exts),
}, null);
const vki = try gfx.InstanceDispatch.load(instance, vkb.dispatch.vkGetInstanceProcAddr);
return .{ instance, vki };
}
/// note: destroy with vki.destroySurfaceKHR(instance, surface, null)
fn create_surface(instance: vk.Instance, window: *c.GLFWwindow) !vk.SurfaceKHR {
var surface: vk.SurfaceKHR = undefined;
if (c.glfwCreateWindowSurface(instance, window, null, &surface) != .success) {
return error.SurfaceInitFailed;
}
return surface;
}
/// note: destroy with c.glfwDestroyWindow(window)
fn create_window(extent: vk.Extent2D, title: [*:0]const u8) !*c.GLFWwindow {
c.glfwWindowHintString(c.GLFW_X11_CLASS_NAME, "floating_window");
c.glfwWindowHintString(c.GLFW_X11_INSTANCE_NAME, "floating_window");
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
return c.glfwCreateWindow(
@intCast(extent.width),
@intCast(extent.height),
title,
null,
null,
) orelse error.WindowInitFailed;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
if (c.glfwInit() != c.GLFW_TRUE) return error.GlfwInitFailed;
defer c.glfwTerminate();
@@ -61,23 +113,18 @@ pub fn main() !void {
var extent = vk.Extent2D{ .width = 800, .height = 600 };
c.glfwWindowHintString(c.GLFW_X11_CLASS_NAME, "floating_window");
c.glfwWindowHintString(c.GLFW_X11_INSTANCE_NAME, "floating_window");
c.glfwWindowHint(c.GLFW_CLIENT_API, c.GLFW_NO_API);
const window = c.glfwCreateWindow(
@intCast(extent.width),
@intCast(extent.height),
app_name,
null,
null,
) orelse return error.WindowInitFailed;
const window = try create_window(extent, app_name);
defer c.glfwDestroyWindow(window);
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
const vkb = try gfx.BaseDispatch.load(c.glfwGetInstanceProcAddress);
const gc = try GraphicsContext.init(allocator, app_name, window);
const instance, const vki = try create_instance(vkb);
defer vki.destroyInstance(instance, null);
const surface = try create_surface(instance, window);
defer vki.destroySurfaceKHR(instance, surface, null);
const gc = try GraphicsContext.init(allocator, instance, surface, vki);
defer gc.deinit();
std.log.debug("Using device: {s}", .{gc.deviceName()});

View File

@@ -1,97 +0,0 @@
const std = @import("std");
const mat4f = mat(4, 4, f32);
const vec4f = mat(4, 1, f32);
const mat4i = mat(4, 4, i32);
const vec4i = mat(4, 1, i32);
const mat4u = mat(4, 4, u32);
const vec4u = mat(4, 1, u32);
pub fn mat(comptime R_: usize, comptime C_: usize, comptime T_: type) type {
return struct {
pub const Rows = R_;
pub const Cols = C_;
pub const T = T_;
data: [Cols][Rows]T,
pub fn mul(l: @This(), r: anytype) MatMulReturnType(@This(), @TypeOf(r)) {
return matmul(l, r);
}
};
}
fn MatMulReturnType(comptime L: type, comptime R: type) type {
if (L.Cols != R.Rows) @compileError("invalid dimensions");
const x: L.T = std.mem.zeroes(L.T);
const y: R.T = std.mem.zeroes(R.T);
const T = @TypeOf(x + y);
return mat(L.Rows, R.Cols, T);
}
pub fn matmul(lhs: anytype, rhs: anytype) MatMulReturnType(@TypeOf(lhs), @TypeOf(rhs)) {
@setFloatMode(.optimized);
const L = @TypeOf(lhs);
const R = @TypeOf(rhs);
const Ret = MatMulReturnType(L, R);
var res = std.mem.zeroes(Ret);
if (L.Cols != R.Rows) @compileError("invalid dimensions");
inline for (0..R.Cols) |col| {
inline for (0..L.Rows) |row| {
inline for (0..L.Cols) |k| {
res.data[col][row] += lhs.data[k][row] * rhs.data[col][k];
}
}
}
return res;
}
export fn c_matmul_f_4x4_1x4(lhs: *const anyopaque, rhs: *const anyopaque, out: *anyopaque) void {
const l: *const mat4f = @alignCast(@ptrCast(lhs));
const r: *const vec4f = @alignCast(@ptrCast(rhs));
const o: *vec4f = @alignCast(@ptrCast(out));
o.* = matmul(l.*, r.*);
}
export fn c_matmul_i_4x4_1x4(lhs: *const anyopaque, rhs: *const anyopaque, out: *anyopaque) void {
const l: *const mat4i = @alignCast(@ptrCast(lhs));
const r: *const vec4i = @alignCast(@ptrCast(rhs));
const o: *vec4i = @alignCast(@ptrCast(out));
o.* = matmul(l.*, r.*);
}
export fn c_matmul_u_4x4_1x4(lhs: *const anyopaque, rhs: *const anyopaque, out: *anyopaque) void {
const l: *const mat4u = @alignCast(@ptrCast(lhs));
const r: *const vec4u = @alignCast(@ptrCast(rhs));
const o: *vec4u = @alignCast(@ptrCast(out));
o.* = matmul(l.*, r.*);
}
test "matmul" {
// note, column major; it's transposed.
const m: mat4u = .{ .data = .{
.{ 85, 84, 87, 37 },
.{ 33, 54, 49, 83 },
.{ 96, 97, 3, 13 },
.{ 69, 12, 45, 77 },
} };
const u: vec4u = .{ .data = .{.{ 37, 69, 94, 87 }} };
const actual: vec4u = matmul(m, u);
const expect: vec4u = .{ .data = .{.{ 20449, 16996, 10797, 15017 }} };
try std.testing.expectEqualDeep(expect, actual);
}