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 Textures = @import("assets/Textures.zig");
|
||||
const CommandBuffer = @import("engine/CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("engine/Engine.zig");
|
||||
const GenericBuffer = @import("engine/GenericBuffer.zig").GenericBuffer;
|
||||
const StagingBuffer = @import("engine/StagingBuffer.zig");
|
||||
@@ -115,7 +116,7 @@ index_buffer: IndexBuffer,
|
||||
|
||||
global_uniforms: GlobalUniformsBuffer,
|
||||
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,
|
||||
point_lights: PointLightBuffer,
|
||||
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);
|
||||
|
||||
const global_uniforms_transfer_command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
errdefer engine.freeTransferCommandBuffer(global_uniforms_transfer_command_buffer);
|
||||
var global_uniforms_transfer_command_buffer: CommandBuffer(.graphics, .persistent) = try .init(engine);
|
||||
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_staging_buffer.buffer,
|
||||
global_uniforms.buffer,
|
||||
1,
|
||||
&.{
|
||||
.{
|
||||
.src_offset = 0,
|
||||
@@ -685,7 +685,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine, swapchain: *Swapchain
|
||||
|
||||
.global_uniforms = global_uniforms,
|
||||
.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,
|
||||
.point_lights = point_lights,
|
||||
.directional_lights = directional_lights,
|
||||
@@ -706,6 +706,7 @@ pub fn deinit(self: *Game) void {
|
||||
|
||||
self.global_uniforms.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.directional_lights.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));
|
||||
self.global_uniforms_staging_buffer.unmap(self.engine);
|
||||
|
||||
const submits = [_]vk.SubmitInfo{
|
||||
.{
|
||||
.command_buffer_count = 1,
|
||||
.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| {
|
||||
self.global_uniforms_transfer_command_buffer.submit(self.engine, .{
|
||||
.signal_semaphores = &.{self.global_uniforms_transfer_semaphores[self.swapchain.image_index]},
|
||||
}) catch |err| {
|
||||
std.log.err("Failed to submit global uniforms transfer: {s}", .{@errorName(err)});
|
||||
@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 {
|
||||
const engine = self.engine;
|
||||
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
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
try command_buffer.beginCommandBuffer(.{});
|
||||
{
|
||||
const clear_values = [_]vk.ClearValue{
|
||||
.{
|
||||
.color = .{
|
||||
.float_32 = .{ 0, 0, 0, 0 },
|
||||
},
|
||||
},
|
||||
.{
|
||||
.depth_stencil = .{
|
||||
.depth = 0,
|
||||
.stencil = 0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
command_buffer.beginRenderPass(&.{
|
||||
command_buffer.beginRenderPass(.{
|
||||
.render_pass = self.swapchain.render_pass,
|
||||
.framebuffer = self.swapchain.swapchain_images[self.swapchain.image_index].framebuffer,
|
||||
.render_area = .{
|
||||
.offset = .{ .x = 0, .y = 0 },
|
||||
.extent = extent,
|
||||
},
|
||||
.clear_value_count = clear_values.len,
|
||||
.p_clear_values = &clear_values,
|
||||
.clear_values = &.{
|
||||
.{
|
||||
.color = .{
|
||||
.float_32 = .{ 0, 0, 0, 0 },
|
||||
},
|
||||
},
|
||||
.{
|
||||
.depth_stencil = .{
|
||||
.depth = 0,
|
||||
.stencil = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
}, .@"inline");
|
||||
defer command_buffer.endRenderPass();
|
||||
|
||||
const viewports = [_]vk.Viewport{
|
||||
command_buffer.setViewport(0, &.{
|
||||
.{
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
@@ -920,29 +910,33 @@ fn render(self: *Game) !void {
|
||||
.min_depth = 0,
|
||||
.max_depth = 1,
|
||||
},
|
||||
};
|
||||
command_buffer.setViewport(0, viewports.len, &viewports);
|
||||
|
||||
const scissors = [_]vk.Rect2D{
|
||||
});
|
||||
command_buffer.setScissor(0, &.{
|
||||
.{
|
||||
.offset = .{ .x = 0, .y = 0 },
|
||||
.extent = extent,
|
||||
},
|
||||
};
|
||||
command_buffer.setScissor(0, scissors.len, &scissors);
|
||||
});
|
||||
|
||||
command_buffer.bindPipeline(.graphics, self.pipeline);
|
||||
|
||||
command_buffer.bindVertexBuffers(0, 1, @ptrCast(&self.vertex_buffer.buffer), &.{0});
|
||||
try command_buffer.bindVertexBuffers(0, &.{
|
||||
.{
|
||||
.buffer = self.vertex_buffer.buffer,
|
||||
.offset = 0,
|
||||
},
|
||||
});
|
||||
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();
|
||||
|
||||
const res = try self.swapchain.present(self.engine, .{
|
||||
.command_buffer = command_buffer.handle,
|
||||
.command_buffer = command_buffer,
|
||||
.wait_semaphores = &.{
|
||||
.{
|
||||
.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 Queue = @import("Queue.zig");
|
||||
const QueueType = @import("QueueType.zig").QueueType;
|
||||
const VkAllocator = @import("VkAllocator.zig");
|
||||
|
||||
pub const Mode = union(enum) {
|
||||
@@ -15,18 +16,6 @@ pub const Mode = union(enum) {
|
||||
surface: vk.SurfaceKHR,
|
||||
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);
|
||||
@@ -104,6 +93,9 @@ transfer_queue: Queue,
|
||||
graphics_command_pool: vk.CommandPool,
|
||||
compute_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,
|
||||
|
||||
prng_ptr: *std.Random.Pcg,
|
||||
@@ -337,6 +329,18 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
||||
}, &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(&.{
|
||||
.flags = .{ .transient_bit = true },
|
||||
.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,
|
||||
.compute_command_pool = compute_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,
|
||||
|
||||
.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.compute_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.destroyDevice(&self.vk_allocator.interface);
|
||||
@@ -437,70 +447,6 @@ pub fn allocate(self: *const Engine, memory_requirements: vk.MemoryRequirements,
|
||||
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(
|
||||
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
||||
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
||||
|
||||
@@ -2,6 +2,7 @@ const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
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));
|
||||
staging_buffer.unmap(engine);
|
||||
|
||||
const command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
||||
defer engine.freeTransientTransferCommandBuffer(command_buffer);
|
||||
var command_buffer: CommandBuffer(.transfer, .transient) = try .init(engine);
|
||||
defer command_buffer.deinit(engine);
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
command_buffer.copyBuffer(
|
||||
staging_buffer.buffer,
|
||||
self.buffer,
|
||||
@intCast(regions.items.len),
|
||||
regions.items.ptr,
|
||||
);
|
||||
try command_buffer.beginCommandBuffer(.{});
|
||||
command_buffer.copyBuffer(staging_buffer.buffer, self.buffer, regions.items);
|
||||
try command_buffer.endCommandBuffer();
|
||||
|
||||
const fence = try engine.createFence(.{});
|
||||
defer engine.destroyFence(fence);
|
||||
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
try command_buffer.submit(engine, .{ .fence = 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;
|
||||
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, .{
|
||||
.target_queue = self.target_queue,
|
||||
.capacity = data_size,
|
||||
@@ -190,22 +178,27 @@ pub fn GenericBuffer(comptime Header: type, comptime Element: type) type {
|
||||
@memcpy(staging_memory, data);
|
||||
staging_buffer.unmap(engine);
|
||||
|
||||
const command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
||||
defer engine.freeTransientTransferCommandBuffer(command_buffer);
|
||||
const command_buffer: CommandBuffer(.tranfer, .transient) = try .init(engine);
|
||||
defer command_buffer.deinit(engine);
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
try command_buffer.beginCommandBuffer(.{});
|
||||
command_buffer.copyBuffer(
|
||||
staging_buffer.buffer,
|
||||
self.buffer,
|
||||
@intCast(regions.items.len),
|
||||
regions.items.ptr,
|
||||
&.{
|
||||
.{
|
||||
.src_offset = 0,
|
||||
.dst_offset = data_offset,
|
||||
.size = data_size,
|
||||
},
|
||||
},
|
||||
);
|
||||
try command_buffer.endCommandBuffer();
|
||||
|
||||
const fence = try engine.createFence(.{});
|
||||
defer engine.destroyFence(fence);
|
||||
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
try command_buffer.submit(engine, .{ .fence = 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 CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("Engine.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
const Texture = @import("Texture.zig");
|
||||
const WaitSemaphore = @import("WaitSemaphore.zig");
|
||||
|
||||
params: Params,
|
||||
render_pass: vk.RenderPass,
|
||||
@@ -117,7 +119,7 @@ pub fn deinit(self: *Swapchain, engine: *Engine) void {
|
||||
|
||||
const allocator = engine.vk_allocator.allocator;
|
||||
|
||||
for (self.swapchain_images) |swapchain_image| {
|
||||
for (self.swapchain_images) |*swapchain_image| {
|
||||
swapchain_image.deinit(engine);
|
||||
}
|
||||
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
|
||||
// null and deinit the old swapchain and images.
|
||||
|
||||
for (old_swapchain_images) |swapchain_image| {
|
||||
for (old_swapchain_images) |*swapchain_image| {
|
||||
swapchain_image.deinit(engine);
|
||||
}
|
||||
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);
|
||||
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| {
|
||||
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);
|
||||
};
|
||||
errdefer {
|
||||
for (new_swapchain_images) |swapchain_image| {
|
||||
for (new_swapchain_images) |*swapchain_image| {
|
||||
swapchain_image.deinit(engine);
|
||||
}
|
||||
allocator.free(new_swapchain_images);
|
||||
@@ -262,14 +264,9 @@ pub fn recreate(self: *Swapchain, engine: *Engine) !void {
|
||||
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 {
|
||||
command_buffer: vk.CommandBuffer,
|
||||
wait_semaphores: []const WaitSemaphore,
|
||||
command_buffer: CommandBuffer(.graphics, .transient),
|
||||
wait_semaphores: []const WaitSemaphore = &.{},
|
||||
};
|
||||
|
||||
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];
|
||||
try engine.waitForFence(current_swapchain_image.fence);
|
||||
if (current_swapchain_image.command_buffer != .null_handle) {
|
||||
device.freeCommandBuffers(engine.graphics_command_pool, 1, @ptrCast(¤t_swapchain_image.command_buffer));
|
||||
current_swapchain_image.command_buffer = .null_handle;
|
||||
if (current_swapchain_image.command_buffer) |*command_buffer| {
|
||||
command_buffer.deinit(engine);
|
||||
current_swapchain_image.command_buffer = null;
|
||||
}
|
||||
try engine.resetFence(current_swapchain_image.fence);
|
||||
|
||||
// --- 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);
|
||||
try wait_semaphores.ensureTotalCapacity(allocator, 1 + present_info.wait_semaphores.len);
|
||||
|
||||
wait_semaphores.appendAssumeCapacity(.{
|
||||
.semaphore = current_swapchain_image.semaphore_image_acquired,
|
||||
.stage_flags = .{ .top_of_pipe_bit = true },
|
||||
});
|
||||
for (present_info.wait_semaphores) |wait_semaphore| {
|
||||
wait_semaphores.appendAssumeCapacity(wait_semaphore);
|
||||
}
|
||||
|
||||
const signal_semaphores = [_]vk.Semaphore{
|
||||
current_swapchain_image.semaphore_render_finished,
|
||||
};
|
||||
wait_semaphores.appendSliceAssumeCapacity(present_info.wait_semaphores);
|
||||
|
||||
current_swapchain_image.command_buffer = present_info.command_buffer;
|
||||
try device.queueSubmit(engine.graphics_queue.handle, 1, &.{
|
||||
.{
|
||||
.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 = 1,
|
||||
.p_command_buffers = @ptrCast(&present_info.command_buffer),
|
||||
.signal_semaphore_count = signal_semaphores.len,
|
||||
.p_signal_semaphores = &signal_semaphores,
|
||||
},
|
||||
}, current_swapchain_image.fence);
|
||||
try present_info.command_buffer.submit(engine, .{
|
||||
.wait_semaphores = wait_semaphores.items,
|
||||
.signal_semaphores = &.{current_swapchain_image.semaphore_render_finished},
|
||||
.fence = current_swapchain_image.fence,
|
||||
});
|
||||
|
||||
// --- PRESENT CURRENT FRAME -----------------------------------------------
|
||||
|
||||
@@ -415,7 +399,7 @@ const SwapchainImage = struct {
|
||||
semaphore_render_finished: vk.Semaphore,
|
||||
fence: vk.Fence,
|
||||
framebuffer: vk.Framebuffer,
|
||||
command_buffer: vk.CommandBuffer,
|
||||
command_buffer: ?CommandBuffer(.graphics, .transient),
|
||||
|
||||
const InitProps = struct {
|
||||
image: vk.Image,
|
||||
@@ -467,18 +451,23 @@ const SwapchainImage = struct {
|
||||
.semaphore_render_finished = semaphore_render_finished,
|
||||
.fence = fence,
|
||||
.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 });
|
||||
|
||||
engine.waitForFence(self.fence) catch {};
|
||||
if (self.command_buffer) |*command_buffer| {
|
||||
command_buffer.deinit(engine);
|
||||
}
|
||||
engine.destroyFramebuffer(self.framebuffer);
|
||||
engine.destroyFence(self.fence);
|
||||
engine.destroySemaphore(self.semaphore_render_finished);
|
||||
engine.destroySemaphore(self.semaphore_image_acquired);
|
||||
engine.destroyImageView(self.image_view);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const CommandBuffer = @import("CommandBuffer.zig").CommandBuffer;
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
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 -----------------
|
||||
|
||||
const transfer_command_buffer = try engine.allocateTransientTransferCommandBuffer();
|
||||
defer engine.freeTransientTransferCommandBuffer(transfer_command_buffer);
|
||||
var transfer_command_buffer: CommandBuffer(.transfer, .transient) = try .init(engine);
|
||||
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{
|
||||
.{
|
||||
.src_access_mask = .{},
|
||||
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||
.old_layout = .undefined,
|
||||
.new_layout = .transfer_dst_optimal,
|
||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.image = self.image,
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.base_mip_level = 0,
|
||||
.level_count = 1,
|
||||
.base_array_layer = 0,
|
||||
.layer_count = 1,
|
||||
transfer_command_buffer.pipelineBarrier(.{
|
||||
.src_stage_mask = .{ .top_of_pipe_bit = true },
|
||||
.dst_stage_mask = .{ .transfer_bit = true },
|
||||
.image_memory_barriers = &.{
|
||||
.{
|
||||
.src_access_mask = .{},
|
||||
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||
.old_layout = .undefined,
|
||||
.new_layout = .transfer_dst_optimal,
|
||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.image = self.image,
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.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(
|
||||
staging_buffer.buffer,
|
||||
self.image,
|
||||
.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();
|
||||
@@ -259,73 +249,48 @@ pub fn writeRaw(self: Texture, engine: *Engine, data: []const u8) !void {
|
||||
const semaphore = try engine.createSemaphore();
|
||||
defer engine.destroySemaphore(semaphore);
|
||||
|
||||
const transfer_submits = [_]vk.SubmitInfo{
|
||||
.{
|
||||
.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);
|
||||
try transfer_command_buffer.submit(engine, .{
|
||||
.signal_semaphores = &.{semaphore},
|
||||
});
|
||||
|
||||
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ----------------------
|
||||
|
||||
const graphics_command_buffer = try engine.allocateGraphicsCommandBuffer();
|
||||
defer engine.freeGraphicsCommandBuffer(graphics_command_buffer);
|
||||
var graphics_command_buffer: CommandBuffer(.graphics, .transient) = try .init(engine);
|
||||
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{
|
||||
.{
|
||||
.src_access_mask = .{ .transfer_write_bit = true },
|
||||
.dst_access_mask = .{ .shader_read_bit = true },
|
||||
.old_layout = .transfer_dst_optimal,
|
||||
.new_layout = .shader_read_only_optimal,
|
||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.image = self.image,
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.base_mip_level = 0,
|
||||
.level_count = 1,
|
||||
.base_array_layer = 0,
|
||||
.layer_count = 1,
|
||||
graphics_command_buffer.pipelineBarrier(.{
|
||||
.src_stage_mask = .{ .transfer_bit = true },
|
||||
.dst_stage_mask = .{ .fragment_shader_bit = true },
|
||||
.image_memory_barriers = &.{
|
||||
.{
|
||||
.src_access_mask = .{ .transfer_write_bit = true },
|
||||
.dst_access_mask = .{ .shader_read_bit = true },
|
||||
.old_layout = .transfer_dst_optimal,
|
||||
.new_layout = .shader_read_only_optimal,
|
||||
.src_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.dst_queue_family_index = vk.QUEUE_FAMILY_IGNORED,
|
||||
.image = self.image,
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.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();
|
||||
|
||||
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(.{});
|
||||
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);
|
||||
}
|
||||
|
||||
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