156 lines
5.5 KiB
Zig
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);
|
|
}
|