Add dynamic uniform buffers

This commit is contained in:
Przemyslaw Gasinski 2024-07-24 10:39:16 +02:00
parent b1bbd65aaa
commit 6f4f600fda
4 changed files with 206 additions and 69 deletions

View file

@ -1,12 +1,17 @@
const std = @import("std"); const std = @import("std");
const vk = @import("vulkan"); const vk = @import("vulkan");
const zm = @import("zmath");
const Utilities = @import("utilities.zig"); const Utilities = @import("utilities.zig");
const Vertex = Utilities.Vertex; const Vertex = Utilities.Vertex;
const Device = @import("vulkan_renderer.zig").Device; const Device = @import("vulkan_renderer.zig").Device;
const Instance = @import("vulkan_renderer.zig").Instance; const Instance = @import("vulkan_renderer.zig").Instance;
const UboModel = @import("vulkan_renderer.zig").UboModel;
const Self = @This(); const Self = @This();
ubo_model: UboModel,
vertex_count: u32, vertex_count: u32,
vertex_buffer: vk.Buffer, vertex_buffer: vk.Buffer,
vertex_buffer_memory: vk.DeviceMemory, vertex_buffer_memory: vk.DeviceMemory,
@ -44,6 +49,8 @@ pub fn new(
try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices); try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices);
try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices); try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices);
self.ubo_model = .{ .model = zm.identity() };
return self; return self;
} }

View file

@ -47,7 +47,17 @@ pub fn main() !void {
angle -= 360.0; angle -= 360.0;
} }
try vulkan_renderer.updateModel(zm.rotationZ(angle)); var first_model = zm.identity();
var second_model = zm.identity();
first_model = zm.mul(first_model, zm.rotationZ(angle));
first_model = zm.mul(first_model, zm.translation(-2.0, 0.0, -5.0));
second_model = zm.mul(second_model, zm.rotationZ(-angle * 2));
second_model = zm.mul(second_model, zm.translation(2.0, 0.0, -5.0));
try vulkan_renderer.updateModel(0, first_model);
try vulkan_renderer.updateModel(1, second_model);
try vulkan_renderer.draw(); try vulkan_renderer.draw();
} }

View file

@ -3,15 +3,18 @@
layout(location = 0) in vec3 pos; layout(location = 0) in vec3 pos;
layout(location = 1) in vec3 col; layout(location = 1) in vec3 col;
layout(binding = 0) uniform MVP { layout(binding = 0) uniform UboViewProjection {
mat4 projection; mat4 projection;
mat4 view; mat4 view;
} uboViewProjection;
layout(binding = 1) uniform UboModel {
mat4 model; mat4 model;
} mvp; } uboModel;
layout(location = 0) out vec3 fragCol; layout(location = 0) out vec3 fragCol;
void main() { void main() {
gl_Position = mvp.projection * mvp.view * mvp.model * vec4(pos, 1.0); gl_Position = uboViewProjection.projection * uboViewProjection.view * uboModel.model * vec4(pos, 1.0);
fragCol = col; fragCol = col;
} }

View file

