Merge branch 'master' of ssh://git.ody.si:2025/przmk/vulkan-zig
This commit is contained in:
commit
8c60f79f7d
4 changed files with 322 additions and 79 deletions
|
@ -5,12 +5,12 @@
|
||||||
|
|
||||||
.dependencies = .{
|
.dependencies = .{
|
||||||
.vulkan_zig = .{
|
.vulkan_zig = .{
|
||||||
.url = "https://github.com/Snektron/vulkan-zig/archive/66b7b773bb61e2102025f2d5ff0ae8c5f53e19cc.tar.gz",
|
.url = "https://github.com/Snektron/vulkan-zig/archive/9f6e6177b1fdb3ed22231d9216a24480e84cfa5e.tar.gz",
|
||||||
.hash = "12208958f173b8b81bfac797955f0416ab38b21d1f69d4ebf6c7ca460a828a41cd45",
|
.hash = "1220f2961df224f7d35dee774b26194b8b937cc252fa8e4023407776c58521d53e38",
|
||||||
},
|
},
|
||||||
.sdl = .{
|
.sdl = .{
|
||||||
.url = "https://github.com/ikskuh/SDL.zig/archive/fac81ec499cfd64da7b846de27f6db4a0d4943bf.tar.gz",
|
.url = "https://github.com/MasterQ32/SDL.zig/archive/1432ed3f6a020973906fbc996868131ae1d631be.tar.gz",
|
||||||
.hash = "12206c3d312175cf6a1bf1e8247ace5ac49ed8be80a94d8857d7d41fd7d1aee7ac4b",
|
.hash = "1220ebeeaade31e207a56977aff537a65e6338cddc68d50217ddf30bbc58fb27d367",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
190
src/Mesh.zig
190
src/Mesh.zig
|
@ -11,84 +11,166 @@ vertex_count: u32,
|
||||||
vertex_buffer: vk.Buffer,
|
vertex_buffer: vk.Buffer,
|
||||||
vertex_buffer_memory: vk.DeviceMemory,
|
vertex_buffer_memory: vk.DeviceMemory,
|
||||||
|
|
||||||
|
index_count: u32,
|
||||||
|
index_buffer: vk.Buffer,
|
||||||
|
index_buffer_memory: vk.DeviceMemory,
|
||||||
|
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
physical_device: vk.PhysicalDevice,
|
physical_device: vk.PhysicalDevice,
|
||||||
device: Device,
|
device: Device,
|
||||||
|
|
||||||
pub fn new(instance: Instance, pdev: vk.PhysicalDevice, device: Device, vertices: []const Vertex) !Self {
|
allocator: std.mem.Allocator,
|
||||||
var mesh: Self = undefined;
|
|
||||||
|
|
||||||
mesh.vertex_count = @intCast(vertices.len);
|
pub fn new(
|
||||||
mesh.instance = instance;
|
instance: Instance,
|
||||||
mesh.physical_device = pdev;
|
pdev: vk.PhysicalDevice,
|
||||||
mesh.device = device;
|
device: Device,
|
||||||
try mesh.createVertexBuffer(vertices);
|
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.destroyBuffer(self.vertex_buffer, null);
|
||||||
self.device.freeMemory(self.vertex_buffer_memory, 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 {
|
fn createVertexBuffer(
|
||||||
// Create vertex buffer
|
self: *Self,
|
||||||
// Information to create buffer (doesn't include assigning memory)
|
transfer_queue: vk.Queue,
|
||||||
const buffer_create_info: vk.BufferCreateInfo = .{
|
transfer_command_pool: vk.CommandPool,
|
||||||
.size = @sizeOf(Vertex) * vertices.len, // Size of buffer (size of 1 vertex * number of vertices)
|
vertices: []const Vertex,
|
||||||
.usage = .{ .vertex_buffer_bit = true }, // Multiple types of buffer possible, we want vertex buffer
|
) !void {
|
||||||
.sharing_mode = .exclusive, // Similar to swapchain images, can share vertex buffers
|
// 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
|
// Create buffer and allocate memory to it
|
||||||
const mem_requirements = self.device.getBufferMemoryRequirements(self.vertex_buffer);
|
try Utilities.createBuffer(
|
||||||
|
self.physical_device,
|
||||||
// Allocate memory to buffer
|
self.instance,
|
||||||
const allocate_info: vk.MemoryAllocateInfo = .{
|
self.device,
|
||||||
.allocation_size = mem_requirements.size,
|
buffer_size,
|
||||||
.memory_type_index = self.findMemoryTypeIndex(
|
.{ .transfer_src_bit = true },
|
||||||
mem_requirements.memory_type_bits, // Index of memory type of physical device that has required bit flags
|
.{ .host_visible_bit = true, .host_coherent_bit = true },
|
||||||
.{
|
&staging_buffer,
|
||||||
.host_visible_bit = true, // CPU can interact with memory
|
&staging_buffer_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);
|
|
||||||
|
|
||||||
// Map memory to vertex
|
// Map memory to vertex
|
||||||
// 1. Create pointer to a point in normal memory
|
// 1. Create pointer to a point in normal memory
|
||||||
// 2. Map the vertex buffer memory to that point
|
// 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
|
// 3. Copy memory from vertices vector to the point in memory
|
||||||
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(data));
|
const gpu_vertices: [*]Vertex = @ptrCast(@alignCast(data));
|
||||||
@memcpy(gpu_vertices, vertices[0..]);
|
@memcpy(gpu_vertices, vertices[0..]);
|
||||||
|
|
||||||
// 4. Unmap the vertex buffer memory
|
// 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 {
|
fn createIndexBuffer(
|
||||||
// Get properties of physical device memory
|
self: *Self,
|
||||||
const memory_properties = self.instance.getPhysicalDeviceMemoryProperties(self.physical_device);
|
transfer_queue: vk.Queue,
|
||||||
const mem_type_count = memory_properties.memory_type_count;
|
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| {
|
// Temporary buffer to "stage" vertex data before transfering to GPU
|
||||||
// Index of memory type must match corresponding bit in allowed_types
|
var staging_buffer: vk.Buffer = undefined;
|
||||||
if (allowed_types & (@as(u32, 1) << @truncate(i)) != 0 and mem_type.property_flags.contains(properties)) {
|
var staging_buffer_memory: vk.DeviceMemory = undefined;
|
||||||
// Return the index of the valid memory type
|
defer self.device.destroyBuffer(staging_buffer, null);
|
||||||
return @truncate(i);
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const vk = @import("vulkan");
|
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 device_extensions = [_][*:0]const u8{vk.extensions.khr_swapchain.name};
|
||||||
|
|
||||||
pub const Vector3 = @Vector(3, f32);
|
pub const Vector3 = @Vector(3, f32);
|
||||||
|
@ -31,3 +35,121 @@ pub const SwapchainImage = struct {
|
||||||
image: vk.Image,
|
image: vk.Image,
|
||||||
image_view: vk.ImageView,
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ pub const VulkanRenderer = struct {
|
||||||
current_frame: u32 = 0,
|
current_frame: u32 = 0,
|
||||||
|
|
||||||
// Scene objects
|
// Scene objects
|
||||||
first_mesh: Mesh,
|
meshes: [2]Mesh,
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
instance: Instance,
|
instance: Instance,
|
||||||
|
@ -101,24 +101,58 @@ pub const VulkanRenderer = struct {
|
||||||
|
|
||||||
try self.getPhysicalDevice();
|
try self.getPhysicalDevice();
|
||||||
try self.createLogicalDevice();
|
try self.createLogicalDevice();
|
||||||
|
|
||||||
// Create mesh
|
|
||||||
var mesh_vertices = [_]Vertex{
|
|
||||||
.{ .pos = .{ -0.5, -0.5, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } },
|
|
||||||
.{ .pos = .{ 0.5, -0.5, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } },
|
|
||||||
.{ .pos = .{ 0.5, 0.5, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } },
|
|
||||||
.{ .pos = .{ 0.5, 0.5, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } },
|
|
||||||
.{ .pos = .{ -0.5, 0.5, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } },
|
|
||||||
.{ .pos = .{ -0.5, -0.5, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } },
|
|
||||||
};
|
|
||||||
|
|
||||||
self.first_mesh = try Mesh.new(self.instance, self.physical_device, self.device, &mesh_vertices);
|
|
||||||
|
|
||||||
try self.createSwapchain();
|
try self.createSwapchain();
|
||||||
try self.createRenderPass();
|
try self.createRenderPass();
|
||||||
try self.createGraphicsPipeline();
|
try self.createGraphicsPipeline();
|
||||||
try self.createFramebuffers();
|
try self.createFramebuffers();
|
||||||
try self.createCommandPool();
|
try self.createCommandPool();
|
||||||
|
|
||||||
|
// Create meshes
|
||||||
|
// Vertex Data
|
||||||
|
var mesh_vertices = [_]Vertex{
|
||||||
|
.{ .pos = .{ -0.1, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0
|
||||||
|
.{ .pos = .{ -0.1, 0.4, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 1
|
||||||
|
.{ .pos = .{ -0.9, 0.4, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 2
|
||||||
|
.{ .pos = .{ -0.9, -0.4, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3
|
||||||
|
};
|
||||||
|
|
||||||
|
var mesh_vertices2 = [_]Vertex{
|
||||||
|
.{ .pos = .{ 0.9, -0.3, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0
|
||||||
|
.{ .pos = .{ 0.9, 0.1, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 1
|
||||||
|
.{ .pos = .{ 0.1, 0.3, 0.0 }, .col = .{ 0.0, 0.0, 1.0 } }, // 2
|
||||||
|
.{ .pos = .{ 0.1, -0.3, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3
|
||||||
|
};
|
||||||
|
|
||||||
|
// Index Data
|
||||||
|
const mesh_indices = [_]u32{
|
||||||
|
0, 1, 2,
|
||||||
|
2, 3, 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const first_mesh = try Mesh.new(
|
||||||
|
self.instance,
|
||||||
|
self.physical_device,
|
||||||
|
self.device,
|
||||||
|
self.graphics_queue.handle,
|
||||||
|
self.graphics_command_pool,
|
||||||
|
&mesh_vertices,
|
||||||
|
&mesh_indices,
|
||||||
|
self.allocator,
|
||||||
|
);
|
||||||
|
|
||||||
|
const second_mesh = try Mesh.new(
|
||||||
|
self.instance,
|
||||||
|
self.physical_device,
|
||||||
|
self.device,
|
||||||
|
self.graphics_queue.handle,
|
||||||
|
self.graphics_command_pool,
|
||||||
|
&mesh_vertices2,
|
||||||
|
&mesh_indices,
|
||||||
|
self.allocator,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.meshes = [_]Mesh{ first_mesh, second_mesh };
|
||||||
|
|
||||||
try self.createCommandBuffers();
|
try self.createCommandBuffers();
|
||||||
try self.recordCommands();
|
try self.recordCommands();
|
||||||
try self.createSynchronisation();
|
try self.createSynchronisation();
|
||||||
|
@ -181,7 +215,9 @@ pub const VulkanRenderer = struct {
|
||||||
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
|
self.instance.destroyDebugUtilsMessengerEXT(self.debug_utils.?, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.first_mesh.destroyVertexBuffer();
|
for (self.meshes) |mesh| {
|
||||||
|
mesh.destroyBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
for (0..MAX_FRAME_DRAWS) |i| {
|
for (0..MAX_FRAME_DRAWS) |i| {
|
||||||
self.device.destroySemaphore(self.render_finished[i], null);
|
self.device.destroySemaphore(self.render_finished[i], null);
|
||||||
|
@ -745,23 +781,26 @@ pub const VulkanRenderer = struct {
|
||||||
// Begin render pass
|
// Begin render pass
|
||||||
command_buffer.beginRenderPass(&render_pass_begin_info, vk.SubpassContents.@"inline");
|
command_buffer.beginRenderPass(&render_pass_begin_info, vk.SubpassContents.@"inline");
|
||||||
|
|
||||||
{
|
// Needed when using dynamic state
|
||||||
|
command_buffer.setViewport(0, 1, @ptrCast(&self.viewport));
|
||||||
|
command_buffer.setScissor(0, 1, @ptrCast(&self.scissor));
|
||||||
|
|
||||||
|
for (self.meshes) |mesh| {
|
||||||
// Bind pipeline to be used in render pass
|
// Bind pipeline to be used in render pass
|
||||||
command_buffer.bindPipeline(.graphics, self.graphics_pipeline);
|
command_buffer.bindPipeline(.graphics, self.graphics_pipeline);
|
||||||
|
|
||||||
// Buffers to bind
|
// Buffers to bind
|
||||||
const vertex_buffers = [_]vk.Buffer{self.first_mesh.vertex_buffer};
|
const vertex_buffers = [_]vk.Buffer{mesh.vertex_buffer};
|
||||||
// Offsets into buffers being bound
|
// Offsets into buffers being bound
|
||||||
const offsets = [_]vk.DeviceSize{0};
|
const offsets = [_]vk.DeviceSize{0};
|
||||||
// Command to bind vertex buffer before drawing with them
|
// Command to bind vertex buffer before drawing with them
|
||||||
command_buffer.bindVertexBuffers(0, 1, &vertex_buffers, &offsets);
|
command_buffer.bindVertexBuffers(0, 1, &vertex_buffers, &offsets);
|
||||||
|
|
||||||
// Needed when using dynamic state
|
// Bind mesh index buffer, with 0 offset and using the uint32 type
|
||||||
command_buffer.setViewport(0, 1, @ptrCast(&self.viewport));
|
command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32);
|
||||||
command_buffer.setScissor(0, 1, @ptrCast(&self.scissor));
|
|
||||||
|
|
||||||
// Execute a pipeline
|
// Execute a pipeline
|
||||||
command_buffer.draw(self.first_mesh.vertex_count, 1, 0, 0);
|
command_buffer.drawIndexed(mesh.index_count, 1, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End render pass
|
// End render pass
|
||||||
|
|
Loading…
Reference in a new issue