CommandBuffer wrapper
This commit is contained in:
90
src/Game.zig
90
src/Game.zig
@@ -8,6 +8,7 @@ const math = @import("math.zig");
|
|||||||
|
|
||||||
const Materials = @import("assets/Materials.zig");
|
const Materials = @import("assets/Materials.zig");
|
||||||
const Textures = @import("assets/Textures.zig");
|
const Textures = @import("assets/Textures.zig");
|
||||||
|
const CommandBuffer = @import("engine/CommandBuffer.zig").CommandBuffer;
|
||||||
const Engine = @import("engine/Engine.zig");
|
const Engine = @import("engine/Engine.zig");
|
||||||
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
|
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
|
||||||
const StagingBuffer = @import("engine/StagingBuffer.zig");
|
const StagingBuffer = @import("engine/StagingBuffer.zig");
|
||||||
@@ -115,7 +116,7 @@ index_buffer: IndexBuffer,
|
|||||||
|
|
||||||
global_uniforms: GlobalUniformsBuffer,
|
global_uniforms: GlobalUniformsBuffer,
|
||||||
global_uniforms_staging_buffer: StagingBuffer,
|
global_uniforms_staging_buffer: StagingBuffer,
|
||||||
global_uniforms_transfer_command_buffer: vk.CommandBuffer,
|
global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent),
|
||||||
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
global_uniforms_transfer_semaphores: []vk.Semaphore,
|
||||||
point_lights: PointLightBuffer,
|
point_lights: PointLightBuffer,
|
||||||
directional_lights: DirectionalLightBuffer,
|
directional_lights: DirectionalLightBuffer,
|
||||||
@@ -305,14 +306,13 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
|||||||
});
|
});
|
||||||
errdefer global_uniforms_staging_buffer.deinit(engine);
|
errdefer global_uniforms_staging_buffer.deinit(engine);
|
||||||
|
|
||||||
const global_uniforms_transfer_command_buffer = try engine.allocateTransferCommandBuffer();
|
var global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent) = try .init(engine);
|
||||||
errdefer engine.freeTransferCommandBuffer(global_uniforms_transfer_command_buffer);
|
errdefer global_uniforms_transfer_command_buffer.deinit(engine);
|
||||||
|
|
||||||
try global_uniforms_transfer_command_buffer.beginCommandBuffer(&.{});
|
try global_uniforms_transfer_command_buffer.beginCommandBuffer(.{});
|
||||||
global_uniforms_transfer_command_buffer.copyBuffer(
|
global_uniforms_transfer_command_buffer.copyBuffer(
|
||||||
global_uniforms_staging_buffer.buffer,
|
global_uniforms_staging_buffer.buffer,
|
||||||
global_uniforms.buffer,
|
global_uniforms.buffer,
|
||||||
1,
|
|
||||||
&.{
|
&.{
|
||||||
.{
|
.{
|
||||||
.src_offset = 0,
|
.src_offset = 0,
|
||||||
@@ -685,7 +685,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
|||||||
|
|
||||||
.global_uniforms = global_uniforms,
|
.global_uniforms = global_uniforms,
|
||||||
.global_uniforms_staging_buffer = global_uniforms_staging_buffer,
|
.global_uniforms_staging_buffer = global_uniforms_staging_buffer,
|
||||||
.global_uniforms_transfer_command_buffer = global_uniforms_transfer_command_buffer.handle,
|
.global_uniforms_transfer_command_buffer = global_uniforms_transfer_command_buffer,
|
||||||
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
|
.global_uniforms_transfer_semaphores = global_uniforms_transfer_semaphores,
|
||||||
.point_lights = point_lights,
|
.point_lights = point_lights,
|
||||||
.directional_lights = directional_lights,
|
.directional_lights = directional_lights,
|
||||||
@@ -706,6 +706,7 @@ pub fn deinit(self: *Game) void {
|
|||||||
|
|
||||||
self.global_uniforms.deinit(self.engine);
|
self.global_uniforms.deinit(self.engine);
|
||||||
self.global_uniforms_staging_buffer.deinit(self.engine);
|
self.global_uniforms_staging_buffer.deinit(self.engine);
|
||||||
|
self.global_uniforms_transfer_command_buffer.deinit(self.engine);
|
||||||
self.point_lights.deinit(self.engine);
|
self.point_lights.deinit(self.engine);
|
||||||
self.directional_lights.deinit(self.engine);
|
self.directional_lights.deinit(self.engine);
|
||||||
self.object_uniforms.deinit(self.engine);
|
self.object_uniforms.deinit(self.engine);
|
||||||
@@ -782,16 +783,9 @@ pub fn update(self: *Game, dt: f32) void {
|
|||||||
@memcpy(staging_memory, std.mem.asBytes(&global_uniforms_data));
|
@memcpy(staging_memory, std.mem.asBytes(&global_uniforms_data));
|
||||||
self.global_uniforms_staging_buffer.unmap(self.engine);
|
self.global_uniforms_staging_buffer.unmap(self.engine);
|
||||||
|
|
||||||
const submits = [_]vk.SubmitInfo{
|
self.global_uniforms_transfer_command_buffer.submit(self.engine, .{
|
||||||
.{
|
.signal_semaphores = &.{self.global_uniforms_transfer_semaphores[self.swapchain.image_index]},
|
||||||
.command_buffer_count = 1,
|
}) catch |err| {
|
||||||
.p_command_buffers = @ptrCast(&self.global_uniforms_transfer_command_buffer),
|
|
||||||
.signal_semaphore_count = 1,
|
|
||||||
.p_signal_semaphores = @ptrCast(&self.global_uniforms_transfer_semaphores[self.swapchain.image_index]),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
self.engine.device.queueSubmit(self.engine.transfer_queue.handle, submits.len, &submits, .null_handle) catch |err| {
|
|
||||||
std.log.err("Failed to submit global uniforms transfer: {s}", .{@errorName(err)});
|
std.log.err("Failed to submit global uniforms transfer: {s}", .{@errorName(err)});
|
||||||
@panic("Frame update failed");
|
@panic("Frame update failed");
|
||||||
};
|
};
|
||||||
@@ -877,41 +871,37 @@ pub fn onMouseUp(self: *Game, button: glfw.MouseButton, mods: glfw.Mods) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render(self: *Game) !void {
|
fn render(self: *Game) !void {
|
||||||
const engine = self.engine;
|
|
||||||
const extent = self.swapchain.extent;
|
const extent = self.swapchain.extent;
|
||||||
|
|
||||||
const command_buffer = try engine.allocateGraphicsCommandBuffer();
|
const command_buffer: CommandBuffer(.graphics, .transient) = try .init(self.engine);
|
||||||
// NOTE Do not free command buffer yet
|
// NOTE Do not free command buffer yet
|
||||||
|
|
||||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try command_buffer.beginCommandBuffer(.{});
|
||||||
{
|
{
|
||||||
const clear_values = [_]vk.ClearValue{
|
command_buffer.beginRenderPass(.{
|
||||||
.{
|
|
||||||
.color = .{
|
|
||||||
.float_32 = .{ 0, 0, 0, 0 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.{
|
|
||||||
.depth_stencil = .{
|
|
||||||
.depth = 0,
|
|
||||||
.stencil = 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
command_buffer.beginRenderPass(&.{
|
|
||||||
.render_pass = self.swapchain.render_pass,
|
.render_pass = self.swapchain.render_pass,
|
||||||
.framebuffer = self.swapchain.swapchain_images[self.swapchain.image_index].framebuffer,
|
.framebuffer = self.swapchain.swapchain_images[self.swapchain.image_index].framebuffer,
|
||||||
.render_area = .{
|
.render_area = .{
|
||||||
.offset = .{ .x = 0, .y = 0 },
|
.offset = .{ .x = 0, .y = 0 },
|
||||||
.extent = extent,
|
.extent = extent,
|
||||||
},
|
},
|
||||||
.clear_value_count = clear_values.len,
|
.clear_values = &.{
|
||||||
.p_clear_values = &clear_values,
|
.{
|
||||||
|
.color = .{
|
||||||
|
.float_32 = .{ 0, 0, 0, 0 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.{
|
||||||
|
.depth_stencil = .{
|
||||||
|
.depth = 0,
|
||||||
|
.stencil = 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}, .@"inline");
|
}, .@"inline");
|
||||||
defer command_buffer.endRenderPass();
|
defer command_buffer.endRenderPass();
|
||||||
|
|
||||||
const viewports = [_]vk.Viewport{
|
command_buffer.setViewport(0, &.{
|
||||||
.{
|
.{
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
@@ -920,29 +910,33 @@ fn render(self: *Game) !void {
|
|||||||
.min_depth = 0,
|
.min_depth = 0,
|
||||||
.max_depth = 1,
|
.max_depth = 1,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
command_buffer.setViewport(0, viewports.len, &viewports);
|
command_buffer.setScissor(0, &.{
|
||||||
|
|
||||||
const scissors = [_]vk.Rect2D{
|
|
||||||
.{
|
.{
|
||||||
.offset = .{ .x = 0, .y = 0 },
|
.offset = .{ .x = 0, .y = 0 },
|
||||||
.extent = extent,
|
.extent = extent,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
command_buffer.setScissor(0, scissors.len, &scissors);
|
|
||||||
|
|
||||||
command_buffer.bindPipeline(.graphics, self.pipeline);
|
command_buffer.bindPipeline(.graphics, self.pipeline);
|
||||||
|
try command_buffer.bindVertexBuffers(0, &.{
|
||||||
command_buffer.bindVertexBuffers(0, 1, @ptrCast(&self.vertex_buffer.buffer), &.{0});
|
.{
|
||||||
|
.buffer = self.vertex_buffer.buffer,
|
||||||
|
.offset = 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
command_buffer.bindIndexBuffer(self.index_buffer.buffer, 0, .uint16);
|
||||||
command_buffer.bindDescriptorSets(.graphics, self.pipeline_layout, 0, self.descriptor_sets.len, &self.descriptor_sets, 0, null);
|
command_buffer.bindDescriptorSets(.graphics, self.pipeline_layout, 0, &self.descriptor_sets, &.{});
|
||||||
|
|
||||||
command_buffer.drawIndexed(@intCast(self.index_buffer.array_capacity), self.object_count, 0, 0, 0);
|
command_buffer.drawIndexed(.{
|
||||||
|
.index_count = self.index_buffer.array_capacity,
|
||||||
|
.instance_count = self.object_count,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
try command_buffer.endCommandBuffer();
|
try command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
const res = try self.swapchain.present(self.engine, .{
|
const res = try self.swapchain.present(self.engine, .{
|
||||||
.command_buffer = command_buffer.handle,
|
.command_buffer = command_buffer,
|
||||||
.wait_semaphores = &.{
|
.wait_semaphores = &.{
|
||||||
.{
|
.{
|
||||||
.semaphore = self.global_uniforms_transfer_semaphores[self.swapchain.image_index],
|
.semaphore = self.global_uniforms_transfer_semaphores[self.swapchain.image_index],
|
||||||
|
|||||||
272
src/engine/CommandBuffer.zig
Normal file
272
src/engine/CommandBuffer.zig
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const Engine = @import("Engine.zig");
|
||||||
|
const QueueType = @import("QueueType.zig").QueueType;
|
||||||
|
const Transient = @import("Transient.zig").Transient;
|
||||||
|
const WaitSemaphore = @import("WaitSemaphore.zig");
|
||||||
|
|
||||||
|
pub const DrawIndexed = struct {
|
||||||
|
index_count: u32,
|
||||||
|
instance_count: u32 = 1,
|
||||||
|
first_index: u32 = 0,
|
||||||
|
vertex_offset: i32 = 0,
|
||||||
|
first_instance: u32 = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const PipelineBarrier = struct {
|
||||||
|
src_stage_mask: vk.PipelineStageFlags,
|
||||||
|
dst_stage_mask: vk.PipelineStageFlags,
|
||||||
|
dependency_flags: vk.DependencyFlags = .{},
|
||||||
|
memory_barriers: []const vk.MemoryBarrier = &.{},
|
||||||
|
buffer_memory_barriers: []const vk.BufferMemoryBarrier = &.{},
|
||||||
|
image_memory_barriers: []const vk.ImageMemoryBarrier = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const RenderPassBeginInfo = struct {
|
||||||
|
render_pass: vk.RenderPass,
|
||||||
|
framebuffer: vk.Framebuffer,
|
||||||
|
render_area: vk.Rect2D,
|
||||||
|
clear_values: []const vk.ClearValue = &.{},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const SubmitInfo = struct {
|
||||||
|
wait_semaphores: []const WaitSemaphore = &.{},
|
||||||
|
signal_semaphores: []const vk.Semaphore = &.{},
|
||||||
|
fence: vk.Fence = .null_handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const VertexBufferBinding = struct {
|
||||||
|
buffer: vk.Buffer,
|
||||||
|
offset: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn CommandBuffer(comptime queue_type: QueueType, comptime transient: Transient) type {
|
||||||
|
return struct {
|
||||||
|
const Self = @This();
|
||||||
|
|
||||||
|
proxy: vk.CommandBufferProxy,
|
||||||
|
allocator: std.mem.Allocator,
|
||||||
|
|
||||||
|
pub fn init(engine: *const Engine) !Self {
|
||||||
|
const handle = try allocateCommandBuffer(engine, queue_type, transient);
|
||||||
|
const proxy: vk.CommandBufferProxy = .init(handle, engine.device.wrapper);
|
||||||
|
const allocator = engine.vk_allocator.allocator;
|
||||||
|
return .{ .proxy = proxy, .allocator = allocator };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self, engine: *const Engine) void {
|
||||||
|
freeCommandBuffer(engine, queue_type, transient, self.proxy.handle);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn submit(self: Self, engine: *const Engine, submit_info: SubmitInfo) !void {
|
||||||
|
try submitCommandBuffer(engine, queue_type, self.proxy.handle, submit_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const CommandBufferBeginInfo = struct {
|
||||||
|
flags: vk.CommandBufferUsageFlags = .{
|
||||||
|
.one_time_submit_bit = switch (transient) {
|
||||||
|
.persistent => false,
|
||||||
|
.transient => true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inheritance_info: ?vk.CommandBufferInheritanceInfo = null,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn beginCommandBuffer(self: Self, begin_info: CommandBufferBeginInfo) !void {
|
||||||
|
try self.proxy.beginCommandBuffer(&.{
|
||||||
|
.flags = begin_info.flags,
|
||||||
|
.p_inheritance_info = if (begin_info.inheritance_info) |*x| x else null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn beginRenderPass(self: Self, render_pass_begin: RenderPassBeginInfo, contents: vk.SubpassContents) void {
|
||||||
|
self.proxy.beginRenderPass(&.{
|
||||||
|
.render_pass = render_pass_begin.render_pass,
|
||||||
|
.framebuffer = render_pass_begin.framebuffer,
|
||||||
|
.render_area = render_pass_begin.render_area,
|
||||||
|
.clear_value_count = @intCast(render_pass_begin.clear_values.len),
|
||||||
|
.p_clear_values = render_pass_begin.clear_values.ptr,
|
||||||
|
}, contents);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn bindDescriptorSets(
|
||||||
|
self: Self,
|
||||||
|
pipeline_bind_point: vk.PipelineBindPoint,
|
||||||
|
layout: vk.PipelineLayout,
|
||||||
|
first_set: u32,
|
||||||
|
descriptor_sets: []const vk.DescriptorSet,
|
||||||
|
dynamic_offsets: []const u32,
|
||||||
|
) void {
|
||||||
|
self.proxy.bindDescriptorSets(
|
||||||
|
pipeline_bind_point,
|
||||||
|
layout,
|
||||||
|
first_set,
|
||||||
|
@intCast(descriptor_sets.len),
|
||||||
|
descriptor_sets.ptr,
|
||||||
|
@intCast(dynamic_offsets.len),
|
||||||
|
dynamic_offsets.ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn bindPipeline(self: Self, pipeline_bind_point: vk.PipelineBindPoint, pipeline: vk.Pipeline) void {
|
||||||
|
self.proxy.bindPipeline(pipeline_bind_point, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn bindIndexBuffer(self: Self, buffer: vk.Buffer, offset: u64, index_type: vk.IndexType) void {
|
||||||
|
self.proxy.bindIndexBuffer(buffer, offset, index_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn bindVertexBuffers(self: Self, first_binding: u32, bindings: []const VertexBufferBinding) !void {
|
||||||
|
var vertex_buffer_bindings = std.MultiArrayList(VertexBufferBinding){};
|
||||||
|
defer vertex_buffer_bindings.deinit(self.allocator);
|
||||||
|
try vertex_buffer_bindings.ensureTotalCapacity(self.allocator, bindings.len);
|
||||||
|
|
||||||
|
for (bindings) |binding| {
|
||||||
|
vertex_buffer_bindings.appendAssumeCapacity(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.proxy.bindVertexBuffers(
|
||||||
|
first_binding,
|
||||||
|
@intCast(vertex_buffer_bindings.len),
|
||||||
|
vertex_buffer_bindings.items(.buffer).ptr,
|
||||||
|
vertex_buffer_bindings.items(.offset).ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn drawIndexed(self: Self, draw_indexed: DrawIndexed) void {
|
||||||
|
self.proxy.drawIndexed(
|
||||||
|
draw_indexed.index_count,
|
||||||
|
draw_indexed.instance_count,
|
||||||
|
draw_indexed.first_index,
|
||||||
|
draw_indexed.vertex_offset,
|
||||||
|
draw_indexed.first_instance,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn endCommandBuffer(self: Self) !void {
|
||||||
|
try self.proxy.endCommandBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn endRenderPass(self: Self) void {
|
||||||
|
self.proxy.endRenderPass();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn copyBuffer(
|
||||||
|
self: Self,
|
||||||
|
src_buffer: vk.Buffer,
|
||||||
|
dst_buffer: vk.Buffer,
|
||||||
|
regions: []const vk.BufferCopy,
|
||||||
|
) void {
|
||||||
|
self.proxy.copyBuffer(src_buffer, dst_buffer, @intCast(regions.len), regions.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn copyBufferToImage(
|
||||||
|
self: Self,
|
||||||
|
src_buffer: vk.Buffer,
|
||||||
|
dst_image: vk.Image,
|
||||||
|
dst_image_layout: vk.ImageLayout,
|
||||||
|
regions: []const vk.BufferImageCopy,
|
||||||
|
) void {
|
||||||
|
self.proxy.copyBufferToImage(src_buffer, dst_image, dst_image_layout, @intCast(regions.len), regions.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn pipelineBarrier(self: Self, barrier: PipelineBarrier) void {
|
||||||
|
self.proxy.pipelineBarrier(
|
||||||
|
barrier.src_stage_mask,
|
||||||
|
barrier.dst_stage_mask,
|
||||||
|
barrier.dependency_flags,
|
||||||
|
@intCast(barrier.memory_barriers.len),
|
||||||
|
barrier.memory_barriers.ptr,
|
||||||
|
@intCast(barrier.buffer_memory_barriers.len),
|
||||||
|
barrier.buffer_memory_barriers.ptr,
|
||||||
|
@intCast(barrier.image_memory_barriers.len),
|
||||||
|
barrier.image_memory_barriers.ptr,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn setScissor(self: Self, first_scissor: u32, scissors: []const vk.Rect2D) void {
|
||||||
|
self.proxy.setScissor(first_scissor, @intCast(scissors.len), scissors.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn setViewport(self: Self, first_viewport: u32, viewports: []const vk.Viewport) void {
|
||||||
|
self.proxy.setViewport(first_viewport, @intCast(viewports.len), viewports.ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fn resolveCommandPool(self: *const Engine, comptime queue_type: QueueType, comptime transient: Transient) vk.CommandPool {
|
||||||
|
return switch (queue_type) {
|
||||||
|
.graphics => switch (transient) {
|
||||||
|
.persistent => self.graphics_command_pool,
|
||||||
|
.transient => self.transient_graphics_command_pool,
|
||||||
|
},
|
||||||
|
.compute => switch (transient) {
|
||||||
|
.persistent => self.compute_command_pool,
|
||||||
|
.transient => self.transient_compute_command_pool,
|
||||||
|
},
|
||||||
|
.transfer => switch (transient) {
|
||||||
|
.persistent => self.transfer_command_pool,
|
||||||
|
.transient => self.transient_transfer_command_pool,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn allocateCommandBuffer(engine: *const Engine, comptime queue_type: QueueType, comptime transient: Transient) !vk.CommandBuffer {
|
||||||
|
const command_pool = resolveCommandPool(engine, queue_type, transient);
|
||||||
|
|
||||||
|
var command_buffers: [1]vk.CommandBuffer = undefined;
|
||||||
|
try engine.device.allocateCommandBuffers(&.{
|
||||||
|
.command_pool = command_pool,
|
||||||
|
.level = .primary,
|
||||||
|
.command_buffer_count = command_buffers.len,
|
||||||
|
}, &command_buffers);
|
||||||
|
|
||||||
|
return command_buffers[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
fn freeCommandBuffer(engine: *const Engine, comptime queue_type: QueueType, comptime transient: Transient, command_buffer: vk.CommandBuffer) void {
|
||||||
|
const command_pool = resolveCommandPool(engine, queue_type, transient);
|
||||||
|
const command_buffers = [_]vk.CommandBuffer{command_buffer};
|
||||||
|
|
||||||
|
engine.device.freeCommandBuffers(command_pool, command_buffers.len, &command_buffers);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn submitCommandBuffer(
|
||||||
|
engine: *const Engine,
|
||||||
|
comptime queue_type: QueueType,
|
||||||
|
command_buffer: vk.CommandBuffer,
|
||||||
|
submit_info: SubmitInfo,
|
||||||
|
) !void {
|
||||||
|
const queue = switch (queue_type) {
|
||||||
|
.graphics => engine.graphics_queue.handle,
|
||||||
|
.compute => engine.compute_queue.handle,
|
||||||
|
.transfer => engine.transfer_queue.handle,
|
||||||
|
};
|
||||||
|
|
||||||
|
const command_buffers = [_]vk.CommandBuffer{command_buffer};
|
||||||
|
|
||||||
|
var wait_semaphores = std.MultiArrayList(WaitSemaphore){};
|
||||||
|
defer wait_semaphores.deinit(engine.vk_allocator.allocator);
|
||||||
|
try wait_semaphores.ensureTotalCapacity(engine.vk_allocator.allocator, submit_info.wait_semaphores.len);
|
||||||
|
|
||||||
|
for (submit_info.wait_semaphores) |wait_semaphore| {
|
||||||
|
wait_semaphores.appendAssumeCapacity(wait_semaphore);
|
||||||
|
}
|
||||||
|
|
||||||
|
const submits = [_]vk.SubmitInfo{
|
||||||
|
.{
|
||||||
|
.wait_semaphore_count = @intCast(wait_semaphores.len),
|
||||||
|
.p_wait_semaphores = wait_semaphores.items(.semaphore).ptr,
|
||||||
|
.p_wait_dst_stage_mask = wait_semaphores.items(.stage_flags).ptr,
|
||||||
|
.command_buffer_count = command_buffers.len,
|
||||||
|
.p_command_buffers = &command_buffers,
|
||||||
|
.signal_semaphore_count = @intCast(submit_info.signal_semaphores.len),
|
||||||
|
.p_signal_semaphores = submit_info.signal_semaphores.ptr,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
try engine.device.queueSubmit(queue, submits.len, &submits, submit_info.fence);
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ const glfw = @import("zglfw");
|
|||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
const Queue = @import("Queue.zig");
|
const Queue = @import("Queue.zig");
|
||||||
|
const QueueType = @import("QueueType.zig").QueueType;
|
||||||
const VkAllocator = @import("VkAllocator.zig");
|
const VkAllocator = @import("VkAllocator.zig");
|
||||||
|
|
||||||
pub const Mode = union(enum) {
|
pub const Mode = union(enum) {
|
||||||
@@ -15,18 +16,6 @@ pub const Mode = union(enum) {
|
|||||||
surface: vk.SurfaceKHR,
|
surface: vk.SurfaceKHR,
|
||||||
presentation_queue: Queue,
|
presentation_queue: Queue,
|
||||||
},
|
},
|
||||||
|
|
||||||
pub fn deinit(self: *Mode, instance: vk.InstanceProxy, vk_allocator: *VkAllocator) void {
|
|
||||||
std.log.debug("Deinitializing {*} with InstanceProxy@{{{X},{*}}} and {*}", .{ self, instance.handle, instance.wrapper, vk_allocator });
|
|
||||||
switch (self.*) {
|
|
||||||
.headless => {},
|
|
||||||
.surface => |x| {
|
|
||||||
instance.destroySurfaceKHR(x.surface, &vk_allocator.interface);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ModeTag = std.meta.Tag(Mode);
|
pub const ModeTag = std.meta.Tag(Mode);
|
||||||
@@ -104,6 +93,9 @@ transfer_queue: Queue,
|
|||||||
graphics_command_pool: vk.CommandPool,
|
graphics_command_pool: vk.CommandPool,
|
||||||
compute_command_pool: vk.CommandPool,
|
compute_command_pool: vk.CommandPool,
|
||||||
transfer_command_pool: vk.CommandPool,
|
transfer_command_pool: vk.CommandPool,
|
||||||
|
|
||||||
|
transient_graphics_command_pool: vk.CommandPool,
|
||||||
|
transient_compute_command_pool: vk.CommandPool,
|
||||||
transient_transfer_command_pool: vk.CommandPool,
|
transient_transfer_command_pool: vk.CommandPool,
|
||||||
|
|
||||||
prng_ptr: *std.Random.Pcg,
|
prng_ptr: *std.Random.Pcg,
|
||||||
@@ -337,6 +329,18 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
|||||||
}, &vk_allocator.interface);
|
}, &vk_allocator.interface);
|
||||||
errdefer device.destroyCommandPool(transfer_command_pool, &vk_allocator.interface);
|
errdefer device.destroyCommandPool(transfer_command_pool, &vk_allocator.interface);
|
||||||
|
|
||||||
|
const transient_graphics_command_pool = try device.createCommandPool(&.{
|
||||||
|
.flags = .{ .transient_bit = true },
|
||||||
|
.queue_family_index = queue_allocations.graphics_queue.family,
|
||||||
|
}, &vk_allocator.interface);
|
||||||
|
errdefer device.destroyCommandPool(transient_graphics_command_pool, &vk_allocator.interface);
|
||||||
|
|
||||||
|
const transient_compute_command_pool = try device.createCommandPool(&.{
|
||||||
|
.flags = .{ .transient_bit = true },
|
||||||
|
.queue_family_index = queue_allocations.compute_queue.family,
|
||||||
|
}, &vk_allocator.interface);
|
||||||
|
errdefer device.destroyCommandPool(transient_compute_command_pool, &vk_allocator.interface);
|
||||||
|
|
||||||
const transient_transfer_command_pool = try device.createCommandPool(&.{
|
const transient_transfer_command_pool = try device.createCommandPool(&.{
|
||||||
.flags = .{ .transient_bit = true },
|
.flags = .{ .transient_bit = true },
|
||||||
.queue_family_index = queue_allocations.transfer_queue.family,
|
.queue_family_index = queue_allocations.transfer_queue.family,
|
||||||
@@ -383,6 +387,9 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
|||||||
.graphics_command_pool = graphics_command_pool,
|
.graphics_command_pool = graphics_command_pool,
|
||||||
.compute_command_pool = compute_command_pool,
|
.compute_command_pool = compute_command_pool,
|
||||||
.transfer_command_pool = transfer_command_pool,
|
.transfer_command_pool = transfer_command_pool,
|
||||||
|
|
||||||
|
.transient_graphics_command_pool = transient_graphics_command_pool,
|
||||||
|
.transient_compute_command_pool = transient_compute_command_pool,
|
||||||
.transient_transfer_command_pool = transient_transfer_command_pool,
|
.transient_transfer_command_pool = transient_transfer_command_pool,
|
||||||
|
|
||||||
.prng_ptr = prng_ptr,
|
.prng_ptr = prng_ptr,
|
||||||
@@ -400,6 +407,9 @@ pub fn deinit(self: *Engine) void {
|
|||||||
self.device.destroyCommandPool(self.graphics_command_pool, &self.vk_allocator.interface);
|
self.device.destroyCommandPool(self.graphics_command_pool, &self.vk_allocator.interface);
|
||||||
self.device.destroyCommandPool(self.compute_command_pool, &self.vk_allocator.interface);
|
self.device.destroyCommandPool(self.compute_command_pool, &self.vk_allocator.interface);
|
||||||
self.device.destroyCommandPool(self.transfer_command_pool, &self.vk_allocator.interface);
|
self.device.destroyCommandPool(self.transfer_command_pool, &self.vk_allocator.interface);
|
||||||
|
|
||||||
|
self.device.destroyCommandPool(self.transient_graphics_command_pool, &self.vk_allocator.interface);
|
||||||
|
self.device.destroyCommandPool(self.transient_compute_command_pool, &self.vk_allocator.interface);
|
||||||
self.device.destroyCommandPool(self.transient_transfer_command_pool, &self.vk_allocator.interface);
|
self.device.destroyCommandPool(self.transient_transfer_command_pool, &self.vk_allocator.interface);
|
||||||
|
|
||||||
self.device.destroyDevice(&self.vk_allocator.interface);
|
self.device.destroyDevice(&self.vk_allocator.interface);
|
||||||
@@ -437,70 +447,6 @@ pub fn allocate(self: *const Engine, memory_requirements: vk.MemoryRequirements,
|
|||||||
return error.NoSuitableMemoryType;
|
return error.NoSuitableMemoryType;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn allocateTransientTransferCommandBuffer(self: *const Engine) !vk.CommandBufferProxy {
|
|
||||||
var command_buffer: vk.CommandBuffer = undefined;
|
|
||||||
try self.device.allocateCommandBuffers(&.{
|
|
||||||
.command_pool = self.transient_transfer_command_pool,
|
|
||||||
.level = .primary,
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
}, @ptrCast(&command_buffer));
|
|
||||||
return .init(command_buffer, self.device.wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn allocateTransferCommandBuffer(self: *const Engine) !vk.CommandBufferProxy {
|
|
||||||
var command_buffer: vk.CommandBuffer = undefined;
|
|
||||||
try self.device.allocateCommandBuffers(&.{
|
|
||||||
.command_pool = self.transfer_command_pool,
|
|
||||||
.level = .primary,
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
}, @ptrCast(&command_buffer));
|
|
||||||
return .init(command_buffer, self.device.wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn allocateGraphicsCommandBuffer(self: *const Engine) !vk.CommandBufferProxy {
|
|
||||||
var command_buffer: vk.CommandBuffer = undefined;
|
|
||||||
try self.device.allocateCommandBuffers(&.{
|
|
||||||
.command_pool = self.graphics_command_pool,
|
|
||||||
.level = .primary,
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
}, @ptrCast(&command_buffer));
|
|
||||||
return .init(command_buffer, self.device.wrapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn freeTransferCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy) void {
|
|
||||||
self.device.freeCommandBuffers(self.transfer_command_pool, 1, @ptrCast(&command_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn freeTransientTransferCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy) void {
|
|
||||||
self.device.freeCommandBuffers(self.transient_transfer_command_pool, 1, @ptrCast(&command_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn freeGraphicsCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy) void {
|
|
||||||
self.device.freeCommandBuffers(self.graphics_command_pool, 1, @ptrCast(&command_buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn submitTransferCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy, fence: vk.Fence) !void {
|
|
||||||
const submits = [_]vk.SubmitInfo{
|
|
||||||
.{
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
.p_command_buffers = @ptrCast(&command_buffer.handle),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try self.device.queueSubmit(self.transfer_queue.handle, submits.len, &submits, fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn submitGraphicsCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy, fence: vk.Fence) !void {
|
|
||||||
const submits = [_]vk.SubmitInfo{
|
|
||||||
.{
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
.p_command_buffers = @ptrCast(&command_buffer.handle),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
try self.device.queueSubmit(self.graphics_queue.handle, submits.len, &submits, fence);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn debugUtilsMessengerCallback(
|
fn debugUtilsMessengerCallback(
|
||||||
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
||||||
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ const std = @import("std");
|
|||||||
|
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
||||||
@@ -146,22 +147,17 @@ pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
|
|||||||
@memcpy(staging_memory[array_write_offset..write_size], std.mem.sliceAsBytes(write_info.elements));
|
@memcpy(staging_memory[array_write_offset..write_size], std.mem.sliceAsBytes(write_info.elements));
|
||||||
staging_buffer.unmap(engine);
|
staging_buffer.unmap(engine);
|
||||||
|
|
||||||
const command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
var command_buffer: CommandBuffer(.transfer, .transient) = try .init(engine);
|
||||||
defer engine.freeTransientTransferCommandBuffer(command_buffer);
|
defer command_buffer.deinit(engine);
|
||||||
|
|
||||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try command_buffer.beginCommandBuffer(.{});
|
||||||
command_buffer.copyBuffer(
|
command_buffer.copyBuffer(staging_buffer.buffer, self.buffer, regions.items);
|
||||||
staging_buffer.buffer,
|
|
||||||
self.buffer,
|
|
||||||
@intCast(regions.items.len),
|
|
||||||
regions.items.ptr,
|
|
||||||
);
|
|
||||||
try command_buffer.endCommandBuffer();
|
try command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
const fence = try engine.createFence(.{});
|
const fence = try engine.createFence(.{});
|
||||||
defer engine.destroyFence(fence);
|
defer engine.destroyFence(fence);
|
||||||
|
|
||||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
try command_buffer.submit(engine, .{ .fence = fence });
|
||||||
try engine.waitForFence(fence);
|
try engine.waitForFence(fence);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,14 +168,6 @@ pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
|
|||||||
const data_size = std.math.cast(u32, data.len) orelse return error.Overflow;
|
const data_size = std.math.cast(u32, data.len) orelse return error.Overflow;
|
||||||
std.debug.assert(data_offset + data_size <= size);
|
std.debug.assert(data_offset + data_size <= size);
|
||||||
|
|
||||||
const regions = [_]vk.BufferCopy{
|
|
||||||
.{
|
|
||||||
.src_offset = 0,
|
|
||||||
.dst_offset = data_offset,
|
|
||||||
.size = data_size,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
var staging_buffer = try StagingBuffer.init(engine, .{
|
var staging_buffer = try StagingBuffer.init(engine, .{
|
||||||
.target_queue = self.target_queue,
|
.target_queue = self.target_queue,
|
||||||
.capacity = data_size,
|
.capacity = data_size,
|
||||||
@@ -190,22 +178,27 @@ pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
|
|||||||
@memcpy(staging_memory, data);
|
@memcpy(staging_memory, data);
|
||||||
staging_buffer.unmap(engine);
|
staging_buffer.unmap(engine);
|
||||||
|
|
||||||
const command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
const command_buffer: CommandBuffer(.tranfer, .transient) = try .init(engine);
|
||||||
defer engine.freeTransientTransferCommandBuffer(command_buffer);
|
defer command_buffer.deinit(engine);
|
||||||
|
|
||||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try command_buffer.beginCommandBuffer(.{});
|
||||||
command_buffer.copyBuffer(
|
command_buffer.copyBuffer(
|
||||||
staging_buffer.buffer,
|
staging_buffer.buffer,
|
||||||
self.buffer,
|
self.buffer,
|
||||||
@intCast(regions.items.len),
|
&.{
|
||||||
regions.items.ptr,
|
.{
|
||||||
|
.src_offset = 0,
|
||||||
|
.dst_offset = data_offset,
|
||||||
|
.size = data_size,
|
||||||
|
},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
try command_buffer.endCommandBuffer();
|
try command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
const fence = try engine.createFence(.{});
|
const fence = try engine.createFence(.{});
|
||||||
defer engine.destroyFence(fence);
|
defer engine.destroyFence(fence);
|
||||||
|
|
||||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
try command_buffer.submit(engine, .{ .fence = fence });
|
||||||
try engine.waitForFence(fence);
|
try engine.waitForFence(fence);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
5
src/engine/QueueType.zig
Normal file
5
src/engine/QueueType.zig
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pub const QueueType = enum {
|
||||||
|
graphics,
|
||||||
|
compute,
|
||||||
|
transfer,
|
||||||
|
};
|
||||||
@@ -3,9 +3,11 @@ const std = @import("std");
|
|||||||
|
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const QSM = @import("QueueSharingMode.zig");
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
const Texture = @import("Texture.zig");
|
const Texture = @import("Texture.zig");
|
||||||
|
const WaitSemaphore = @import("WaitSemaphore.zig");
|
||||||
|
|
||||||
params: Params,
|
params: Params,
|
||||||
render_pass: vk.RenderPass,
|
render_pass: vk.RenderPass,
|
||||||
@@ -117,7 +119,7 @@ pub fn deinit(self: *Swapchain, engine: *Engine) void {
|
|||||||
|
|
||||||
const allocator = engine.vk_allocator.allocator;
|
const allocator = engine.vk_allocator.allocator;
|
||||||
|
|
||||||
for (self.swapchain_images) |swapchain_image| {
|
for (self.swapchain_images) |*swapchain_image| {
|
||||||
swapchain_image.deinit(engine);
|
swapchain_image.deinit(engine);
|
||||||
}
|
}
|
||||||
allocator.free(self.swapchain_images);
|
allocator.free(self.swapchain_images);
|
||||||
@@ -178,7 +180,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
|
|||||||
// to revert on error. Instead, we set the current swapchain and images to
|
// to revert on error. Instead, we set the current swapchain and images to
|
||||||
// null and deinit the old swapchain and images.
|
// null and deinit the old swapchain and images.
|
||||||
|
|
||||||
for (old_swapchain_images) |swapchain_image| {
|
for (old_swapchain_images) |*swapchain_image| {
|
||||||
swapchain_image.deinit(engine);
|
swapchain_image.deinit(engine);
|
||||||
}
|
}
|
||||||
allocator.free(self.swapchain_images);
|
allocator.free(self.swapchain_images);
|
||||||
@@ -219,7 +221,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
|
|||||||
var swapchain_images: std.ArrayList(SwapchainImage) = try .initCapacity(allocator, images.len);
|
var swapchain_images: std.ArrayList(SwapchainImage) = try .initCapacity(allocator, images.len);
|
||||||
errdefer swapchain_images.deinit(allocator);
|
errdefer swapchain_images.deinit(allocator);
|
||||||
|
|
||||||
errdefer for (swapchain_images.items) |x| x.deinit(engine);
|
errdefer for (swapchain_images.items) |*x| x.deinit(engine);
|
||||||
|
|
||||||
for (images) |image| {
|
for (images) |image| {
|
||||||
swapchain_images.appendAssumeCapacity(try SwapchainImage.init(engine, .{
|
swapchain_images.appendAssumeCapacity(try SwapchainImage.init(engine, .{
|
||||||
@@ -234,7 +236,7 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
|
|||||||
break :blk try swapchain_images.toOwnedSlice(allocator);
|
break :blk try swapchain_images.toOwnedSlice(allocator);
|
||||||
};
|
};
|
||||||
errdefer {
|
errdefer {
|
||||||
for (new_swapchain_images) |swapchain_image| {
|
for (new_swapchain_images) |*swapchain_image| {
|
||||||
swapchain_image.deinit(engine);
|
swapchain_image.deinit(engine);
|
||||||
}
|
}
|
||||||
allocator.free(new_swapchain_images);
|
allocator.free(new_swapchain_images);
|
||||||
@@ -262,14 +264,9 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
|
|||||||
self.semaphore_image_acquired = semaphore_image_acquired;
|
self.semaphore_image_acquired = semaphore_image_acquired;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const WaitSemaphore = struct {
|
|
||||||
semaphore: vk.Semaphore,
|
|
||||||
stage_flags: vk.PipelineStageFlags = .{ .top_of_pipe_bit = true },
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PresentInfo = struct {
|
pub const PresentInfo = struct {
|
||||||
command_buffer: vk.CommandBuffer,
|
command_buffer: CommandBuffer(.graphics, .transient),
|
||||||
wait_semaphores: []const WaitSemaphore,
|
wait_semaphores: []const WaitSemaphore = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn present(self: *Swapchain, engine: *Engine, present_info: PresentInfo) !PresentResult {
|
pub fn present(self: *Swapchain, engine: *Engine, present_info: PresentInfo) !PresentResult {
|
||||||
@@ -281,42 +278,29 @@ pub fn present(self: *Swapchain, engine: *Engine, present_info: PresentInfo) !Pr
|
|||||||
|
|
||||||
const current_swapchain_image = &self.swapchain_images[self.image_index];
|
const current_swapchain_image = &self.swapchain_images[self.image_index];
|
||||||
try engine.waitForFence(current_swapchain_image.fence);
|
try engine.waitForFence(current_swapchain_image.fence);
|
||||||
if (current_swapchain_image.command_buffer != .null_handle) {
|
if (current_swapchain_image.command_buffer) |*command_buffer| {
|
||||||
device.freeCommandBuffers(engine.graphics_command_pool, 1, @ptrCast(¤t_swapchain_image.command_buffer));
|
command_buffer.deinit(engine);
|
||||||
current_swapchain_image.command_buffer = .null_handle;
|
current_swapchain_image.command_buffer = null;
|
||||||
}
|
}
|
||||||
try engine.resetFence(current_swapchain_image.fence);
|
try engine.resetFence(current_swapchain_image.fence);
|
||||||
|
|
||||||
// --- SUBMIT COMMAND BUFFER -----------------------------------------------
|
// --- SUBMIT COMMAND BUFFER -----------------------------------------------
|
||||||
|
|
||||||
var wait_semaphores = std.MultiArrayList(WaitSemaphore){};
|
var wait_semaphores: std.ArrayList(WaitSemaphore) = try .initCapacity(allocator, 1 + present_info.wait_semaphores.len);
|
||||||
defer wait_semaphores.deinit(allocator);
|
defer wait_semaphores.deinit(allocator);
|
||||||
try wait_semaphores.ensureTotalCapacity(allocator, 1 + present_info.wait_semaphores.len);
|
|
||||||
|
|
||||||
wait_semaphores.appendAssumeCapacity(.{
|
wait_semaphores.appendAssumeCapacity(.{
|
||||||
.semaphore = current_swapchain_image.semaphore_image_acquired,
|
.semaphore = current_swapchain_image.semaphore_image_acquired,
|
||||||
.stage_flags = .{ .top_of_pipe_bit = true },
|
.stage_flags = .{ .top_of_pipe_bit = true },
|
||||||
});
|
});
|
||||||
for (present_info.wait_semaphores) |wait_semaphore| {
|
wait_semaphores.appendSliceAssumeCapacity(present_info.wait_semaphores);
|
||||||
wait_semaphores.appendAssumeCapacity(wait_semaphore);
|
|
||||||
}
|
|
||||||
|
|
||||||
const signal_semaphores = [_]vk.Semaphore{
|
|
||||||
current_swapchain_image.semaphore_render_finished,
|
|
||||||
};
|
|
||||||
|
|
||||||
current_swapchain_image.command_buffer = present_info.command_buffer;
|
current_swapchain_image.command_buffer = present_info.command_buffer;
|
||||||
try device.queueSubmit(engine.graphics_queue.handle, 1, &.{
|
try present_info.command_buffer.submit(engine, .{
|
||||||
.{
|
.wait_semaphores = wait_semaphores.items,
|
||||||
.wait_semaphore_count = @intCast(wait_semaphores.len),
|
.signal_semaphores = &.{current_swapchain_image.semaphore_render_finished},
|
||||||
.p_wait_semaphores = wait_semaphores.items(.semaphore).ptr,
|
.fence = current_swapchain_image.fence,
|
||||||
.p_wait_dst_stage_mask = wait_semaphores.items(.stage_flags).ptr,
|
});
|
||||||
.command_buffer_count = 1,
|
|
||||||
.p_command_buffers = @ptrCast(&present_info.command_buffer),
|
|
||||||
.signal_semaphore_count = signal_semaphores.len,
|
|
||||||
.p_signal_semaphores = &signal_semaphores,
|
|
||||||
},
|
|
||||||
}, current_swapchain_image.fence);
|
|
||||||
|
|
||||||
// --- PRESENT CURRENT FRAME -----------------------------------------------
|
// --- PRESENT CURRENT FRAME -----------------------------------------------
|
||||||
|
|
||||||
@@ -415,7 +399,7 @@ const SwapchainImage = struct {
|
|||||||
semaphore_render_finished: vk.Semaphore,
|
semaphore_render_finished: vk.Semaphore,
|
||||||
fence: vk.Fence,
|
fence: vk.Fence,
|
||||||
framebuffer: vk.Framebuffer,
|
framebuffer: vk.Framebuffer,
|
||||||
command_buffer: vk.CommandBuffer,
|
command_buffer: ?CommandBuffer(.graphics, .transient),
|
||||||
|
|
||||||
const InitProps = struct {
|
const InitProps = struct {
|
||||||
image: vk.Image,
|
image: vk.Image,
|
||||||
@@ -467,18 +451,23 @@ const SwapchainImage = struct {
|
|||||||
.semaphore_render_finished = semaphore_render_finished,
|
.semaphore_render_finished = semaphore_render_finished,
|
||||||
.fence = fence,
|
.fence = fence,
|
||||||
.framebuffer = framebuffer,
|
.framebuffer = framebuffer,
|
||||||
.command_buffer = .null_handle,
|
.command_buffer = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: SwapchainImage, engine: *Engine) void {
|
fn deinit(self: *SwapchainImage, engine: *Engine) void {
|
||||||
std.log.debug("Deinitializing {*} with {*}", .{ &self, engine });
|
std.log.debug("Deinitializing {*} with {*}", .{ &self, engine });
|
||||||
|
|
||||||
engine.waitForFence(self.fence) catch {};
|
engine.waitForFence(self.fence) catch {};
|
||||||
|
if (self.command_buffer) |*command_buffer| {
|
||||||
|
command_buffer.deinit(engine);
|
||||||
|
}
|
||||||
engine.destroyFramebuffer(self.framebuffer);
|
engine.destroyFramebuffer(self.framebuffer);
|
||||||
engine.destroyFence(self.fence);
|
engine.destroyFence(self.fence);
|
||||||
engine.destroySemaphore(self.semaphore_render_finished);
|
engine.destroySemaphore(self.semaphore_render_finished);
|
||||||
engine.destroySemaphore(self.semaphore_image_acquired);
|
engine.destroySemaphore(self.semaphore_image_acquired);
|
||||||
engine.destroyImageView(self.image_view);
|
engine.destroyImageView(self.image_view);
|
||||||
|
|
||||||
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ const std = @import("std");
|
|||||||
|
|
||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
const CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
||||||
@@ -194,64 +195,53 @@ pub fn writeRaw(self: Texture, engine: *Engine, data: []const u8) !void {
|
|||||||
|
|
||||||
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -----------------
|
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -----------------
|
||||||
|
|
||||||
const transfer_command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
var transfer_command_buffer: CommandBuffer(.transfer, .transient) = try .init(engine);
|
||||||
defer engine.freeTransientTransferCommandBuffer(transfer_command_buffer);
|
defer transfer_command_buffer.deinit(engine);
|
||||||
|
|
||||||
try transfer_command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try transfer_command_buffer.beginCommandBuffer(.{});
|
||||||
|
|
||||||
const transfer_transition_barriers = [_]vk.ImageMemoryBarrier{
|
transfer_command_buffer.pipelineBarrier(.{
|
||||||
.{
|
.src_stage_mask = .{ .top_of_pipe_bit = true },
|
||||||
.src_access_mask = .{},
|
.dst_stage_mask = .{ .transfer_bit = true },
|
||||||
.dst_access_mask = .{ .transfer_write_bit = true },
|
.image_memory_barriers = &.{
|
||||||
.old_layout = .undefined,
|
.{
|
||||||
.new_layout = .transfer_dst_optimal,
|
.src_access_mask = .{},
|
||||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
.old_layout = .undefined,
|
||||||
.image = self.image,
|
.new_layout = .transfer_dst_optimal,
|
||||||
.subresource_range = .{
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
.aspect_mask = .{ .color_bit = true },
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
.base_mip_level = 0,
|
.image = self.image,
|
||||||
.level_count = 1,
|
.subresource_range = .{
|
||||||
.base_array_layer = 0,
|
.aspect_mask = .{ .color_bit = true },
|
||||||
.layer_count = 1,
|
.base_mip_level = 0,
|
||||||
|
.level_count = 1,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
transfer_command_buffer.pipelineBarrier(
|
|
||||||
.{ .top_of_pipe_bit = true },
|
|
||||||
.{ .transfer_bit = true },
|
|
||||||
.{},
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
transfer_transition_barriers.len,
|
|
||||||
&transfer_transition_barriers,
|
|
||||||
);
|
|
||||||
|
|
||||||
const regions = [_]vk.BufferImageCopy{
|
|
||||||
.{
|
|
||||||
.buffer_offset = 0,
|
|
||||||
.buffer_row_length = self.width,
|
|
||||||
.buffer_image_height = self.height,
|
|
||||||
.image_subresource = .{
|
|
||||||
.aspect_mask = .{ .color_bit = true },
|
|
||||||
.mip_level = 0,
|
|
||||||
.base_array_layer = 0,
|
|
||||||
.layer_count = 1,
|
|
||||||
},
|
|
||||||
.image_offset = .{ .x = 0, .y = 0, .z = 0 },
|
|
||||||
.image_extent = .{ .width = self.width, .height = self.height, .depth = 1 },
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
transfer_command_buffer.copyBufferToImage(
|
transfer_command_buffer.copyBufferToImage(
|
||||||
staging_buffer.buffer,
|
staging_buffer.buffer,
|
||||||
self.image,
|
self.image,
|
||||||
.transfer_dst_optimal,
|
.transfer_dst_optimal,
|
||||||
regions.len,
|
&.{
|
||||||
®ions,
|
.{
|
||||||
|
.buffer_offset = 0,
|
||||||
|
.buffer_row_length = self.width,
|
||||||
|
.buffer_image_height = self.height,
|
||||||
|
.image_subresource = .{
|
||||||
|
.aspect_mask = .{ .color_bit = true },
|
||||||
|
.mip_level = 0,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
|
.image_offset = .{ .x = 0, .y = 0, .z = 0 },
|
||||||
|
.image_extent = .{ .width = self.width, .height = self.height, .depth = 1 },
|
||||||
|
},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
try transfer_command_buffer.endCommandBuffer();
|
try transfer_command_buffer.endCommandBuffer();
|
||||||
@@ -259,73 +249,48 @@ pub fn writeRaw(self: Texture, engine: *Engine, data: []const u8) !void {
|
|||||||
const semaphore = try engine.createSemaphore();
|
const semaphore = try engine.createSemaphore();
|
||||||
defer engine.destroySemaphore(semaphore);
|
defer engine.destroySemaphore(semaphore);
|
||||||
|
|
||||||
const transfer_submits = [_]vk.SubmitInfo{
|
try transfer_command_buffer.submit(engine, .{
|
||||||
.{
|
.signal_semaphores = &.{semaphore},
|
||||||
.command_buffer_count = 1,
|
});
|
||||||
.p_command_buffers = @ptrCast(&transfer_command_buffer.handle),
|
|
||||||
.signal_semaphore_count = 1,
|
|
||||||
.p_signal_semaphores = @ptrCast(&semaphore),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
try engine.device.queueSubmit(engine.transfer_queue.handle, transfer_submits.len, &transfer_submits, .null_handle);
|
|
||||||
|
|
||||||
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ----------------------
|
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ----------------------
|
||||||
|
|
||||||
const graphics_command_buffer = try engine.allocateGraphicsCommandBuffer();
|
var graphics_command_buffer: CommandBuffer(.graphics, .transient) = try .init(engine);
|
||||||
defer engine.freeGraphicsCommandBuffer(graphics_command_buffer);
|
defer graphics_command_buffer.deinit(engine);
|
||||||
|
|
||||||
try graphics_command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
try graphics_command_buffer.beginCommandBuffer(.{});
|
||||||
|
|
||||||
const graphics_transition_barriers = [_]vk.ImageMemoryBarrier{
|
graphics_command_buffer.pipelineBarrier(.{
|
||||||
.{
|
.src_stage_mask = .{ .transfer_bit = true },
|
||||||
.src_access_mask = .{ .transfer_write_bit = true },
|
.dst_stage_mask = .{ .fragment_shader_bit = true },
|
||||||
.dst_access_mask = .{ .shader_read_bit = true },
|
.image_memory_barriers = &.{
|
||||||
.old_layout = .transfer_dst_optimal,
|
.{
|
||||||
.new_layout = .shader_read_only_optimal,
|
.src_access_mask = .{ .transfer_write_bit = true },
|
||||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
.dst_access_mask = .{ .shader_read_bit = true },
|
||||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
.old_layout = .transfer_dst_optimal,
|
||||||
.image = self.image,
|
.new_layout = .shader_read_only_optimal,
|
||||||
.subresource_range = .{
|
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
.aspect_mask = .{ .color_bit = true },
|
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||||
.base_mip_level = 0,
|
.image = self.image,
|
||||||
.level_count = 1,
|
.subresource_range = .{
|
||||||
.base_array_layer = 0,
|
.aspect_mask = .{ .color_bit = true },
|
||||||
.layer_count = 1,
|
.base_mip_level = 0,
|
||||||
|
.level_count = 1,
|
||||||
|
.base_array_layer = 0,
|
||||||
|
.layer_count = 1,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
|
|
||||||
graphics_command_buffer.pipelineBarrier(
|
|
||||||
.{ .transfer_bit = true },
|
|
||||||
.{ .fragment_shader_bit = true },
|
|
||||||
.{},
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
0,
|
|
||||||
null,
|
|
||||||
graphics_transition_barriers.len,
|
|
||||||
&graphics_transition_barriers,
|
|
||||||
);
|
|
||||||
|
|
||||||
try graphics_command_buffer.endCommandBuffer();
|
try graphics_command_buffer.endCommandBuffer();
|
||||||
|
|
||||||
const wait_stage_masks = [_]vk.PipelineStageFlags{
|
|
||||||
.{ .top_of_pipe_bit = true },
|
|
||||||
};
|
|
||||||
|
|
||||||
const graphics_submits = [_]vk.SubmitInfo{
|
|
||||||
.{
|
|
||||||
.command_buffer_count = 1,
|
|
||||||
.p_command_buffers = @ptrCast(&graphics_command_buffer.handle),
|
|
||||||
.wait_semaphore_count = 1,
|
|
||||||
.p_wait_semaphores = @ptrCast(&semaphore),
|
|
||||||
.p_wait_dst_stage_mask = &wait_stage_masks,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const fence = try engine.createFence(.{});
|
const fence = try engine.createFence(.{});
|
||||||
defer engine.destroyFence(fence);
|
defer engine.destroyFence(fence);
|
||||||
|
|
||||||
try engine.device.queueSubmit(engine.graphics_queue.handle, graphics_submits.len, &graphics_submits, fence);
|
try graphics_command_buffer.submit(engine, .{
|
||||||
|
.wait_semaphores = &.{.{ .semaphore = semaphore }},
|
||||||
|
.fence = fence,
|
||||||
|
});
|
||||||
try engine.waitForFence(fence);
|
try engine.waitForFence(fence);
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/engine/Transient.zig
Normal file
4
src/engine/Transient.zig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub const Transient = enum {
|
||||||
|
persistent,
|
||||||
|
transient,
|
||||||
|
};
|
||||||
4
src/engine/WaitSemaphore.zig
Normal file
4
src/engine/WaitSemaphore.zig
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
|
semaphore: vk.Semaphore,
|
||||||
|
stage_flags: vk.PipelineStageFlags = .{ .top_of_pipe_bit = true },
|
||||||
Reference in New Issue
Block a user