172 lines
5.2 KiB
Zig
172 lines
5.2 KiB
Zig
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,
|
|
);
|
|
}
|