@ -17,6 +17,7 @@ const enable_validation_layers = builtin.mode == .Debug;
const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
const MAX_FRAME_DRAWS: u32 = 2; const MAX_FRAME_DRAWS: u32 = 2;
const MAX_OBJECTS: u32 = 2;
const apis: []const vk.ApiInfo = &.{ const apis: []const vk.ApiInfo = &.{
vk.features.version_1_0, vk.features.version_1_0,
@ -37,15 +38,18 @@ pub const Device = vk.DeviceProxy(apis);
pub const Queue = vk.QueueProxy(apis); pub const Queue = vk.QueueProxy(apis);
pub const CommandBuffer = vk.CommandBufferProxy(apis); pub const CommandBuffer = vk.CommandBufferProxy(apis);
const UboViewProjection = struct {
projection: zm.Mat align(16),
view: zm.Mat align(16),
};
pub const UboModel = struct {
model: zm.Mat align(16),
};
pub const VulkanRenderer = struct { pub const VulkanRenderer = struct {
const Self = @This(); const Self = @This();
const Mvp = struct {
projection: zm.Mat,
view: zm.Mat,
model: zm.Mat,
};
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
vkb: BaseDispatch, vkb: BaseDispatch,
@ -58,7 +62,7 @@ pub const VulkanRenderer = struct {
meshes: [2]Mesh, meshes: [2]Mesh,
// Scene settings // Scene settings
mvp: Mvp, ubo_view_projection: UboViewProjection,
// Main // Main
instance: Instance, instance: Instance,
@ -81,8 +85,11 @@ pub const VulkanRenderer = struct {
descriptor_pool: vk.DescriptorPool, descriptor_pool: vk.DescriptorPool,
descriptor_sets: []vk.DescriptorSet, descriptor_sets: []vk.DescriptorSet,
uniform_buffer: []vk.Buffer, vp_uniform_buffer: []vk.Buffer,
uniform_buffer_memory: []vk.DeviceMemory, vp_uniform_buffer_memory: []vk.DeviceMemory,
model_duniform_buffer: []vk.Buffer,
model_duniform_buffer_memory: []vk.DeviceMemory,
// Pipeline // Pipeline
graphics_pipeline: vk.Pipeline, graphics_pipeline: vk.Pipeline,
@ -96,6 +103,10 @@ pub const VulkanRenderer = struct {
swapchain_image_format: vk.Format, swapchain_image_format: vk.Format,
extent: vk.Extent2D, extent: vk.Extent2D,
min_uniform_buffer_offset: vk.DeviceSize,
model_uniform_alignment: usize,
model_transfer_space: [MAX_OBJECTS]UboModel,
// Synchronisation // Synchronisation
image_available: [MAX_FRAME_DRAWS]vk.Semaphore, image_available: [MAX_FRAME_DRAWS]vk.Semaphore,
render_finished: [MAX_FRAME_DRAWS]vk.Semaphore, render_finished: [MAX_FRAME_DRAWS]vk.Semaphore,
@ -128,36 +139,35 @@ pub const VulkanRenderer = struct {
try self.createCommandPool(); try self.createCommandPool();
const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height)); const aspect: f32 = @as(f32, @floatFromInt(self.extent.width)) / @as(f32, @floatFromInt(self.extent.height));
self.mvp.projection = zm.perspectiveFovRh( self.ubo_view_projection.projection = zm.perspectiveFovRh(
std.math.degreesToRadians(45.0), std.math.degreesToRadians(45.0),
aspect, aspect,
0.1, 0.1,
100.0, 100.0,
); );
self.mvp.view = zm.lookAtRh( self.ubo_view_projection.view = zm.lookAtRh(
zm.Vec{ 0.0, 0.0, 2.0, 0.0 }, zm.Vec{ 0.0, 0.0, 2.0, 0.0 },
zm.Vec{ 0.0, 0.0, 0.0, 0.0 }, zm.Vec{ 0.0, 0.0, 0.0, 0.0 },
zm.Vec{ 0.0, 1.0, 0.0, 0.0 }, zm.Vec{ 0.0, 1.0, 0.0, 0.0 },
); );
self.mvp.model = zm.identity();
// Invert y scale // Invert y scale
self.mvp.projection[1][1] *= -1; self.ubo_view_projection.projection[1][1] *= -1;
// Create meshes // Create meshes
// Vertex Data // Vertex Data
var mesh_vertices = [_]Vertex{ var mesh_vertices = [_]Vertex{
.{ .pos = .{ -0.1, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0 .{ .pos = .{ -0.4, 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.4, -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.4, -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 .{ .pos = .{ 0.4, 0.4, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3
}; };
var mesh_vertices2 = [_]Vertex{ var mesh_vertices2 = [_]Vertex{
.{ .pos = .{ 0.9, -0.3, 0.0 }, .col = .{ 1.0, 0.0, 0.0 } }, // 0 .{ .pos = .{ -0.25, 0.6, 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.25, -0.6, 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.25, -0.6, 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 .{ .pos = .{ 0.25, 0.6, 0.0 }, .col = .{ 0.0, 1.0, 0.0 } }, // 3
}; };
// Index Data // Index Data
@ -191,7 +201,7 @@ pub const VulkanRenderer = struct {
self.meshes = [_]Mesh{ first_mesh, second_mesh }; self.meshes = [_]Mesh{ first_mesh, second_mesh };
try self.createCommandBuffers(); try self.createCommandBuffers();
try self.allocateDynamicBufferTransferSpace();
try self.createUniformBuffers(); try self.createUniformBuffers();
try self.createDescriptorPool(); try self.createDescriptorPool();
try self.createDescriptorSets(); try self.createDescriptorSets();
@ -202,8 +212,10 @@ pub const VulkanRenderer = struct {
return self; return self;
} }
pub fn updateModel(self: *Self, new_model: zm.Mat) !void { pub fn updateModel(self: *Self, model_id: u32, new_model: zm.Mat) !void {
self.mvp.model = new_model; if (model_id < self.meshes.len) {
self.meshes[model_id].ubo_model.model = new_model;
}
} }
pub fn draw(self: *Self) !void { pub fn draw(self: *Self) !void {
@ -221,7 +233,7 @@ pub const VulkanRenderer = struct {
.null_handle, .null_handle,
); );
try self.updateUniformBuffer(image_index_result.image_index); try self.updateUniformBuffers(image_index_result.image_index);
// -- Submit command buffer to render // -- Submit command buffer to render
// Queue submission information // Queue submission information
@ -266,12 +278,16 @@ pub const VulkanRenderer = struct {
self.device.destroyDescriptorPool(self.descriptor_pool, null); self.device.destroyDescriptorPool(self.descriptor_pool, null);
self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null); self.device.destroyDescriptorSetLayout(self.descriptor_set_layout, null);
for (self.uniform_buffer, self.uniform_buffer_memory) |buffer, buffer_memory| { for (0..self.swapchain_images.len) |i| {
self.device.destroyBuffer(buffer, null); self.device.destroyBuffer(self.vp_uniform_buffer[i], null);
self.device.freeMemory(buffer_memory, null); self.device.freeMemory(self.vp_uniform_buffer_memory[i], null);
self.device.destroyBuffer(self.model_duniform_buffer[i], null);
self.device.freeMemory(self.model_duniform_buffer_memory[i], null);
} }
self.allocator.free(self.uniform_buffer); self.allocator.free(self.vp_uniform_buffer);
self.allocator.free(self.uniform_buffer_memory); self.allocator.free(self.vp_uniform_buffer_memory);
self.allocator.free(self.model_duniform_buffer);
self.allocator.free(self.model_duniform_buffer_memory);
self.allocator.free(self.descriptor_sets); self.allocator.free(self.descriptor_sets);
for (self.meshes) |mesh| { for (self.meshes) |mesh| {
@ -551,8 +567,8 @@ pub const VulkanRenderer = struct {
} }
fn createDescriptorSetLayout(self: *Self) !void { fn createDescriptorSetLayout(self: *Self) !void {
// MVP binding info // UboViewProjection binding info
const mvp_layout_binding: vk.DescriptorSetLayoutBinding = .{ const vp_layout_binding: vk.DescriptorSetLayoutBinding = .{
.binding = 0, // Binding point in shader (designated by binding number in shader) .binding = 0, // Binding point in shader (designated by binding number in shader)
.descriptor_type = .uniform_buffer, // Type of descriptor (unifor, dynamic uniform, image sampler, etc) .descriptor_type = .uniform_buffer, // Type of descriptor (unifor, dynamic uniform, image sampler, etc)
.descriptor_count = 1, // Number of descriptors for binding .descriptor_count = 1, // Number of descriptors for binding
@ -560,10 +576,21 @@ pub const VulkanRenderer = struct {
.p_immutable_samplers = null, // For texture: can make smapler data immutable by specifying in layout .p_immutable_samplers = null, // For texture: can make smapler data immutable by specifying in layout
}; };
// Model binding info
const model_layout_binding: vk.DescriptorSetLayoutBinding = .{
.binding = 1,
.descriptor_type = .uniform_buffer_dynamic,
.descriptor_count = 1,
.stage_flags = .{ .vertex_bit = true },
.p_immutable_samplers = null,
};
const layout_bindings = [_]vk.DescriptorSetLayoutBinding{ vp_layout_binding, model_layout_binding };
// Create descriptor set layout with given bindings // Create descriptor set layout with given bindings
const layout_create_info: vk.DescriptorSetLayoutCreateInfo = .{ const layout_create_info: vk.DescriptorSetLayoutCreateInfo = .{
.binding_count = 1, // Number of binding infos .binding_count = @intCast(layout_bindings.len), // Number of binding infos
.p_bindings = @ptrCast(&mvp_layout_binding), // Array of binding infos .p_bindings = &layout_bindings, // Array of binding infos
}; };
// Create descriptor set layout // Create descriptor set layout
@ -831,40 +858,66 @@ pub const VulkanRenderer = struct {
} }
fn createUniformBuffers(self: *Self) !void { fn createUniformBuffers(self: *Self) !void {
// Buffer size will be size of all three variables (will offset to access) // View projection buffer size
const buffer_size: vk.DeviceSize = @sizeOf(@TypeOf(self.mvp)); const vp_buffer_size: vk.DeviceSize = @sizeOf(UboViewProjection);
// Model buffer size
const model_buffer_size: vk.DeviceSize = self.model_uniform_alignment * MAX_OBJECTS;
// One uniform buffer for each image (and by extension, command buffer) // One uniform buffer for each image (and by extension, command buffer)
self.uniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain_images.len); self.vp_uniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain_images.len);
self.uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len); self.vp_uniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len);
self.model_duniform_buffer = try self.allocator.alloc(vk.Buffer, self.swapchain_images.len);
self.model_duniform_buffer_memory = try self.allocator.alloc(vk.DeviceMemory, self.swapchain_images.len);
// Create the uniform buffers // Create the uniform buffers
for (0..self.uniform_buffer.len) |i| { for (0..self.vp_uniform_buffer.len) |i| {
try Utilities.createBuffer( try Utilities.createBuffer(
self.physical_device, self.physical_device,
self.instance, self.instance,
self.device, self.device,
buffer_size, vp_buffer_size,
.{ .uniform_buffer_bit = true }, .{ .uniform_buffer_bit = true },
.{ .host_visible_bit = true, .host_coherent_bit = true }, .{ .host_visible_bit = true, .host_coherent_bit = true },
&self.uniform_buffer[i], &self.vp_uniform_buffer[i],
&self.uniform_buffer_memory[i], &self.vp_uniform_buffer_memory[i],
);
try Utilities.createBuffer(
self.physical_device,
self.instance,
self.device,
model_buffer_size,
.{ .uniform_buffer_bit = true },
.{ .host_visible_bit = true, .host_coherent_bit = true },
&self.model_duniform_buffer[i],
&self.model_duniform_buffer_memory[i],
); );
} }
} }
fn createDescriptorPool(self: *Self) !void { fn createDescriptorPool(self: *Self) !void {
// Type of descriptors + how many descriptors (!= descriptor sets) (combined makes the pool size) // Type of descriptors + how many descriptors (!= descriptor sets) (combined makes the pool size)
const pool_size: vk.DescriptorPoolSize = .{ // View projection pool
const vp_pool_size: vk.DescriptorPoolSize = .{
.type = .uniform_buffer, .type = .uniform_buffer,
.descriptor_count = @intCast(self.uniform_buffer.len), .descriptor_count = @intCast(self.vp_uniform_buffer.len),
}; };
// Model pool (dynamic)
const model_pool_size: vk.DescriptorPoolSize = .{
.type = .uniform_buffer_dynamic,
.descriptor_count = @intCast(self.model_duniform_buffer.len),
};
// List of pool sizes
const descriptor_pool_sizes = [_]vk.DescriptorPoolSize{ vp_pool_size, model_pool_size };
// Data to create descriptor pool // Data to create descriptor pool
const pool_create_info: vk.DescriptorPoolCreateInfo = .{ const pool_create_info: vk.DescriptorPoolCreateInfo = .{
.max_sets = @intCast(self.uniform_buffer.len), // Maximum number of descriptor sets that can be created from pool .max_sets = @intCast(self.swapchain_images.len), // Maximum number of descriptor sets that can be created from pool
.pool_size_count = 1, // Amount of pool sizes being passed .pool_size_count = @intCast(descriptor_pool_sizes.len), // Amount of pool sizes being passed
.p_pool_sizes = @ptrCast(&pool_size), // Pool sizes to create pool with .p_pool_sizes = &descriptor_pool_sizes, // Pool sizes to create pool with
}; };
// Create descriptor pool // Create descriptor pool
@ -873,9 +926,9 @@ pub const VulkanRenderer = struct {
fn createDescriptorSets(self: *Self) !void { fn createDescriptorSets(self: *Self) !void {
// One descriptor set for every buffer // One descriptor set for every buffer
self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.uniform_buffer.len); self.descriptor_sets = try self.allocator.alloc(vk.DescriptorSet, self.swapchain_images.len);
var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.uniform_buffer.len); var set_layouts = try self.allocator.alloc(vk.DescriptorSetLayout, self.swapchain_images.len);
defer self.allocator.free(set_layouts); defer self.allocator.free(set_layouts);
for (0..set_layouts.len) |i| { for (0..set_layouts.len) |i| {
set_layouts[i] = self.descriptor_set_layout; set_layouts[i] = self.descriptor_set_layout;
@ -884,7 +937,7 @@ pub const VulkanRenderer = struct {
// Descriptor set allocation info // Descriptor set allocation info
const set_alloc_info: vk.DescriptorSetAllocateInfo = .{ const set_alloc_info: vk.DescriptorSetAllocateInfo = .{
.descriptor_pool = self.descriptor_pool, // Pool to allocate descriptor set from .descriptor_pool = self.descriptor_pool, // Pool to allocate descriptor set from
.descriptor_set_count = @intCast(self.descriptor_sets.len), // Number of sets to allocate .descriptor_set_count = @intCast(self.swapchain_images.len), // Number of sets to allocate
.p_set_layouts = set_layouts.ptr, // Layouts to use to allocate sets (1:1 relationship) .p_set_layouts = set_layouts.ptr, // Layouts to use to allocate sets (1:1 relationship)
}; };
@ -892,37 +945,83 @@ pub const VulkanRenderer = struct {
try self.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr); try self.device.allocateDescriptorSets(&set_alloc_info, self.descriptor_sets.ptr);
// Update all of descriptor set buffer bindings // Update all of descriptor set buffer bindings
for (0..self.descriptor_sets.len) |i| { for (0..self.swapchain_images.len) |i| {
// -- View projection descriptor
// Buffer info and data offset info // Buffer info and data offset info
const mvp_buffer_info: vk.DescriptorBufferInfo = .{ const vp_buffer_info: vk.DescriptorBufferInfo = .{
.buffer = self.uniform_buffer[i], // Bufer to get data from .buffer = self.vp_uniform_buffer[i], // Bufer to get data from
.offset = 0, // Position of start of data .offset = 0, // Position of start of data
.range = @sizeOf(@TypeOf(self.mvp)), // Size of data .range = @sizeOf(UboViewProjection), // Size of data
}; };
// Data about connection between binding and buffer // Data about connection between binding and buffer
const mvp_set_write: vk.WriteDescriptorSet = .{ const vp_set_write: vk.WriteDescriptorSet = .{
.dst_set = self.descriptor_sets[i], // Descriptor set to update .dst_set = self.descriptor_sets[i], // Descriptor set to update
.dst_binding = 0, // Binding to update (matches with binding on layout/shader) .dst_binding = 0, // Binding to update (matches with binding on layout/shader)
.dst_array_element = 0, // Index in array to update .dst_array_element = 0, // Index in array to update
.descriptor_type = .uniform_buffer, // Type of descriptor .descriptor_type = .uniform_buffer, // Type of descriptor
.descriptor_count = 1, // Amount to update .descriptor_count = 1, // Amount to update
.p_buffer_info = @ptrCast(&mvp_buffer_info), // Information about buffer data to bind .p_buffer_info = @ptrCast(&vp_buffer_info), // Information about buffer data to bind
.p_image_info = undefined, .p_image_info = undefined,
.p_texel_buffer_view = undefined, .p_texel_buffer_view = undefined,
}; };
// -- Model descriptor
// Model buffer binding info
const model_buffer_info: vk.DescriptorBufferInfo = .{
.buffer = self.model_duniform_buffer[i],
.offset = 0,
.range = self.model_uniform_alignment,
};
const model_set_write: vk.WriteDescriptorSet = .{
.dst_set = self.descriptor_sets[i],
.dst_binding = 1,
.dst_array_element = 0,
.descriptor_type = .uniform_buffer_dynamic,
.descriptor_count = 1,
.p_buffer_info = @ptrCast(&model_buffer_info),
.p_image_info = undefined,
.p_texel_buffer_view = undefined,
};
// List of descriptor set writes
const set_writes = [_]vk.WriteDescriptorSet{ vp_set_write, model_set_write };
// Update the descriptor sets with new buffer/binding info // Update the descriptor sets with new buffer/binding info
self.device.updateDescriptorSets(1, @ptrCast(&mvp_set_write), 0, null); self.device.updateDescriptorSets(@intCast(set_writes.len), &set_writes, 0, null);
} }
} }
fn updateUniformBuffer(self: Self, image_index: u32) !void { fn updateUniformBuffers(self: *Self, image_index: u32) !void {
const data = try self.device.mapMemory(self.uniform_buffer_memory[image_index], 0, @sizeOf(Mvp), .{}); // Copy VP data
var data = try self.device.mapMemory(
self.vp_uniform_buffer_memory[image_index],
0,
@sizeOf(UboViewProjection),
.{},
);
const mvp_data: *Mvp = @ptrCast(@alignCast(data)); const vp_data: *UboViewProjection = @ptrCast(@alignCast(data));
mvp_data.* = self.mvp; vp_data.* = self.ubo_view_projection;
self.device.unmapMemory(self.uniform_buffer_memory[image_index]); self.device.unmapMemory(self.vp_uniform_buffer_memory[image_index]);
// Copy model data
for (self.meshes, 0..) |mesh, i| {
self.model_transfer_space[i] = mesh.ubo_model;
}
// Map the list of model data
data = try self.device.mapMemory(
self.model_duniform_buffer_memory[image_index],
0,
self.model_uniform_alignment * self.meshes.len,
.{},
);
const model_data: [*]UboModel = @ptrCast(@alignCast(data));
@memcpy(model_data, self.model_transfer_space[0..self.meshes.len]);
self.device.unmapMemory(self.model_duniform_buffer_memory[image_index]);
} }
fn recordCommands(self: *Self) !void { fn recordCommands(self: *Self) !void {
@ -962,7 +1061,7 @@ pub const VulkanRenderer = struct {
command_buffer.setViewport(0, 1, @ptrCast(&self.viewport)); command_buffer.setViewport(0, 1, @ptrCast(&self.viewport));
command_buffer.setScissor(0, 1, @ptrCast(&self.scissor)); command_buffer.setScissor(0, 1, @ptrCast(&self.scissor));
for (self.meshes) |mesh| { for (self.meshes, 0..) |mesh, j| {
// 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);
@ -976,6 +1075,9 @@ pub const VulkanRenderer = struct {
// Bind mesh index buffer, with 0 offset and using the uint32 type // Bind mesh index buffer, with 0 offset and using the uint32 type
command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32); command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32);
// Dynamic offset amount
const dynamic_offset: u32 = @intCast(self.model_uniform_alignment * j);
// Bind descriptor sets // Bind descriptor sets
command_buffer.bindDescriptorSets( command_buffer.bindDescriptorSets(
.graphics, .graphics,
@ -983,8 +1085,8 @@ pub const VulkanRenderer = struct {
0, 0,
1, 1,
@ptrCast(&self.descriptor_sets[i]), @ptrCast(&self.descriptor_sets[i]),
0, 1,
null, @ptrCast(&dynamic_offset),
); );
// Execute a pipeline // Execute a pipeline
@ -1018,6 +1120,21 @@ pub const VulkanRenderer = struct {
// TODO Obviously needs to be something else // TODO Obviously needs to be something else
unreachable; unreachable;
} }
// Get properties of our new device
const device_props = self.instance.getPhysicalDeviceProperties(self.physical_device);
self.min_uniform_buffer_offset = device_props.limits.min_uniform_buffer_offset_alignment;
}
fn allocateDynamicBufferTransferSpace(self: *Self) !void {
// TODO Needed in zig (we have align())?
// Calculate alignment of model data
self.model_uniform_alignment =
(@sizeOf(UboModel) + self.min_uniform_buffer_offset - 1) & ~(self.min_uniform_buffer_offset - 1);
// Create space in memory to hold dynamic buffer that is aligned to our required alignment and holds MAX_OBJECTS
// self.model_transfer_space = try self.allocator.create(UboModel);
} }
fn getRequiredExtensions(self: Self) ![][*:0]const u8 { fn getRequiredExtensions(self: Self) ![][*:0]const u8 {