Add dynamic uniform buffers
This commit is contained in:
parent
b1bbd65aaa
commit
6f4f600fda
4 changed files with 206 additions and 69 deletions
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
12
src/main.zig
12
src/main.zig
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue