Add index buffers
This commit is contained in:
parent
c391c53eea
commit
aa8a3c1f34
3 changed files with 318 additions and 75 deletions
190
src/Mesh.zig
190
src/Mesh.zig
|
@ -11,84 +11,166 @@ vertex_count: u32,
|
|||
vertex_buffer: vk.Buffer,
|
||||
vertex_buffer_memory: vk.DeviceMemory,
|
||||
|
||||
index_count: u32,
|
||||
index_buffer: vk.Buffer,
|
||||
index_buffer_memory: vk.DeviceMemory,
|
||||
|
||||
instance: Instance,
|
||||
physical_device: vk.PhysicalDevice,
|
||||
device: Device,
|
||||
|
||||
pub fn new(instance: Instance, pdev: vk.PhysicalDevice, device: Device, vertices: []const Vertex) !Self {
|
||||
var mesh: Self = undefined;
|
||||
allocator: std.mem.Allocator,
|
||||
|
||||
mesh.vertex_count = @intCast(vertices.len);
|
||||
mesh.instance = instance;
|
||||
mesh.physical_device = pdev;
|
||||
mesh.device = device;
|
||||
try mesh.createVertexBuffer(vertices);
|
||||
pub fn new(
|
||||
instance: Instance,
|
||||
pdev: vk.PhysicalDevice,
|
||||
device: Device,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
vertices: []const Vertex,
|
||||
indices: []const u32,
|
||||
allocator: std.mem.Allocator,
|
||||
) !Self {
|
||||
var self: Self = undefined;
|
||||
|
||||
return mesh;
|
||||
self.vertex_count = @intCast(vertices.len);
|
||||
self.index_count = @intCast(indices.len);
|
||||
|
||||
self.instance = instance;
|
||||
self.physical_device = pdev;
|
||||
self.device = device;
|
||||
self.allocator = allocator;
|
||||
|
||||
try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices);
|
||||
try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn destroyVertexBuffer(self: Self) void {
|
||||
pub fn destroyBuffers(self: Self) void {
|
||||
self.device.destroyBuffer(self.vertex_buffer, null);
|
||||
self.device.freeMemory(self.vertex_buffer_memory, null);
|
||||
|
||||
self.device.destroyBuffer(self.index_buffer, null);
|
||||
self.device.freeMemory(self.index_buffer_memory, null);
|
||||
}
|
||||
|
||||
fn createVertexBuffer(self: *Self, vertices: []const Vertex) !void {
|
||||
// Create vertex buffer
|
||||
// Information to create buffer (doesn't include assigning memory)
|
||||
const buffer_create_info: vk.BufferCreateInfo = .{
|
||||
.size = @sizeOf(Vertex) * vertices.len, // Size of buffer (size of 1 vertex * number of vertices)
|
||||
.usage = .{ .vertex_buffer_bit = true }, // Multiple types of buffer possible, we want vertex buffer
|
||||
.sharing_mode = .exclusive, // Similar to swapchain images, can share vertex buffers
|
||||
};
|
||||
fn createVertexBuffer(
|
||||
self: *Self,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
vertices: []const Vertex,
|
||||
) !void {
|
||||
// Get size of buffer needed for vertices
|
||||
const buffer_size: vk.DeviceSize = @sizeOf(Vertex) * vertices.len;
|
||||
|
||||
self.vertex_buffer = try self.device.createBuffer(&buffer_create_info, null);
|
||||
// Temporary buffer to "stage" vertex data before transfering to GPU
|
||||
var staging_buffer: vk.Buffer = undefined;
|
||||
var staging_buffer_memory: vk.DeviceMemory = undefined;
|
||||
defer self.device.destroyBuffer(staging_buffer, null);
|
||||
defer self.device.freeMemory(staging_buffer_memory, null);
|
||||
|
||||
// Get buffer memory requirements
|
||||
const mem_requirements = self.device.getBufferMemoryRequirements(self.vertex_buffer);
|
||||
|
||||
// Allocate memory to buffer
|
||||
const allocate_info: vk.MemoryAllocateInfo = .{
|
||||
.allocation_size = mem_requirements.size,
|
||||
.memory_type_index = self.findMemoryTypeIndex(
|
||||
mem_requirements.memory_type_bits, // Index of memory type of physical device that has required bit flags
|
||||
.{
|
||||
.host_visible_bit = true, // CPU can interact with memory
|
||||
.host_coherent_bit = true, // Allows placement of data straight into buffer after mapping (otherwise would have to specify manually)
|
||||
},
|
||||
),
|
||||
};
|
||||
|
||||
// Allocate memory to vkDeviceMemory
|
||||
self.vertex_buffer_memory = try self.device.allocateMemory(&allocate_info, null);
|
||||
|
||||
// Allocate memory to given vertex buffer
|
||||
try self.device.bindBufferMemory(self.vertex_buffer, self.vertex_buffer_memory, 0);
|
||||
// Create buffer and allocate memory to it
|
||||
try Utilities.createBuffer(
|
||||
self.physical_device,
|
||||
self.instance,
|
||||
self.device,
|
||||
buffer_size,
|
||||
.{ .transfer_src_bit = true },
|
||||
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
||||
&staging_buffer,
|
||||
&staging_buffer_memory,
|
||||
);
|
||||
|
||||
// Map memory to vertex
|
||||
// 1. Create pointer to a point in normal memory
|
||||
// 2. Map the vertex buffer memory to that point
|
||||
const data = try self.device.mapMemory(self.vertex_buffer_memory, 0, vk.WHOLE_SIZE, .{});
|
||||
|
||||
const data = try self.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{});
|
||||
// 3. Copy memory from vertices vector to the point in memory
|
||||
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(data));
|
||||
@memcpy(gpu_vertices, vertices[0..]);
|
||||
|
||||
// 4. Unmap the vertex buffer memory
|
||||
self.device.unmapMemory(self.vertex_buffer_memory);
|
||||
self.device.unmapMemory(staging_buffer_memory);
|
||||
|
||||
// ---
|
||||
|
||||
// Create buffer with TRANSFER_DST_BIT to mark as recipient of transfer data (also VERTEX_BUFFER)
|
||||
// Buffer memory is to be DEVICE_LOCAL_BIT meaning memory is on the GPU and only accessible by it and not CPU (host)
|
||||
try Utilities.createBuffer(
|
||||
self.physical_device,
|
||||
self.instance,
|
||||
self.device,
|
||||
buffer_size,
|
||||
.{ .transfer_dst_bit = true, .vertex_buffer_bit = true },
|
||||
.{ .device_local_bit = true },
|
||||
&self.vertex_buffer,
|
||||
&self.vertex_buffer_memory,
|
||||
);
|
||||
|
||||
// Copy staging buffer to vertex buffer on GPU
|
||||
try Utilities.copyBuffer(
|
||||
self.device,
|
||||
transfer_queue,
|
||||
transfer_command_pool,
|
||||
staging_buffer,
|
||||
self.vertex_buffer,
|
||||
buffer_size,
|
||||
self.allocator,
|
||||
);
|
||||
}
|
||||
|
||||
fn findMemoryTypeIndex(self: Self, allowed_types: u32, properties: vk.MemoryPropertyFlags) u32 {
|
||||
// Get properties of physical device memory
|
||||
const memory_properties = self.instance.getPhysicalDeviceMemoryProperties(self.physical_device);
|
||||
const mem_type_count = memory_properties.memory_type_count;
|
||||
fn createIndexBuffer(
|
||||
self: *Self,
|
||||
transfer_queue: vk.Queue,
|
||||
transfer_command_pool: vk.CommandPool,
|
||||
indices: []const u32,
|
||||
) !void {
|
||||
// Get size of buffer needed for indices
|
||||
const buffer_size: vk.DeviceSize = @sizeOf(u32) * indices.len;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
// Temporary buffer to "stage" vertex data before transfering to GPU
|
||||
var staging_buffer: vk.Buffer = undefined;
|
||||
var staging_buffer_memory: vk.DeviceMemory = undefined;
|
||||
defer self.device.destroyBuffer(staging_buffer, null);
|
||||
defer self.device.freeMemory(staging_buffer_memory, null);
|
||||
|
||||
unreachable;
|
||||
try Utilities.createBuffer(
|
||||
self.physical_device,
|
||||
self.instance,
|
||||
self.device,
|
||||
buffer_size,
|
||||
.{ .transfer_src_bit = true },
|
||||
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
||||
&staging_buffer,
|
||||
&staging_buffer_memory,
|
||||
);
|
||||
|
||||
// Map memory to index buffer
|
||||
const data = try self.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{});
|
||||
const gpu_vertices: [*]u32 = @ptrCast(@alignCast(data));
|
||||
@memcpy(gpu_vertices, indices[0..]);
|
||||
self.device.unmapMemory(staging_buffer_memory);
|
||||
|
||||
// Create buffer for index data on GPU access only
|
||||
try Utilities.createBuffer(
|
||||
self.physical_device,
|
||||
self.instance,
|
||||
self.device,
|
||||
buffer_size,
|
||||
.{ .transfer_dst_bit = true, .index_buffer_bit = true },
|
||||
.{ .device_local_bit = true },
|
||||
&self.index_buffer,
|
||||
&self.index_buffer_memory,
|
||||
);
|
||||
|
||||
// Copy from staging buffer to GPU access buffer
|
||||
try Utilities.copyBuffer(
|
||||
self.device,
|
||||
transfer_queue,
|
||||
transfer_command_pool,
|
||||
staging_buffer,
|
||||
self.index_buffer,
|
||||
buffer_size,
|
||||
self.allocator,
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue