diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml index 0834b6c..0b0bc92 100644 --- a/.github/workflows/Build.yml +++ b/.github/workflows/Build.yml @@ -12,8 +12,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: mlugg/setup-zig@v2 - with: - version: 0.15.2 - name: Building run: zig build diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml index 18a3e00..892abff 100644 --- a/.github/workflows/Test.yml +++ b/.github/workflows/Test.yml @@ -12,8 +12,6 @@ jobs: steps: - uses: actions/checkout@v4 - uses: mlugg/setup-zig@v2 - with: - version: 0.15.2 - name: Building run: zig build diff --git a/build.zig b/build.zig index a41e2f4..bb11b64 100644 --- a/build.zig +++ b/build.zig @@ -73,6 +73,7 @@ pub fn build(b: *std.Build) !void { test_step.dependOn(&run_tests.step); const volk = b.lazyDependency("volk", .{}) orelse continue; + const kvf = b.lazyDependency("kvf", .{}) orelse continue; const c_test_exe = b.addExecutable(.{ .name = b.fmt("c_test_vulkan_{s}", .{impl.name}), @@ -84,6 +85,7 @@ pub fn build(b: *std.Build) !void { }); c_test_exe.root_module.addSystemIncludePath(volk.path("")); + c_test_exe.root_module.addSystemIncludePath(kvf.path("")); c_test_exe.root_module.addSystemIncludePath(vulkan_headers.path("include")); c_test_exe.root_module.addCSourceFile(.{ diff --git a/build.zig.zon b/build.zig.zon index 28d4eeb..3248d3a 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -5,6 +5,10 @@ .minimum_zig_version = "0.15.2", .dependencies = .{ + .compile_commands = .{ + .url = "git+https://github.com/the-argus/zig-compile-commands#f74e2d13e43fafab3a71e19557a0e1cfbf0f2e1b", + .hash = "zig_compile_commands-0.0.1-OZg5-a3CAACM-h32Kjb1obTMqrKGs9YoDhorVZ8-LGle", + }, .vulkan_headers = .{ .url = "git+https://github.com/KhronosGroup/Vulkan-Headers?ref=v1.4.330#ee3b5caaa7e372715873c7b9c390ee1c3ca5db25", .hash = "N-V-__8AAFXYAQKsK51AAGXB9HziPDFjS_DVUq6_QHVxHrBM", @@ -17,19 +21,20 @@ .url = "git+https://github.com/FObersteiner/zdt/?ref=v0.8.1#8b551a0a3e5ae64a32b5bad0e6a93119787b43af", .hash = "zdt-0.8.1-xr0_vAxUDwCJRDh9pcAS_mdZBIsvcGTtN-K8JJSWY4I6", }, - .volk = .{ - .url = "git+https://github.com/zeux/volk/#8f53cc717f50f142db4736f401d0b61956cd78f9", - .hash = "N-V-__8AAPn9BwCBHnaxOC_rffCpFI7QRfi5qBCLvov9EYK3", - .lazy = true, - }, .cpuinfo = .{ .url = "git+https://github.com/Kbz-8/cpuinfo-zig#77f82a1248194e7fb706967343c66021f8522766", .hash = "cpuinfo-0.1.0-V7dMLcghAADJuG7dkd3MnwDPZ232pBK_8uGjxY43eP5u", .lazy = true, }, - .compile_commands = .{ - .url = "git+https://github.com/the-argus/zig-compile-commands#f74e2d13e43fafab3a71e19557a0e1cfbf0f2e1b", - .hash = "zig_compile_commands-0.0.1-OZg5-a3CAACM-h32Kjb1obTMqrKGs9YoDhorVZ8-LGle", + .volk = .{ + .url = "git+https://github.com/zeux/volk/#8f53cc717f50f142db4736f401d0b61956cd78f9", + .hash = "N-V-__8AAPn9BwCBHnaxOC_rffCpFI7QRfi5qBCLvov9EYK3", + .lazy = true, + }, + .kvf = .{ + .url = "git+https://github.com/Kbz-8/KVF#492a2f8e08f5aa3f5e9c9869668829af3f483d26", + .hash = "N-V-__8AALuHAgC55XjEl7WQZIw2YjKvEwvE04FMHGtzVOH5", + .lazy = true, }, }, diff --git a/src/soft/SoftCommandPool.zig b/src/soft/SoftCommandPool.zig new file mode 100644 index 0000000..90d20f7 --- /dev/null +++ b/src/soft/SoftCommandPool.zig @@ -0,0 +1,39 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const base = @import("base"); + +const VkError = base.VkError; +const Device = base.Device; + +const Self = @This(); +pub const Interface = base.CommandPool; + +interface: Interface, + +pub fn create(device: *base.Device, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, allocator, info); + + interface.vtable = &.{ + .destroy = destroy, + .reset = reset, + }; + + self.* = .{ + .interface = interface, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn reset(interface: *Interface, flags: vk.CommandPoolResetFlags) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + _ = self; + _ = flags; +} diff --git a/src/soft/SoftDevice.zig b/src/soft/SoftDevice.zig index aad962b..62156ae 100644 --- a/src/soft/SoftDevice.zig +++ b/src/soft/SoftDevice.zig @@ -5,9 +5,11 @@ const builtin = @import("builtin"); const Debug = std.builtin.OptimizeMode.Debug; +const SoftQueue = @import("SoftQueue.zig"); + +const SoftCommandPool = @import("SoftCommandPool.zig"); const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); const SoftFence = @import("SoftFence.zig"); -const SoftQueue = @import("SoftQueue.zig"); const VkError = base.VkError; @@ -33,8 +35,10 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato interface.dispatch_table = &.{ .allocateMemory = allocateMemory, + .createCommandPool = createCommandPool, .createFence = createFence, .destroy = destroy, + .destroyCommandPool = destroyCommandPool, .destroyFence = destroyFence, .freeMemory = freeMemory, .getFenceStatus = getFenceStatus, @@ -99,6 +103,17 @@ pub fn waitForFences(_: *Interface, fences: []*base.Fence, waitForAll: bool, tim } } +// Command Pool functions ============================================================================================================================ + +pub fn createCommandPool(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!*base.CommandPool { + const pool = try SoftCommandPool.create(interface, allocator, info); + return &pool.interface; +} + +pub fn destroyCommandPool(_: *Interface, allocator: std.mem.Allocator, pool: *base.CommandPool) VkError!void { + pool.destroy(allocator); +} + // Memory functions ================================================================================================================================== pub fn allocateMemory(interface: *Interface, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*base.DeviceMemory { diff --git a/src/soft/SoftFence.zig b/src/soft/SoftFence.zig index 61b3581..733c5b2 100644 --- a/src/soft/SoftFence.zig +++ b/src/soft/SoftFence.zig @@ -13,11 +13,11 @@ mutex: std.Thread.Mutex, condition: std.Thread.Condition, is_signaled: bool, -pub fn create(device: *const Device, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*Self { +pub fn create(device: *Device, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; errdefer allocator.destroy(self); - var interface = try Interface.init(device, info); + var interface = try Interface.init(device, allocator, info); interface.vtable = &.{ .destroy = destroy, diff --git a/src/soft/SoftPhysicalDevice.zig b/src/soft/SoftPhysicalDevice.zig index 9bccd15..d0a84e3 100644 --- a/src/soft/SoftPhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -32,6 +32,8 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr interface.props.device_id = root.DEVICE_ID; interface.props.device_type = .cpu; + interface.props.limits.max_bound_descriptor_sets = 1024; // tmp + interface.mem_props.memory_type_count = 1; interface.mem_props.memory_types[0] = .{ .heap_index = 0, @@ -76,7 +78,7 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr }, // TODO: maybe add a compute specialized queue }; - interface.queue_family_props = std.ArrayList(vk.QueueFamilyProperties).fromOwnedSlice(queue_family_props[0..]); + interface.queue_family_props.appendSlice(allocator, queue_family_props[0..]) catch return VkError.OutOfHostMemory; // TODO: use Pytorch's cpuinfo someday const info = cpuinfo.get(allocator) catch return VkError.InitializationFailed; @@ -140,5 +142,6 @@ pub fn getSparseImageFormatProperties( pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + interface.queue_family_props.deinit(allocator); allocator.destroy(self); } diff --git a/src/soft/SoftQueue.zig b/src/soft/SoftQueue.zig index 5ddbaee..e8efc67 100644 --- a/src/soft/SoftQueue.zig +++ b/src/soft/SoftQueue.zig @@ -62,8 +62,6 @@ pub fn submit(interface: *Interface, info: []const vk.SubmitInfo, fence: ?*base. // TODO: commands executions - std.log.debug("Queue execution", .{}); - std.Thread.sleep(1_000_000_000); if (p_fence) |fence_obj| { fence_obj.signal() catch {}; } diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 123699e..c19ba26 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -7,6 +7,7 @@ pub const SoftDevice = @import("SoftDevice.zig"); pub const SoftPhysicalDevice = @import("SoftPhysicalDevice.zig"); pub const SoftQueue = @import("SoftQueue.zig"); +pub const SoftCommandPool = @import("SoftCommandPool.zig"); pub const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); pub const SoftFence = @import("SoftFence.zig"); diff --git a/src/vulkan/CommandPool.zig b/src/vulkan/CommandPool.zig new file mode 100644 index 0000000..53ba505 --- /dev/null +++ b/src/vulkan/CommandPool.zig @@ -0,0 +1,37 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const VkError = @import("error_set.zig").VkError; +const Device = @import("Device.zig"); + +const Self = @This(); +pub const ObjectType: vk.ObjectType = .command_pool; + +owner: *Device, +flags: vk.CommandPoolCreateFlags, +queue_family_index: u32, + +vtable: *const VTable, + +pub const VTable = struct { + destroy: *const fn (*Self, std.mem.Allocator) void, + reset: *const fn (*Self, vk.CommandPoolResetFlags) VkError!void, +}; + +pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!Self { + _ = allocator; + return .{ + .owner = device, + .flags = info.flags, + .queue_family_index = info.queue_family_index, + .vtable = undefined, + }; +} + +pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + self.vtable.destroy(self, allocator); +} + +pub inline fn reset(self: *Self, flags: vk.CommandPoolResetFlags) VkError!void { + try self.vtable.reset(self, flags); +} diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index a840927..e7ebdbb 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -4,10 +4,13 @@ const vk = @import("vulkan"); const Dispatchable = @import("Dispatchable.zig").Dispatchable; const VulkanAllocator = @import("VulkanAllocator.zig"); const VkError = @import("error_set.zig").VkError; + const PhysicalDevice = @import("PhysicalDevice.zig"); +const Queue = @import("Queue.zig"); + +const CommandPool = @import("CommandPool.zig"); const DeviceMemory = @import("DeviceMemory.zig"); const Fence = @import("Fence.zig"); -const Queue = @import("Queue.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .device; @@ -25,11 +28,13 @@ pub const VTable = struct { pub const DispatchTable = struct { allocateMemory: *const fn (*Self, std.mem.Allocator, *const vk.MemoryAllocateInfo) VkError!*DeviceMemory, + createCommandPool: *const fn (*Self, std.mem.Allocator, *const vk.CommandPoolCreateInfo) VkError!*CommandPool, createFence: *const fn (*Self, std.mem.Allocator, *const vk.FenceCreateInfo) VkError!*Fence, + destroy: *const fn (*Self, std.mem.Allocator) VkError!void, + destroyCommandPool: *const fn (*Self, std.mem.Allocator, *CommandPool) VkError!void, destroyFence: *const fn (*Self, std.mem.Allocator, *Fence) VkError!void, freeMemory: *const fn (*Self, std.mem.Allocator, *DeviceMemory) VkError!void, getFenceStatus: *const fn (*Self, *Fence) VkError!void, - destroy: *const fn (*Self, std.mem.Allocator) VkError!void, resetFences: *const fn (*Self, []*Fence) VkError!void, waitForFences: *const fn (*Self, []*Fence, bool, u64) VkError!void, }; @@ -66,7 +71,7 @@ pub fn createQueues(self: *Self, allocator: std.mem.Allocator, info: *const vk.D } } -pub fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void { +pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void { var it = self.queues.iterator(); while (it.next()) |entry| { const family = entry.value_ptr; @@ -102,6 +107,16 @@ pub inline fn waitForFences(self: *Self, fences: []*Fence, waitForAll: bool, tim try self.dispatch_table.waitForFences(self, fences, waitForAll, timeout); } +// Command Pool functions ============================================================================================================================ + +pub inline fn createCommandPool(self: *Self, allocator: std.mem.Allocator, info: *const vk.CommandPoolCreateInfo) VkError!*CommandPool { + return self.dispatch_table.createCommandPool(self, allocator, info); +} + +pub inline fn destroyCommandPool(self: *Self, allocator: std.mem.Allocator, pool: *CommandPool) VkError!void { + try self.dispatch_table.destroyCommandPool(self, allocator, pool); +} + // Memory functions ================================================================================================================================== pub inline fn allocateMemory(self: *Self, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*DeviceMemory { diff --git a/src/vulkan/Fence.zig b/src/vulkan/Fence.zig index a3c3958..c30e3fa 100644 --- a/src/vulkan/Fence.zig +++ b/src/vulkan/Fence.zig @@ -7,7 +7,7 @@ const Device = @import("Device.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .fence; -owner: *const Device, +owner: *Device, flags: vk.FenceCreateFlags, vtable: *const VTable, @@ -20,7 +20,8 @@ pub const VTable = struct { wait: *const fn (*Self, u64) VkError!void, }; -pub fn init(device: *const Device, info: *const vk.FenceCreateInfo) VkError!Self { +pub fn init(device: *Device, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!Self { + _ = allocator; return .{ .owner = device, .flags = info.flags, diff --git a/src/vulkan/PhysicalDevice.zig b/src/vulkan/PhysicalDevice.zig index 9381203..7bc8263 100644 --- a/src/vulkan/PhysicalDevice.zig +++ b/src/vulkan/PhysicalDevice.zig @@ -35,7 +35,7 @@ pub fn init(allocator: std.mem.Allocator, instance: *const Instance) VkError!Sel .device_type = undefined, .device_name = [_]u8{0} ** vk.MAX_PHYSICAL_DEVICE_NAME_SIZE, .pipeline_cache_uuid = undefined, - .limits = undefined, + .limits = std.mem.zeroInit(vk.PhysicalDeviceLimits, .{}), .sparse_properties = undefined, }, .mem_props = .{ diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index aed84bf..a8ed39e 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -14,6 +14,7 @@ pub const Device = @import("Device.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); pub const Queue = @import("Queue.zig"); +pub const CommandPool = @import("CommandPool.zig"); pub const DeviceMemory = @import("DeviceMemory.zig"); pub const Fence = @import("Fence.zig"); diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 4d5d208..58abc51 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -19,6 +19,7 @@ const Device = @import("Device.zig"); const PhysicalDevice = @import("PhysicalDevice.zig"); const Queue = @import("Queue.zig"); +const CommandPool = @import("CommandPool.zig"); const DeviceMemory = @import("DeviceMemory.zig"); const Fence = @import("Fence.zig"); @@ -73,9 +74,11 @@ const physical_device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComp const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ functionMapEntryPoint("vkAllocateMemory"), + functionMapEntryPoint("vkCreateCommandPool"), + functionMapEntryPoint("vkCreateFence"), + functionMapEntryPoint("vkDestroyCommandPool"), functionMapEntryPoint("vkDestroyFence"), functionMapEntryPoint("vkDestroyDevice"), - functionMapEntryPoint("vkCreateFence"), functionMapEntryPoint("vkFreeMemory"), functionMapEntryPoint("vkGetDeviceQueue"), functionMapEntryPoint("vkGetFenceStatus"), @@ -291,6 +294,18 @@ pub export fn strollAllocateMemory(p_device: vk.Device, p_info: ?*const vk.Memor return .success; } +pub export fn strollCreateCommandPool(p_device: vk.Device, p_info: ?*const vk.CommandPoolCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_pool: *vk.CommandPool) callconv(vk.vulkan_call_conv) vk.Result { + const info = p_info orelse return .error_validation_failed; + if (info.s_type != .command_pool_create_info) { + return .error_validation_failed; + } + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const pool = device.createCommandPool(allocator, info) catch |err| return toVkResult(err); + p_pool.* = (NonDispatchable(CommandPool).wrap(allocator, pool) catch |err| return toVkResult(err)).toVkHandle(vk.CommandPool); + return .success; +} + pub export fn strollCreateFence(p_device: vk.Device, p_info: ?*const vk.FenceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_fence: *vk.Fence) callconv(vk.vulkan_call_conv) vk.Result { const info = p_info orelse return .error_validation_failed; if (info.s_type != .fence_create_info) { @@ -314,6 +329,15 @@ pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.All dispatchable.destroy(allocator); } +pub export fn strollDestroyCommandPool(p_device: vk.Device, p_pool: vk.CommandPool, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + const allocator = VulkanAllocator.init(callbacks, .object).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch return; + const non_dispatchable_pool = NonDispatchable(CommandPool).fromHandle(p_pool) catch return; + + device.destroyCommandPool(allocator, non_dispatchable_pool.object) catch return; + non_dispatchable_pool.destroy(allocator); +} + pub export fn strollDestroyFence(p_device: vk.Device, p_fence: vk.Fence, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { const allocator = VulkanAllocator.init(callbacks, .object).allocator(); const device = Dispatchable(Device).fromHandleObject(p_device) catch return; diff --git a/test/c/main.c b/test/c/main.c index 04a6972..7e7889e 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -1,6 +1,5 @@ #include #include -#include #define VK_NO_PROTOTYPES #include @@ -16,6 +15,11 @@ #define VOLK_IMPLEMENTATION #include +#define KVF_IMPLEMENTATION +#define KVF_ENABLE_VALIDATION_LAYERS +#define KVF_NO_KHR +#include + #define CheckVk(x) \ do { \ if((x) != VK_SUCCESS) \ @@ -49,60 +53,25 @@ int main(void) const char* extensions[] = { VK_LUNARG_DIRECT_DRIVER_LOADING_EXTENSION_NAME }; - VkInstanceCreateInfo instance_create_info = {}; - instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - instance_create_info.pApplicationInfo = NULL; - instance_create_info.enabledExtensionCount = 1; - instance_create_info.ppEnabledExtensionNames = extensions; - instance_create_info.pNext = &direct_driver_list; - - VkInstance instance = VK_NULL_HANDLE; - CheckVk(vkCreateInstance(&instance_create_info, NULL, &instance)); + VkInstance instance = kvfCreateInstanceNext(extensions, 1, &direct_driver_list); volkLoadInstance(instance); - uint32_t count; - vkEnumeratePhysicalDevices(instance, &count, NULL); - VkPhysicalDevice* physical_devices = (VkPhysicalDevice*)calloc(count, sizeof(VkPhysicalDevice)); - vkEnumeratePhysicalDevices(instance, &count, physical_devices); + VkPhysicalDevice physical_device = kvfPickGoodPhysicalDevice(instance, VK_NULL_HANDLE, NULL, 0); - VkPhysicalDeviceProperties props; - vkGetPhysicalDeviceProperties(physical_devices[0], &props); - printf("VkPhysicalDevice name %s\n", props.deviceName); - - VkDeviceQueueCreateInfo queue_create_infos = {0}; - queue_create_infos.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queue_create_infos.queueFamilyIndex = 1; - queue_create_infos.queueCount = 1; - - VkDeviceCreateInfo device_create_info = {0}; - device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - device_create_info.queueCreateInfoCount = 1; - device_create_info.pQueueCreateInfos = &queue_create_infos; - - VkDevice device = VK_NULL_HANDLE; - CheckVk(vkCreateDevice(physical_devices[0], &device_create_info, NULL, &device)); + VkDevice device = kvfCreateDevice(physical_device, NULL, 0, NULL); volkLoadDevice(device); - VkQueue queue = VK_NULL_HANDLE; - vkGetDeviceQueue(device, 1, 0, &queue); + VkQueue queue = kvfGetDeviceQueue(device, KVF_GRAPHICS_QUEUE); + VkFence fence = kvfCreateFence(device); - VkFenceCreateInfo fence_info = {}; - fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT; - VkFence fence = VK_NULL_HANDLE; - CheckVk(vkCreateFence(device, &fence_info, NULL, &fence)); + kvfSubmitCommandBuffer(device, VK_NULL_HANDLE, KVF_GRAPHICS_QUEUE, VK_NULL_HANDLE, VK_NULL_HANDLE, fence, NULL); + kvfWaitForFence(device, fence); - CheckVk(vkQueueSubmit(queue, 0, NULL, fence)); - CheckVk(vkQueueSubmit(queue, 0, NULL, fence)); - CheckVk(vkQueueSubmit(queue, 0, NULL, fence)); - CheckVk(vkQueueWaitIdle(queue)); + kvfDestroyFence(device, fence); - vkDestroyFence(device, fence, NULL); + kvfDestroyDevice(device); + kvfDestroyInstance(instance); - vkDestroyDevice(device, NULL); - vkDestroyInstance(instance, NULL); - - free(physical_devices); dlclose(lib); return 0; }