diff --git a/src/soft/Device.zig b/src/soft/SoftDevice.zig similarity index 51% rename from src/soft/Device.zig rename to src/soft/SoftDevice.zig index ae48507..5f42840 100644 --- a/src/soft/Device.zig +++ b/src/soft/SoftDevice.zig @@ -1,6 +1,6 @@ const std = @import("std"); const vk = @import("vulkan"); -const Instance = @import("Instance.zig"); +const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); const base = @import("base"); const VkError = base.VkError; @@ -9,6 +9,7 @@ const Self = @This(); pub const Interface = base.Device; interface: Interface, +device_allocator: std.heap.ThreadSafeAllocator, pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*Self { const self = allocator.create(Self) catch return VkError.OutOfHostMemory; @@ -17,16 +18,29 @@ pub fn create(physical_device: *base.PhysicalDevice, allocator: std.mem.Allocato var interface = try Interface.init(allocator, physical_device, infos); interface.dispatch_table = &.{ + .allocateMemory = allocateMemory, + .freeMemory = freeMemory, .destroy = destroy, }; self.* = .{ .interface = interface, + .device_allocator = .{ .child_allocator = std.heap.c_allocator }, // TODO: better device allocator base }; return self; } +pub fn allocateMemory(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.MemoryAllocateInfo) VkError!*base.DeviceMemory { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + const device_memory = try SoftDeviceMemory.create(self, allocator, infos.allocation_size, infos.memory_type_index); + return &device_memory.interface; +} + pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void { const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); allocator.destroy(self); } + +pub fn freeMemory(_: *Interface, allocator: std.mem.Allocator, device_memory: *base.DeviceMemory) VkError!void { + device_memory.destroy(allocator); +} diff --git a/src/soft/SoftDeviceMemory.zig b/src/soft/SoftDeviceMemory.zig new file mode 100644 index 0000000..bd4b2a3 --- /dev/null +++ b/src/soft/SoftDeviceMemory.zig @@ -0,0 +1,49 @@ +const std = @import("std"); +const vk = @import("vulkan"); +const SoftDevice = @import("SoftDevice.zig"); +const base = @import("base"); + +const VkError = base.VkError; + +const Self = @This(); +pub const Interface = base.DeviceMemory; + +interface: Interface, +data: []u8, + +pub fn create(device: *SoftDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(&device.interface, size, memory_type_index); + + interface.vtable = &.{ + .destroy = destroy, + .map = map, + .unmap = unmap, + }; + + self.* = .{ + .interface = interface, + .data = device.device_allocator.allocator().alignedAlloc(u8, std.mem.Alignment.@"16", size) catch return VkError.OutOfDeviceMemory, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!?*anyopaque { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + if (offset >= self.data.len or (size != vk.WHOLE_SIZE and offset + size > self.data.len)) { + return VkError.MemoryMapFailed; + } + interface.is_mapped = true; + return @ptrCast(&self.data[offset]); +} + +pub fn unmap(interface: *Interface) void { + interface.is_mapped = false; +} diff --git a/src/soft/SoftFence.zig b/src/soft/SoftFence.zig new file mode 100644 index 0000000..58c8195 --- /dev/null +++ b/src/soft/SoftFence.zig @@ -0,0 +1,83 @@ +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.Fence; + +interface: Interface, +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 { + const self = allocator.create(Self) catch return VkError.OutOfHostMemory; + errdefer allocator.destroy(self); + + var interface = try Interface.init(device, info); + + interface.vtable = &.{ + .destroy = destroy, + .getStatus = getStatus, + .reset = reset, + .signal = signal, + .wait = wait, + }; + + self.* = .{ + .interface = interface, + .mutex = std.Thread.Mutex{}, + .condition = std.Thread.Condition{}, + .is_signaled = info.flags.signaled_bit, + }; + return self; +} + +pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + allocator.destroy(self); +} + +pub fn getStatus(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.mutex.lock(); + defer self.mutex.unlock(); + if (!self.is_signaled) { + return VkError.NotReady; + } +} + +pub fn reset(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + self.mutex.lock(); + defer self.mutex.unlock(); + self.is_signaled = false; +} + +pub fn signal(interface: *Interface) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + { + self.mutex.lock(); + defer self.mutex.unlock(); + self.is_signaled = true; + } + self.condition.broadcast(); +} + +pub fn wait(interface: *Interface, timeout: u64) VkError!void { + const self: *Self = @alignCast(@fieldParentPtr("interface", interface)); + if (self.is_signaled) return; + if (timeout == 0) return VkError.Timeout; + + self.mutex.lock(); + defer self.mutex.unlock(); + + if (timeout == std.math.maxInt(@TypeOf(timeout))) { + self.condition.wait(self.mutex); + } else { + self.condition.timedWait(self.mutex, timeout) catch return VkError.Timeout; + } +} diff --git a/src/soft/Instance.zig b/src/soft/SoftInstance.zig similarity index 86% rename from src/soft/Instance.zig rename to src/soft/SoftInstance.zig index 95777a0..1b93705 100644 --- a/src/soft/Instance.zig +++ b/src/soft/SoftInstance.zig @@ -1,7 +1,7 @@ const std = @import("std"); const vk = @import("vulkan"); const base = @import("base"); -const PhysicalDevice = @import("PhysicalDevice.zig"); +const SoftPhysicalDevice = @import("SoftPhysicalDevice.zig"); const Dispatchable = base.Dispatchable; @@ -27,9 +27,9 @@ pub fn create(allocator: std.mem.Allocator, infos: *const vk.InstanceCreateInfo) fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { // Software driver only has one physical device (the CPU) - const physical_device = try PhysicalDevice.create(allocator, interface); + const physical_device = try SoftPhysicalDevice.create(allocator, interface); errdefer physical_device.interface.releasePhysicalDevice(allocator) catch {}; - interface.physical_devices.append(allocator, try Dispatchable(PhysicalDevice.Interface).wrap(allocator, &physical_device.interface)) catch return VkError.OutOfHostMemory; + interface.physical_devices.append(allocator, try Dispatchable(SoftPhysicalDevice.Interface).wrap(allocator, &physical_device.interface)) catch return VkError.OutOfHostMemory; } fn releasePhysicalDevices(interface: *Interface, allocator: std.mem.Allocator) VkError!void { diff --git a/src/soft/PhysicalDevice.zig b/src/soft/SoftPhysicalDevice.zig similarity index 95% rename from src/soft/PhysicalDevice.zig rename to src/soft/SoftPhysicalDevice.zig index eed363c..3986197 100644 --- a/src/soft/PhysicalDevice.zig +++ b/src/soft/SoftPhysicalDevice.zig @@ -4,8 +4,7 @@ const base = @import("base"); const root = @import("lib.zig"); const cpuinfo = @import("cpuinfo"); -const Device = @import("Device.zig"); -const Instance = @import("Instance.zig"); +const SoftDevice = @import("SoftDevice.zig"); const VkError = base.VkError; @@ -90,8 +89,8 @@ pub fn create(allocator: std.mem.Allocator, instance: *const base.Instance) VkEr return self; } -pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*Device.Interface { - const device = try Device.create(interface, allocator, infos); +pub fn createDevice(interface: *Interface, allocator: std.mem.Allocator, infos: *const vk.DeviceCreateInfo) VkError!*SoftDevice.Interface { + const device = try SoftDevice.create(interface, allocator, infos); return &device.interface; } diff --git a/src/soft/lib.zig b/src/soft/lib.zig index 182214c..86671f1 100644 --- a/src/soft/lib.zig +++ b/src/soft/lib.zig @@ -2,9 +2,12 @@ const std = @import("std"); const vk = @import("vulkan"); pub const base = @import("base"); -pub const Instance = @import("Instance.zig"); -const Device = @import("Device.zig"); -const PhysicalDevice = @import("PhysicalDevice.zig"); +pub const SoftInstance = @import("SoftInstance.zig"); +pub const SoftDevice = @import("SoftDevice.zig"); +pub const SoftDeviceMemory = @import("SoftDeviceMemory.zig"); +pub const SoftPhysicalDevice = @import("SoftPhysicalDevice.zig"); + +pub const Instance = SoftInstance; pub const DRIVER_LOGS_ENV_NAME = base.DRIVER_LOGS_ENV_NAME; pub const DRIVER_NAME = "Soft"; diff --git a/src/vulkan/Device.zig b/src/vulkan/Device.zig index 6b3b72e..1b948f5 100644 --- a/src/vulkan/Device.zig +++ b/src/vulkan/Device.zig @@ -3,6 +3,8 @@ const vk = @import("vulkan"); const VkError = @import("error_set.zig").VkError; const PhysicalDevice = @import("PhysicalDevice.zig"); +const DeviceMemory = @import("DeviceMemory.zig"); +const Fence = @import("Fence.zig"); const Self = @This(); pub const ObjectType: vk.ObjectType = .device; @@ -11,12 +13,19 @@ physical_device: *const PhysicalDevice, dispatch_table: *const DispatchTable, pub const DispatchTable = struct { + allocateMemory: *const fn (*Self, std.mem.Allocator, *const vk.MemoryAllocateInfo) VkError!*DeviceMemory, + createFence: *const fn (*Self, std.mem.Allocator, *const vk.FenceCreateInfo) VkError!*Fence, + 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, }; -pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice, infos: *const vk.DeviceCreateInfo) VkError!Self { +pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice, info: *const vk.DeviceCreateInfo) VkError!Self { _ = allocator; - _ = infos; + _ = info; return .{ .physical_device = physical_device, .dispatch_table = undefined, @@ -26,3 +35,48 @@ pub fn init(allocator: std.mem.Allocator, physical_device: *const PhysicalDevice pub fn destroy(self: *Self, allocator: std.mem.Allocator) VkError!void { try self.dispatch_table.destroy(self, allocator); } + +pub inline fn getFenceStatus(self: *Self, fence: *Fence) VkError!void { + try self.dispatch_table.getFenceStatus(fence); +} + +pub inline fn resetFences(_: *Self, fences: []*Fence) VkError!void { + for (fences) |fence| { + try fence.reset(); + } +} + +pub inline fn waitForFences(_: *Self, fences: []*Fence, waitForAll: bool, timeout: u64) VkError!void { + for (fences) |fence| { + try fence.wait(timeout); + if (!waitForAll) return; + } +} + +// Fence functions =================================================================================================================================== + +pub inline fn createFence(self: *Self, allocator: std.mem.Allocator, info: *const vk.FenceCreateInfo) VkError!*Fence { + return self.dispatch_table.createFence(self, allocator, info); +} + +pub inline fn destroyFence(self: *Self, allocator: std.mem.Allocator, fence: *Fence) VkError!void { + try self.dispatch_table.destroyFence(self, allocator, fence); +} + +// Memory functions ================================================================================================================================== + +pub inline fn allocateMemory(self: *Self, allocator: std.mem.Allocator, info: *const vk.MemoryAllocateInfo) VkError!*DeviceMemory { + return self.dispatch_table.allocateMemory(self, allocator, info); +} + +pub inline fn freeMemory(self: *Self, allocator: std.mem.Allocator, device_memory: *DeviceMemory) VkError!void { + try self.dispatch_table.freeMemory(self, allocator, device_memory); +} + +pub inline fn mapMemory(_: *Self, device_memory: *DeviceMemory, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!?*anyopaque { + return device_memory.map(offset, size); +} + +pub inline fn unmapMemory(_: *Self, device_memory: *DeviceMemory) void { + return device_memory.unmap(); +} diff --git a/src/vulkan/DeviceMemory.zig b/src/vulkan/DeviceMemory.zig index 056875d..65ecb16 100644 --- a/src/vulkan/DeviceMemory.zig +++ b/src/vulkan/DeviceMemory.zig @@ -15,6 +15,7 @@ is_mapped: bool, vtable: *const VTable, pub const VTable = struct { + destroy: *const fn (*Self, std.mem.Allocator) void, map: *const fn (*Self, vk.DeviceSize, vk.DeviceSize) VkError!?*anyopaque, unmap: *const fn (*Self) void, }; @@ -25,9 +26,14 @@ pub fn init(device: *const Device, size: vk.DeviceSize, memory_type_index: u32) .size = size, .memory_type_index = memory_type_index, .is_mapped = false, + .vtable = undefined, }; } +pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + self.vtable.destroy(self, allocator); +} + pub inline fn map(self: *Self, offset: vk.DeviceSize, size: vk.DeviceSize) VkError!?*anyopaque { return self.vtable.map(self, offset, size); } diff --git a/src/vulkan/Fence.zig b/src/vulkan/Fence.zig new file mode 100644 index 0000000..a3c3958 --- /dev/null +++ b/src/vulkan/Fence.zig @@ -0,0 +1,49 @@ +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 = .fence; + +owner: *const Device, +flags: vk.FenceCreateFlags, + +vtable: *const VTable, + +pub const VTable = struct { + destroy: *const fn (*Self, std.mem.Allocator) void, + getStatus: *const fn (*Self) VkError!void, + reset: *const fn (*Self) VkError!void, + signal: *const fn (*Self) VkError!void, + wait: *const fn (*Self, u64) VkError!void, +}; + +pub fn init(device: *const Device, info: *const vk.FenceCreateInfo) VkError!Self { + return .{ + .owner = device, + .flags = info.flags, + .vtable = undefined, + }; +} + +pub inline fn destroy(self: *Self, allocator: std.mem.Allocator) void { + self.vtable.destroy(self, allocator); +} + +pub inline fn getStatus(self: *Self) VkError!void { + try self.vtable.getStatus(self); +} + +pub inline fn reset(self: *Self) VkError!void { + try self.vtable.reset(self); +} + +pub inline fn signal(self: *Self) VkError!void { + try self.vtable.signal(self); +} + +pub inline fn wait(self: *Self, timeout: u64) VkError!void { + try self.vtable.wait(self, timeout); +} diff --git a/src/vulkan/Queue.zig b/src/vulkan/Queue.zig new file mode 100644 index 0000000..99e1908 --- /dev/null +++ b/src/vulkan/Queue.zig @@ -0,0 +1,22 @@ +const std = @import("std"); +const vk = @import("vulkan"); + +const VkError = @import("error_set.zig").VkError; +const Device = @import("Device.zig"); +const Fence = @import("Fence.zig"); + +const Self = @This(); +pub const ObjectType: vk.ObjectType = .queue; + +owner: *const Device, +family_index: u32, +index: u32, +flags: vk.DeviceQueueCreateFlags, + +dispatch_table: *const DispatchTable, + +pub const DispatchTable = struct { + bindSparse: *const fn (*Self, u32, *const vk.BindSparseInfo, ?*Fence) VkError!void, + submit: *const fn (*Self, u32, *const vk.SubmitInfo, ?*Fence) VkError!void, + waitIdle: *const fn (*Self) VkError!void, +}; diff --git a/src/vulkan/VulkanAllocator.zig b/src/vulkan/VulkanAllocator.zig index 44aa655..fecb3e5 100644 --- a/src/vulkan/VulkanAllocator.zig +++ b/src/vulkan/VulkanAllocator.zig @@ -1,11 +1,12 @@ +//! A Zig allocator from VkAllocationCallbacks. +//! Falls back on c_allocator if callbacks passed are null + const std = @import("std"); const vk = @import("vulkan"); const Allocator = std.mem.Allocator; const Alignment = std.mem.Alignment; -/// A Zig allocator from VkAllocationCallbacks. -/// Falls back on c_allocator if callbacks passed are null const Self = @This(); callbacks: ?vk.AllocationCallbacks, diff --git a/src/vulkan/lib.zig b/src/vulkan/lib.zig index 4d340f5..a8dae2a 100644 --- a/src/vulkan/lib.zig +++ b/src/vulkan/lib.zig @@ -10,7 +10,10 @@ pub const VkError = @import("error_set.zig").VkError; pub const Instance = @import("Instance.zig"); pub const Device = @import("Device.zig"); +pub const DeviceMemory = @import("DeviceMemory.zig"); +pub const Fence = @import("Fence.zig"); pub const PhysicalDevice = @import("PhysicalDevice.zig"); +pub const Queue = @import("Queue.zig"); pub const VulkanAllocator = @import("VulkanAllocator.zig"); pub const VULKAN_VENDOR_ID = @typeInfo(vk.VendorId).@"enum".fields[@typeInfo(vk.VendorId).@"enum".fields.len - 1].value + 1; diff --git a/src/vulkan/lib_vulkan.zig b/src/vulkan/lib_vulkan.zig index 36dbcc0..c4273f2 100644 --- a/src/vulkan/lib_vulkan.zig +++ b/src/vulkan/lib_vulkan.zig @@ -10,11 +10,13 @@ const VkError = error_set.VkError; const toVkResult = error_set.toVkResult; const Dispatchable = @import("Dispatchable.zig").Dispatchable; +const NonDispatchable = @import("NonDispatchable.zig").NonDispatchable; const VulkanAllocator = @import("VulkanAllocator.zig"); const Instance = @import("Instance.zig"); const Device = @import("Device.zig"); +const DeviceMemory = @import("DeviceMemory.zig"); const PhysicalDevice = @import("PhysicalDevice.zig"); // This file contains all exported Vulkan entrypoints. @@ -32,7 +34,7 @@ fn functionMapEntryPoint(comptime name: []const u8) struct { []const u8, vk.PfnV else if (std.meta.hasFn(@This(), stroll_name)) .{ name, @as(vk.PfnVoidFunction, @ptrCast(&@field(@This(), stroll_name))) } else - .{ name, null }; + @compileError("Invalid entry point name"); } const icd_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ @@ -67,7 +69,11 @@ const physical_device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComp }); const device_pfn_map = std.StaticStringMap(vk.PfnVoidFunction).initComptime(.{ + functionMapEntryPoint("vkAllocateMemory"), functionMapEntryPoint("vkDestroyDevice"), + functionMapEntryPoint("vkFreeMemory"), + functionMapEntryPoint("vkMapMemory"), + functionMapEntryPoint("vkUnmapMemory"), }); // ICD Interface ============================================================================================================================================= @@ -114,10 +120,10 @@ pub export fn vkGetInstanceProcAddr(p_instance: vk.Instance, p_name: ?[*:0]const return null; } -pub export fn strollCreateInstance(p_infos: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_instance: *vk.Instance) callconv(vk.vulkan_call_conv) vk.Result { - const infos = p_infos orelse return .error_initialization_failed; - if (infos.s_type != .instance_create_info) { - return .error_initialization_failed; +pub export fn strollCreateInstance(p_info: ?*const vk.InstanceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_instance: *vk.Instance) callconv(vk.vulkan_call_conv) vk.Result { + const info = p_info orelse return .error_validation_failed; + if (info.s_type != .instance_create_info) { + return .error_validation_failed; } std.log.scoped(.vkCreateInstance).info("Creating VkInstance", .{}); logger.indent(); @@ -128,7 +134,7 @@ pub export fn strollCreateInstance(p_infos: ?*const vk.InstanceCreateInfo, callb var instance: *lib.Instance = undefined; if (!builtin.is_test) { // Will call impl instead of interface as root refs the impl module - instance = root.Instance.create(allocator, infos) catch |err| return toVkResult(err); + instance = root.Instance.create(allocator, info) catch |err| return toVkResult(err); } instance.requestPhysicalDevices(allocator) catch |err| return toVkResult(err); @@ -176,10 +182,10 @@ pub export fn strollEnumeratePhysicalDevices(p_instance: vk.Instance, count: *u3 // Physical Device functions ================================================================================================================================= -pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, p_infos: ?*const vk.DeviceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_device: *vk.Device) callconv(vk.vulkan_call_conv) vk.Result { - const infos = p_infos orelse return .error_initialization_failed; - if (infos.s_type != .device_create_info) { - return .error_initialization_failed; +pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, p_info: ?*const vk.DeviceCreateInfo, callbacks: ?*const vk.AllocationCallbacks, p_device: *vk.Device) callconv(vk.vulkan_call_conv) vk.Result { + const info = p_info orelse return .error_validation_failed; + if (info.s_type != .device_create_info) { + return .error_validation_failed; } const allocator = VulkanAllocator.init(callbacks, .instance).allocator(); const physical_device = Dispatchable(PhysicalDevice).fromHandleObject(p_physical_device) catch |err| return toVkResult(err); @@ -187,7 +193,7 @@ pub export fn strollCreateDevice(p_physical_device: vk.PhysicalDevice, p_infos: logger.indent(); defer logger.unindent(); - const device = physical_device.createDevice(allocator, infos) catch |err| return toVkResult(err); + const device = physical_device.createDevice(allocator, info) catch |err| return toVkResult(err); p_device.* = (Dispatchable(Device).wrap(allocator, device) catch |err| return toVkResult(err)).toVkHandle(vk.Device); return .success; } @@ -254,7 +260,30 @@ pub export fn strollGetPhysicalDeviceSparseImageFormatProperties( // Device functions ========================================================================================================================================== -pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { +pub export fn strollAllocateMemory(p_device: vk.Device, p_info: ?*const vk.MemoryAllocateInfo, callbacks: ?*const vk.AllocationCallbacks, p_memory: *vk.DeviceMemory) callconv(vk.vulkan_call_conv) vk.Result { + const info = p_info orelse return .error_validation_failed; + if (info.s_type != .memory_allocate_info) { + return .error_validation_failed; + } + const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const device_memory = device.allocateMemory(allocator, info) catch |err| return toVkResult(err); + p_memory.* = (NonDispatchable(DeviceMemory).wrap(allocator, device_memory) catch |err| return toVkResult(err)).toVkHandle(vk.DeviceMemory); + return .success; +} + +pub export fn strollCreateFence(p_device: vk.Device, 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) { + return .error_validation_failed; + } + const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const fence = device.createFence(allocator, info) catch |err| return toVkResult(err); + p_fence.* = (NonDispatchable(Fence).wrap(allocator, fence) catch |err| return toVkResult(err)).toVkHandle(vk.Fence); + return .success; +} + +pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.allocationcallbacks) callconv(vk.vulkan_call_conv) void { const allocator = VulkanAllocator.init(callbacks, .device).allocator(); const dispatchable = Dispatchable(Device).fromHandle(p_device) catch return; std.log.scoped(.vkDestroyDevice).info("Destroying VkDevice created from {s}", .{dispatchable.object.physical_device.props.device_name}); @@ -265,6 +294,15 @@ pub export fn strollDestroyDevice(p_device: vk.Device, callbacks: ?*const vk.All dispatchable.destroy(allocator); } +pub export fn strollFreeMemory(p_device: vk.Device, p_memory: vk.DeviceMemory, callbacks: ?*const vk.AllocationCallbacks) callconv(vk.vulkan_call_conv) void { + const allocator = VulkanAllocator.init(callbacks, .device).allocator(); + const device = Dispatchable(Device).fromHandleObject(p_device) catch return; + const non_dispatchable_device_memory = NonDispatchable(DeviceMemory).fromHandle(p_memory) catch return; + + device.freeMemory(allocator, non_dispatchable_device_memory.object) catch return; + non_dispatchable_device_memory.destroy(allocator); +} + pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u8) callconv(vk.vulkan_call_conv) vk.PfnVoidFunction { if (p_name == null) return null; const name = std.mem.span(p_name.?); @@ -275,3 +313,16 @@ pub export fn strollGetDeviceProcAddr(p_device: vk.Device, p_name: ?[*:0]const u entryPointNotFoundErrorLog(.vkGetDeviceProcAddr, name); return null; } + +pub export fn strollMapMemory(p_device: vk.Device, p_memory: vk.DeviceMemory, offset: vk.DeviceSize, size: vk.DeviceSize, _: vk.MemoryMapFlags, pp_data: *?*anyopaque) callconv(vk.vulkan_call_conv) vk.Result { + const device = Dispatchable(Device).fromHandleObject(p_device) catch |err| return toVkResult(err); + const device_memory = NonDispatchable(DeviceMemory).fromHandleObject(p_memory) catch |err| return toVkResult(err); + pp_data.* = device.mapMemory(device_memory, offset, size) catch |err| return toVkResult(err); + return .success; +} + +pub export fn strollUnmapMemory(p_device: vk.Device, p_memory: vk.DeviceMemory) callconv(vk.vulkan_call_conv) void { + const device = Dispatchable(Device).fromHandleObject(p_device) catch return; + const device_memory = NonDispatchable(DeviceMemory).fromHandleObject(p_memory) catch return; + device.unmapMemory(device_memory); +} diff --git a/test/c/main.c b/test/c/main.c index d05332f..d854308 100644 --- a/test/c/main.c +++ b/test/c/main.c @@ -1,5 +1,6 @@ #include #include +#include #define VK_NO_PROTOTYPES #include @@ -80,6 +81,25 @@ int main(void) volkLoadDevice(device); + VkMemoryAllocateInfo memory_allocate_info = {}; + memory_allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + memory_allocate_info.allocationSize = 512; + memory_allocate_info.memoryTypeIndex = 0; + + VkDeviceMemory memory = VK_NULL_HANDLE; + CheckVk(vkAllocateMemory(device, &memory_allocate_info, NULL, &memory)); + printf("VkDeviceMemory %p\n", memory); + + void* map; + CheckVk(vkMapMemory(device, memory, 0, VK_WHOLE_SIZE, 0, &map)); + const unsigned char data[5] = { 't', 'e', 's', 't', 0x00 }; + memcpy(map, data, 5); + printf("Mapped %p\n", map); + printf("Mapped data: %s\n", (char*)map); + vkUnmapMemory(device, memory); + + vkFreeMemory(device, memory, NULL); + vkDestroyDevice(device, NULL); vkDestroyInstance(instance, NULL);