158 lines
4.8 KiB
Zig
158 lines
4.8 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
|
|
const vk = @import("vk");
|
|
const c = @import("c.zig");
|
|
|
|
pub const Base = @import("gfx/Base.zig");
|
|
pub const Context = @import("gfx/Context.zig");
|
|
pub const Device = @import("gfx/Device.zig");
|
|
pub const Instance = @import("gfx/Instance.zig");
|
|
pub const Swapchain = @import("gfx/Swapchain.zig");
|
|
pub const Window = @import("gfx/Window.zig");
|
|
|
|
pub const use_debug_messenger = switch (builtin.mode) {
|
|
.Debug, .ReleaseSafe => true,
|
|
.ReleaseSmall, .ReleaseFast => false,
|
|
};
|
|
|
|
pub const apis: []const vk.ApiInfo = &.{
|
|
vk.features.version_1_0,
|
|
vk.features.version_1_1,
|
|
vk.features.version_1_2,
|
|
vk.features.version_1_3,
|
|
vk.extensions.khr_surface,
|
|
vk.extensions.khr_swapchain,
|
|
vk.extensions.khr_dynamic_rendering,
|
|
if (use_debug_messenger) vk.extensions.ext_debug_utils else .{},
|
|
};
|
|
|
|
pub fn uploadData(
|
|
comptime T: type,
|
|
pdev: vk.PhysicalDevice,
|
|
vki: Instance.Wrapper,
|
|
dev: vk.Device,
|
|
vkd: Device.Wrapper,
|
|
queue: vk.Queue,
|
|
pool: vk.CommandPool,
|
|
buffer: vk.Buffer,
|
|
source: []const T,
|
|
) !void {
|
|
// if (@typeInfo(T) == .Struct and @typeInfo(T).Struct.layout == .auto) @compileError("Requires defined T layout");
|
|
|
|
const size = @sizeOf(T) * source.len;
|
|
|
|
const staging_buffer = try vkd.createBuffer(dev, &.{
|
|
.size = size,
|
|
.usage = .{ .transfer_src_bit = true },
|
|
.sharing_mode = .exclusive,
|
|
}, null);
|
|
defer vkd.destroyBuffer(dev, staging_buffer, null);
|
|
|
|
const vally = VkAllocator.init(pdev, vki);
|
|
|
|
const mem_reqs = vkd.getBufferMemoryRequirements(dev, staging_buffer);
|
|
const staging_memory = try vally.alloc(dev, vkd, mem_reqs, .{ .host_visible_bit = true, .host_coherent_bit = true });
|
|
// const staging_memory = try allocate(pdev, vki, dev, vkd, mem_reqs, .{
|
|
// .host_visible_bit = true,
|
|
// .host_coherent_bit = true,
|
|
// });
|
|
defer vkd.freeMemory(dev, staging_memory, null);
|
|
|
|
try vkd.bindBufferMemory(dev, staging_buffer, staging_memory, 0);
|
|
|
|
{
|
|
const data = try vkd.mapMemory(dev, staging_memory, 0, vk.WHOLE_SIZE, .{});
|
|
defer vkd.unmapMemory(dev, staging_memory);
|
|
|
|
const dest: [*]T = @ptrCast(@alignCast(data));
|
|
@memcpy(dest, source);
|
|
}
|
|
|
|
try copyBuffer(dev, queue, pool, buffer, staging_buffer, size, vkd);
|
|
}
|
|
|
|
pub fn copyBuffer(
|
|
dev: vk.Device,
|
|
queue: vk.Queue,
|
|
pool: vk.CommandPool,
|
|
dst: vk.Buffer,
|
|
src: vk.Buffer,
|
|
size: vk.DeviceSize,
|
|
vkd: Device.Wrapper,
|
|
) !void {
|
|
var cmdbuf: vk.CommandBuffer = undefined;
|
|
try vkd.allocateCommandBuffers(dev, &.{
|
|
.command_pool = pool,
|
|
.level = .primary,
|
|
.command_buffer_count = 1,
|
|
}, @ptrCast(&cmdbuf));
|
|
defer vkd.freeCommandBuffers(dev, pool, 1, @ptrCast(&cmdbuf));
|
|
|
|
try vkd.beginCommandBuffer(cmdbuf, &.{
|
|
.flags = .{ .one_time_submit_bit = true },
|
|
});
|
|
|
|
const region = vk.BufferCopy{
|
|
.src_offset = 0,
|
|
.dst_offset = 0,
|
|
.size = size,
|
|
};
|
|
vkd.cmdCopyBuffer(cmdbuf, src, dst, 1, @ptrCast(®ion));
|
|
|
|
try vkd.endCommandBuffer(cmdbuf);
|
|
|
|
const si = vk.SubmitInfo{
|
|
.command_buffer_count = 1,
|
|
.p_command_buffers = @ptrCast(&cmdbuf),
|
|
.p_wait_dst_stage_mask = undefined,
|
|
};
|
|
|
|
// creating and submitting a queue for every copy operation seems a bad idea for "streamed" data
|
|
// gonna want a way to send a copy operation WITH SYNCHRONIZATION PRIMITIVES on a particular queue
|
|
// see https://stackoverflow.com/a/62183243
|
|
//
|
|
// this may be a misunderstanding on how submission works...
|
|
|
|
try vkd.queueSubmit(queue, 1, @ptrCast(&si), .null_handle);
|
|
try vkd.queueWaitIdle(queue);
|
|
}
|
|
|
|
pub const VkAllocator = struct {
|
|
memory_types: [vk.MAX_MEMORY_TYPES]vk.MemoryType,
|
|
memory_type_count: u32,
|
|
|
|
pub fn init(
|
|
pdev: vk.PhysicalDevice,
|
|
vki: Instance.Wrapper,
|
|
) VkAllocator {
|
|
const props = vki.getPhysicalDeviceMemoryProperties(pdev);
|
|
|
|
return VkAllocator{
|
|
.memory_types = props.memory_types,
|
|
.memory_type_count = props.memory_type_count,
|
|
};
|
|
}
|
|
|
|
pub fn alloc(
|
|
self: VkAllocator,
|
|
dev: vk.Device,
|
|
vkd: Device.Wrapper,
|
|
reqs: vk.MemoryRequirements,
|
|
flags: vk.MemoryPropertyFlags,
|
|
) !vk.DeviceMemory {
|
|
const memory_type_bits = reqs.memory_type_bits;
|
|
|
|
for (self.memory_types[0..self.memory_type_count], 0..) |mem_type, idx| {
|
|
if (memory_type_bits & (@as(u32, 1) << @truncate(idx)) != 0 and mem_type.property_flags.contains(flags)) {
|
|
return try vkd.allocateMemory(dev, &.{
|
|
.allocation_size = reqs.size,
|
|
.memory_type_index = @intCast(idx),
|
|
}, null);
|
|
}
|
|
}
|
|
|
|
return error.NoSuitableMemoryType;
|
|
}
|
|
};
|