forked from vv/efemra
1
0
Fork 0

start writing vulkan api with pim as reference (thanks Kara!)

This commit is contained in:
Vivianne 2022-07-02 04:21:14 -07:00
parent d67688a5a3
commit 49226a528f
2 changed files with 337 additions and 0 deletions

View File

@ -0,0 +1,172 @@
const std = @import("std");
const vk = @import("vulkan");
const glfw = @import("glfw");
const settings = @import("settings");
const DebugMessenger = @import("debug.zig").DebugMessenger;
// TODO temp allocator
const allocator = std.heap.GeneralPurposeAllocator;
const Layers = struct {
pub const enabled = [_][*:0]u8{
if (settings.khronos_layer_on) "KHRONOS_validation" else void,
if (settings.assist_layer_on) "LUNARG_assistant_layer" else void,
};
};
const Extensions = struct {
const dev_standard = [_][*:0]u8{
"KHR_swapchain",
"EXT_memory_budget",
"EXT_hdr_metadata",
"KHR_shader_float16_int8",
"KHR_16bit_storage",
"KHR_push_descriptor",
"EXT_memory_priority",
"KHR_bind_memory2",
"KHR_shader_float_controls",
"KHR_spirv_1_4",
"EXT_conditional_rendering",
"KHR_draw_indirect_count",
};
const dev_rt = if (settings.rt_on) [_][*:0]u8{
"KHR_acceleration_structure",
"KHR_ray_tracing_pipeline",
"KHR_ray_query",
"KHR_deferred_host_operations",
} else {};
pub const dev = dev_standard ++ dev_rt;
pub const inst = [_][*:0]u8{
"KHR_get_physical_device_properties2",
"EXT_swapchain_colorspace",
if (settings.messenger_on) "EXT_debug_utils" else void,
};
};
pub const Instance = struct {
const Self = @This();
vkInst: vk.Instance,
messenger: DebugMessenger,
layers: [][*:0]const u8,
extensions: [][*:0]const u8,
pub fn init(self: Self) !void {
// TODO: do we absolutely need volk rn? Don't think so? volk init here
const avail_layers = try getAvailableLayers();
defer avail_layers.deinit();
const avail_exts = try getAvailableExtensions();
defer avail_exts.deinit();
self.layers = try getLayers(&avail_layers);
self.extensions = try getExtensions(&avail_exts);
const app_info = vk.ApplicationInfo{
.p_application_name = settings.app_name,
.application_version = vk.makeApiVersion(1, 0, 0, 0),
.p_engine_name = settings.engine_name,
.engine_version = vk.makeApiVersion(1, 0, 0, 0),
.api_version = vk.API_VERSION_1_2,
};
self.vkInst = try self.vkb.createInstance(&.{
.flags = .{},
.p_application_info = &app_info,
.enabled_layer_count = @intCast(u32, self.layers.len),
.pp_enabled_layer_names = self.layers.ptr,
.enabled_extension_count = @intCast(u32, self.extensions.len),
.pp_enabled_extension_names = self.extensions.ptr,
}, null);
self.messenger = DebugMessenger.init();
return self;
}
pub fn deinit(self: Self) void {
self.vki.destroyInstance(self.vkInst, null);
// TODO: remove when using temp allocator
self.layers.deinit();
self.extensions.deinit();
}
/// list all available layers
fn getAvailableLayers(self: Self) !std.StringArrayHashMap {
var count: u32 = undefined;
_ = try self.vki.enumerateInstanceLayerProperties(&count, null);
const list = try allocator.alloc(self.vki.LayerProperties, count);
defer allocator.free(list);
_ = try self.vki.enumerateInstanceLayerProperties(&count, list.ptr);
const hashMap = std.StringArrayHashMap(void).init(allocator);
try hashMap.ensureTotalCapacity(count);
// TODO log
std.debug.print("{} available instance layers", .{count});
for (list) |layer| {
std.debug.print("{s}", layer.layer_name);
hashMap.putAssumeCapacity(layer);
}
return hashMap;
}
fn getLayers(avail_layers: *std.StringArrayHashMap) !std.ArrayList([*:0]const u8) {
const list = try std.ArrayList([*:0]const u8).init(allocator);
for (Layers.enabled) |ext| {
if (avail_layers.contains(ext)) {
list.append(ext);
}
}
return list;
}
/// list all available extensions
fn getAvailableExtensions(self: Self) !std.StringArrayHashMap {
var count: u32 = undefined;
_ = try self.vki.enumerateInstanceExtensionProperties(&count, null);
const list = try allocator.alloc(self.vki.ExtensionProperties, count);
defer allocator.free(list);
_ = try self.vki.enumerateInstanceExtensionProperties(&count, list.ptr);
const hashMap = std.StringArrayHashMap(void).init(allocator);
try hashMap.ensureTotalCapacity(count);
// TODO log
std.debug.print("{} available instance extensions", count);
for (list) |ext| {
std.debug.print("{s}", ext.extension_name);
hashMap.putAssumeCapacity(ext);
}
return hashMap;
}
fn getExtensions(avail_exts: *std.StringArrayHashMap) !std.ArrayList([][*:0]const u8) {
const list = try std.ArrayList([*:0]const u8).init(allocator);
for (try glfw.getRequiredInstanceExtensions()) |ext| {
if (avail_exts.contains(ext)) {
list.append(ext);
}
}
for (Extensions.inst) |ext| {
if (avail_exts.contains(ext)) {
list.append(ext);
}
}
return list;
}
};

