const std = @import("std"); const vk = @import("vulkan"); const zm = @import("zmath"); const Context = @import("Context.zig"); const Utilities = @import("utilities.zig"); const Vertex = Utilities.Vertex; const Device = @import("Context.zig").Device; const Instance = @import("Context.zig").Instance; const Model = @import("vulkan_renderer.zig").Model; const Self = @This(); ubo_model: Model, vertex_count: u32, vertex_buffer: vk.Buffer, vertex_buffer_memory: vk.DeviceMemory, index_count: u32, index_buffer: vk.Buffer, index_buffer_memory: vk.DeviceMemory, ctx: Context, allocator: std.mem.Allocator, pub fn create( allocator: std.mem.Allocator, ctx: Context, transfer_queue: vk.Queue, transfer_command_pool: vk.CommandPool, vertices: []const Vertex, indices: []const u32, tex_id: u32, ) !Self { var self: Self = undefined; self.allocator = allocator; self.vertex_count = @intCast(vertices.len); self.index_count = @intCast(indices.len); self.ctx = ctx; try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices); try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices); self.ubo_model = .{ .model = zm.identity() }; self.tex_id = tex_id; return self; } pub fn destroy(self: Self) void { self.ctx.device.destroyBuffer(self.vertex_buffer, null); self.ctx.device.freeMemory(self.vertex_buffer_memory, null); self.ctx.device.destroyBuffer(self.index_buffer, null); self.ctx.device.freeMemory(self.index_buffer_memory, null); } 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; // 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.ctx.device.destroyBuffer(staging_buffer, null); defer self.ctx.device.freeMemory(staging_buffer_memory, null); // Create buffer and allocate memory to it try Utilities.createBuffer( self.ctx, 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.ctx.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.ctx.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.ctx, 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.ctx, transfer_queue, transfer_command_pool, staging_buffer, self.vertex_buffer, buffer_size, ); } 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; // 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.ctx.device.destroyBuffer(staging_buffer, null); defer self.ctx.device.freeMemory(staging_buffer_memory, null); try Utilities.createBuffer( self.ctx, 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.ctx.device.mapMemory(staging_buffer_memory, 0, buffer_size, .{}); const gpu_vertices: [*]u32 = @ptrCast(@alignCast(data)); @memcpy(gpu_vertices, indices[0..]); self.ctx.device.unmapMemory(staging_buffer_memory); // Create buffer for index data on GPU access only try Utilities.createBuffer( self.ctx, 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.ctx, transfer_queue, transfer_command_pool, staging_buffer, self.index_buffer, buffer_size, ); }