vulkan-zig/src/utilities.zig
2024-07-18 13:14:03 +02:00

156 lines
5.5 KiB
Zig

const std = @import("std");
const vk = @import("vulkan");
const Instance = @import("vulkan_renderer.zig").Instance;
const Device = @import("vulkan_renderer.zig").Device;
const CommandBuffer = @import("vulkan_renderer.zig").CommandBuffer;
pub const device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
pub const Vector3 = @Vector(3, f32);
// Vertex data representation
pub const Vertex = struct {
// Vertex position (x, y, z)
pos: Vector3,
col: Vector3,
};
pub const QueueFamilyIndices = struct {
graphics_family: ?u32 = null,
presentation_family: ?u32 = null,
pub fn isValid(self: QueueFamilyIndices) bool {
return self.graphics_family != null and self.presentation_family != null;
}
};
pub const SwapchainDetails = struct {
surface_capabilities: vk.SurfaceCapabilitiesKHR,
formats: []vk.SurfaceFormatKHR,
presentation_modes: []vk.PresentModeKHR,
};
pub const SwapchainImage = struct {
image: vk.Image,
image_view: vk.ImageView,
};
fn findMemoryTypeIndex(pdev: vk.PhysicalDevice, instance: Instance, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 {
// Get properties of physical device memory
const memory_properties = instance.getPhysicalDeviceMemoryProperties(pdev);
const mem_type_count = memory_properties.memory_type_count;
for (memory_properties.memory_types[0..mem_type_count], 0..mem_type_count) |mem_type, i| {
// Index of memory type must match corresponding bit in allowed_types
if (allowed_types & (@as(u32, 1) << @truncate(i)) != 0 and mem_type.property_flags.contains(properties)) {
// Return the index of the valid memory type
return @truncate(i);
}
}
unreachable;
}
pub fn createBuffer(
pdev: vk.PhysicalDevice,
instance: Instance,
device: Device,
buffer_size: vk.DeviceSize,
buffer_usage: vk.BufferUsageFlags,
buffer_properties: vk.MemoryPropertyFlags,
buffer: *vk.Buffer,
buffer_memory: *vk.DeviceMemory,
) !void {
// Create vertex buffer
// Information to create buffer (doesn't include assigning memory)
const buffer_create_info: vk.BufferCreateInfo = .{
.size = buffer_size, // Size of buffer (size of 1 vertex * number of vertices)
.usage = buffer_usage, // Multiple types of buffer possible
.sharing_mode = .exclusive, // Similar to swapchain images, can share vertex buffers
};
buffer.* = try device.createBuffer(&buffer_create_info, null);
// Get buffer memory requirements
const mem_requirements = device.getBufferMemoryRequirements(buffer.*);
// Allocate memory to buffer
const allocate_info: vk.MemoryAllocateInfo = .{
.allocation_size = mem_requirements.size,
.memory_type_index = findMemoryTypeIndex(
pdev,
instance,
mem_requirements.memory_type_bits, // Index of memory type of physical device that has required bit flags
// Host visible: CPU can interact with memory
// Host coherent: Allows placement of data straight into buffer after mapping (otherwise would have to specify manually)
buffer_properties,
),
};
// Allocate memory to vkDeviceMemory
buffer_memory.* = try device.allocateMemory(&allocate_info, null);
// Allocate memory to given vertex buffer
try device.bindBufferMemory(buffer.*, buffer_memory.*, 0);
}
pub fn copyBuffer(
device: Device,
transfer_queue: vk.Queue,
transfer_command_pool: vk.CommandPool,
src_buffer: vk.Buffer,
dst_buffer: vk.Buffer,
buffer_size: vk.DeviceSize,
allocator: std.mem.Allocator,
) !void {
// Command buffer to hold transfer commands
const transfer_command_buffer_handle = try allocator.create(vk.CommandBuffer);
defer allocator.destroy(transfer_command_buffer_handle);
// Free temporary buffer back to pool
defer device.freeCommandBuffers(transfer_command_pool, 1, @ptrCast(transfer_command_buffer_handle));
// Command buffer details
const alloc_info: vk.CommandBufferAllocateInfo = .{
.command_pool = transfer_command_pool,
.level = .primary,
.command_buffer_count = 1,
};
// Allocate command buffer from pool
try device.allocateCommandBuffers(&alloc_info, @ptrCast(transfer_command_buffer_handle));
const transfer_command_buffer = CommandBuffer.init(transfer_command_buffer_handle.*, device.wrapper);
// Information to begin the command buffer record
const begin_info: vk.CommandBufferBeginInfo = .{
.flags = .{ .one_time_submit_bit = true }, // We're only using the command buffer once, so set to one time submit
};
// Begin recording transfer commands
try transfer_command_buffer.beginCommandBuffer(&begin_info);
// Region of data to copy from and to
const buffer_copy_region: vk.BufferCopy = .{
.src_offset = 0,
.dst_offset = 0,
.size = buffer_size,
};
// Command to copy src buffer to dst buffer
transfer_command_buffer.copyBuffer(src_buffer, dst_buffer, 1, @ptrCast(&buffer_copy_region));
// End commands
try transfer_command_buffer.endCommandBuffer();
// Queue submission information
const submit_info: vk.SubmitInfo = .{
.command_buffer_count = 1,
.p_command_buffers = @ptrCast(&transfer_command_buffer.handle),
};
// Submit transfer command to transfer queue and wait until it finishes
try device.queueSubmit(transfer_queue, 1, @ptrCast(&submit_info), .null_handle);
try device.queueWaitIdle(transfer_queue);
}