View File

@ -0,0 +1,165 @@
const std = @import("std");
const Instance = @import("instance.zig").Instance;
const Window = @import("window.zig").Window;
const Device = @import("device.zig").Device;
const Memory = @import("memory.zig").Memory;
const Framebuffer = @import("framebuffer.zig").Framebuffer;
const Swapchain = @import("swapchain.zig").Swapchain;
const Context = @import("context.zig").Context;
const MainPass = @import("main_pass.zig").MainPass;
const Display = @import("display.zig").Display;
const Command = @import("command.zig").Command;
var g_renderer: VulkanRenderer = undefined;
pub const VulkanRenderer = struct {
instance: Instance,
window: Window,
device: Device,
memory: Memory,
framebuffer: Framebuffer,
swapchain: Swapchain,
context: Context,
// sampler: Sampler, TODO
// texTable: TexTable, TODO
// bindings: Bindings, TODO
// targets: Targets, TODO
// meshSys: MeshSys, TODO
// imSys: ImSys, TODO
mainPass: MainPass,
const Self = @This();
pub fn init() !Self {
const self = Self{};
errdefer std.debug.print("failed to init VulkanRenderer", .{});
errdefer self.deinit();
try self.instance.init();
try windowInit(&self.window);
try self.device.init();
try self.memory.init();
try self.framebuffer.init();
try self.swapchain.init(null);
try self.context.init();
// try self.sampler.init();
// try self.texTable.init();
// try self.bindings.init();
// try self.targets.init();
// try self.meshSys.init();
// try self.imSys.init();
try self.mainPass.init();
return self;
}
pub fn update(self: Self) bool {
// TODO profiling
// base system update
{
self.swapchain.acquireSync();
self.swapchain.acquireImage();
self.memory.update();
}
// system update
{
// TODO: sampler/meshsys/imsys update
}
// setup phase
{
self.mainPass.setup();
// TODO textable update
Command.flush();
// TODO bindings update
}
// execute phase
self.mainPass.execute();
// present phase
self.swapchain.submit(Command.get());
// background work
{
// TODO upload lightmaps, imsys clear
Command.flush();
}
}
pub fn deinit(self: Self) void {
self.device.waitIdle();
// TODO: delete lightmap pack
self.mainPass.deinit();
// self.imSys.deinit();
// self.meshSys.deinit();
// self.targets.deinit();
// self.bindings.deinit();
// self.texTable.deinit();
// self.sampler.deinit();
// clear other passes here.
self.memory.finalize();
self.context.deinit();
self.swapchain.deinit();
self.framebuffer.deinit();
self.window.deinit();
self.memory.deinit();
self.device.deinit();
self.instance.deinit();
}
fn windowInit(window: *Window) !void {
// TODO: convar cv_fullscreen
const fullscreen = false;
const extents = try Display.getSize(fullscreen);
try window.init("efemra", extents, fullscreen);
// TODO: convar r_width/r_height set
// TODO: UISys_Init
}
fn windowDeinit(window: *Window) void {
// TODO: uisys_shutdown
// TODO: convar r_width/r_height unset
window.deinit();
}
fn windowUpdate(self: Self) !void {
if (!self.window.isOpen()) {
return error.WindowNotOpen;
}
// TODO: convar fullscreen change check
if (0) {
self.device.waitIdle();
// TODO: UI pass del
self.swapchain.deinit();
self.window.deinit();
self.window.init();
self.swapchain.init(null);
// TODO: UI pass new
}
if (self.window.updateSize()) {
try self.swapchain.recreate();
// TODO set r_width/r_height convar
}
if (!self.swapchain.handle) {
return error.NoSwapchainHandle;
}
self.targets.maybeRecreate();
}
};