Loading materials and textures
This commit is contained in:
@@ -290,7 +290,14 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
||||
|
||||
device_wrapper_ptr.* = .load(device_handle, instance.wrapper.dispatch.vkGetDeviceProcAddr.?);
|
||||
const device = vk.DeviceProxy.init(device_handle, device_wrapper_ptr);
|
||||
errdefer device.destroyDevice(vk_allocator.interface);
|
||||
errdefer device.destroyDevice(&vk_allocator.interface);
|
||||
|
||||
// --- GET QUEUES, CREATE COMMAND POOLS ------------------------------------
|
||||
|
||||
const graphics_queue = try Queue.initAllocation(device, queue_allocations.graphics_queue, false, &vk_allocator.interface);
|
||||
const compute_queue = try Queue.initAllocation(device, queue_allocations.compute_queue, true, &vk_allocator.interface);
|
||||
const transfer_queue = try Queue.initAllocation(device, queue_allocations.transfer_queue, true, &vk_allocator.interface);
|
||||
const presentation_queue = if (maybe_window != null) try Queue.initAllocation(device, queue_allocations.presentation_queue, false, &vk_allocator.interface) else undefined;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -298,7 +305,7 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
||||
.mode = if (maybe_window) |window| .{ .surface = .{
|
||||
.window = window,
|
||||
.surface = surface,
|
||||
.presentation_queue = .initAllocation(device, queue_allocations.presentation_queue),
|
||||
.presentation_queue = presentation_queue,
|
||||
} } else .{ .headless = {} },
|
||||
.vk_allocator = vk_allocator,
|
||||
|
||||
@@ -311,15 +318,22 @@ pub fn init(allocator: std.mem.Allocator, maybe_window: ?*glfw.Window) !Engine {
|
||||
.memory_types = memory_types,
|
||||
.memory_heaps = memory_heaps,
|
||||
|
||||
.graphics_queue = .initAllocation(device, queue_allocations.graphics_queue),
|
||||
.compute_queue = .initAllocation(device, queue_allocations.compute_queue),
|
||||
.transfer_queue = .initAllocation(device, queue_allocations.transfer_queue),
|
||||
.graphics_queue = graphics_queue,
|
||||
.compute_queue = compute_queue,
|
||||
.transfer_queue = transfer_queue,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Engine) void {
|
||||
const allocator = self.vk_allocator.allocator;
|
||||
|
||||
if (std.meta.activeTag(self.mode) == .surface) {
|
||||
self.mode.surface.presentation_queue.deinit(self.device, &self.vk_allocator.interface);
|
||||
}
|
||||
self.transfer_queue.deinit(self.device, &self.vk_allocator.interface);
|
||||
self.compute_queue.deinit(self.device, &self.vk_allocator.interface);
|
||||
self.graphics_queue.deinit(self.device, &self.vk_allocator.interface);
|
||||
|
||||
self.device.destroyDevice(&self.vk_allocator.interface);
|
||||
allocator.destroy(self.device.wrapper);
|
||||
|
||||
@@ -348,13 +362,63 @@ pub fn allocate(self: *const Engine, memory_requirements: vk.MemoryRequirements,
|
||||
return try self.device.allocateMemory(&.{
|
||||
.allocation_size = memory_requirements.size,
|
||||
.memory_type_index = @truncate(i),
|
||||
});
|
||||
}, &self.vk_allocator.interface);
|
||||
}
|
||||
}
|
||||
|
||||
return error.NoSuitableMemoryType;
|
||||
}
|
||||
|
||||
pub fn allocateTransferCommandBuffer(self: *const Engine) !vk.CommandBufferProxy {
|
||||
var command_buffer: vk.CommandBuffer = undefined;
|
||||
try self.device.allocateCommandBuffers(&.{
|
||||
.command_pool = self.transfer_queue.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_queue.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_queue.command_pool, 1, @ptrCast(&command_buffer));
|
||||
}
|
||||
|
||||
pub fn freeGraphicsCommandBuffer(self: *const Engine, command_buffer: vk.CommandBufferProxy) void {
|
||||
self.device.freeCommandBuffers(self.graphics_queue.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,
|
||||
|
||||
@@ -5,6 +5,7 @@ const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
@@ -13,14 +14,17 @@ index_count: usize,
|
||||
pub fn init(engine: *Engine, index_count: usize) !IndexBuffer {
|
||||
const size = std.math.mul(usize, index_count, @sizeOf(u16)) catch return error.OutOfMemory;
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_dst_bit = true,
|
||||
.index_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
@@ -46,6 +50,36 @@ pub fn deinit(self: *IndexBuffer, engine: *Engine) void {
|
||||
pub fn write(self: IndexBuffer, engine: *Engine, indices: []const u16) !void {
|
||||
std.debug.assert(indices.len == self.index_count);
|
||||
|
||||
const fence = try engine.device.createFence(.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
const size = std.mem.sliceAsBytes(indices).len;
|
||||
|
||||
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(indices), engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
|
||||
const command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
defer engine.freeTransferCommandBuffer(command_buffer);
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const regions = [_]vk.BufferCopy{
|
||||
.{
|
||||
.src_offset = 0,
|
||||
.dst_offset = 0,
|
||||
.size = size,
|
||||
},
|
||||
};
|
||||
|
||||
command_buffer.copyBuffer(
|
||||
staging_buffer.buffer,
|
||||
self.buffer,
|
||||
regions.len,
|
||||
®ions,
|
||||
);
|
||||
|
||||
try command_buffer.endCommandBuffer();
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
}
|
||||
|
||||
@@ -9,11 +9,27 @@ pub const Allocation = struct {
|
||||
};
|
||||
|
||||
handle: vk.Queue,
|
||||
command_pool: vk.CommandPool,
|
||||
allocation: Allocation,
|
||||
|
||||
pub fn initAllocation(device: vk.DeviceProxy, allocation: Allocation) Queue {
|
||||
pub fn initAllocation(device: vk.DeviceProxy, allocation: Allocation, transient: bool, p_allocator: ?*const vk.AllocationCallbacks) !Queue {
|
||||
const command_pool = try device.createCommandPool(&.{
|
||||
.flags = .{
|
||||
.transient_bit = transient,
|
||||
.reset_command_buffer_bit = true,
|
||||
},
|
||||
.queue_family_index = allocation.family,
|
||||
}, p_allocator);
|
||||
errdefer device.destroyCommandPool(command_pool, p_allocator);
|
||||
|
||||
return .{
|
||||
.handle = device.getDeviceQueue(allocation.family, allocation.index),
|
||||
.allocation = allocation,
|
||||
.command_pool = command_pool,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Queue, device: vk.DeviceProxy, p_allocator: ?*const vk.AllocationCallbacks) void {
|
||||
device.destroyCommandPool(self.command_pool, p_allocator);
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
20
src/engine/QueueSharingMode.zig
Normal file
20
src/engine/QueueSharingMode.zig
Normal file
@@ -0,0 +1,20 @@
|
||||
const QueueSharingMode = @This();
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
threadlocal var qsm: QueueSharingMode = undefined;
|
||||
|
||||
buffer: [2]u32,
|
||||
sharing_mode: vk.SharingMode,
|
||||
queue_family_index_count: u32,
|
||||
p_queue_family_indices: ?[*]const u32,
|
||||
|
||||
pub fn resolve(a: u32, b: u32) *const QueueSharingMode {
|
||||
const self = &qsm;
|
||||
const same = a == b;
|
||||
self.buffer = .{ a, b };
|
||||
self.sharing_mode = if (same) .exclusive else .concurrent;
|
||||
self.queue_family_index_count = if (same) 0 else 2;
|
||||
self.p_queue_family_indices = if (same) null else &self.buffer;
|
||||
return self;
|
||||
}
|
||||
@@ -4,6 +4,7 @@ const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
@@ -11,18 +12,17 @@ memory: vk.DeviceMemory,
|
||||
pub fn init(engine: *Engine, data: []const u8, destination_queue_family: u32) !StagingBuffer {
|
||||
const transfer_queue_family = engine.transfer_queue.allocation.family;
|
||||
|
||||
const single_queue_family = transfer_queue_family == destination_queue_family;
|
||||
const queue_family_indices: []const u32 = if (single_queue_family) &.{} else &.{ transfer_queue_family, destination_queue_family };
|
||||
|
||||
const qsm = QSM.resolve(destination_queue_family, transfer_queue_family);
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = data.len,
|
||||
.usage = .{
|
||||
.transfer_src_bit = true,
|
||||
},
|
||||
.sharing_mode = if (single_queue_family) .exclusive else .concurrent,
|
||||
.p_queue_family_indices = queue_family_indices.ptr,
|
||||
}, null);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyBuffer(buffer, &engine.vk_allocator.interface);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
const memory = try engine.allocate(
|
||||
@@ -48,7 +48,7 @@ pub fn init(engine: *Engine, data: []const u8, destination_queue_family: u32) !S
|
||||
|
||||
pub fn deinit(self: *StagingBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
engine.device.destroyBuffer(self.buffer, &engine.vk_allocator.interface);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
@@ -19,17 +20,21 @@ pub fn init(engine: *Engine, comptime PrefixType: type, comptime ElementType: ty
|
||||
const element_size = @sizeOf(ElementType);
|
||||
|
||||
const array_capacity_in_bytes = std.math.mul(usize, array_capacity, element_size) catch return error.OutOfMemory;
|
||||
const size = std.math.add(array_offset, array_capacity_in_bytes) catch return error.OutOfMemory;
|
||||
const size = std.math.add(usize, array_offset, array_capacity_in_bytes) catch return error.OutOfMemory;
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_src_bit = true,
|
||||
.transfer_dst_bit = true,
|
||||
.storage_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyBuffer(buffer, &engine.vk_allocator.interface);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
const memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
||||
@@ -49,26 +54,147 @@ pub fn init(engine: *Engine, comptime PrefixType: type, comptime ElementType: ty
|
||||
|
||||
pub fn deinit(self: *StorageBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
engine.device.destroyBuffer(self.buffer, &engine.vk_allocator.interface);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn write(self: StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, prefix: PrefixType, elements: []const ElementType) !void {
|
||||
std.debug.assert(elements.len <= self.array_capacity);
|
||||
pub fn enlarge(self: *StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, array_capacity: usize) !void {
|
||||
std.debug.assert(array_capacity > self.array_capacity);
|
||||
std.debug.assert(@sizeOf(PrefixType) == self.prefix_size);
|
||||
std.debug.assert(@sizeOf(ElementType) == self.element_size);
|
||||
std.debug.assert(std.mem.isAligned(self.array_offset, @alignOf(ElementType)));
|
||||
|
||||
const array_size_in_bytes = elements.len * elements.len;
|
||||
const fence = try engine.device.createFence(&.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
const prefix_size = @sizeOf(PrefixType);
|
||||
const array_offset = std.mem.alignForward(usize, prefix_size, @alignOf(ElementType));
|
||||
const element_size = @sizeOf(ElementType);
|
||||
|
||||
const old_array_size_in_bytes = self.array_capacity * @sizeOf(ElementType);
|
||||
const old_size = self.array_offset + old_array_size_in_bytes;
|
||||
|
||||
const new_array_capacity_in_bytes = std.math.mul(usize, array_capacity, element_size) catch return error.OutOfMemory;
|
||||
const new_size = std.math.add(usize, array_offset, new_array_capacity_in_bytes) catch return error.OutOfMemory;
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = new_size,
|
||||
.usage = .{
|
||||
.transfer_src_bit = true,
|
||||
.transfer_dst_bit = true,
|
||||
.storage_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyBuffer(buffer, &engine.vk_allocator.interface);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
const memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
||||
errdefer engine.device.freeMemory(memory, &engine.vk_allocator.interface);
|
||||
|
||||
try engine.device.bindBufferMemory(buffer, memory, 0);
|
||||
|
||||
const command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
defer engine.freeTransferCommandBuffer(command_buffer);
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const regions = [_]vk.BufferCopy{
|
||||
.{
|
||||
.src_offset = 0,
|
||||
.dst_offset = 0,
|
||||
.size = old_size,
|
||||
},
|
||||
};
|
||||
|
||||
command_buffer.copyBuffer(
|
||||
self.buffer,
|
||||
buffer,
|
||||
regions.len,
|
||||
®ions,
|
||||
);
|
||||
|
||||
try command_buffer.endCommandBuffer();
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer, &engine.vk_allocator.interface);
|
||||
|
||||
self.buffer = buffer;
|
||||
self.memory = memory;
|
||||
self.array_capacity = array_capacity;
|
||||
}
|
||||
|
||||
pub fn write(self: StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, prefix: PrefixType, elements: []const ElementType) !void {
|
||||
try self.writeOffset(PrefixType, ElementType, engine, prefix, 0, elements);
|
||||
}
|
||||
|
||||
pub fn writeOffset(self: StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, prefix: PrefixType, offset: usize, elements: []const ElementType) !void {
|
||||
std.debug.assert(offset + elements.len <= self.array_capacity);
|
||||
std.debug.assert(@sizeOf(PrefixType) == self.prefix_size);
|
||||
std.debug.assert(@sizeOf(ElementType) == self.element_size);
|
||||
std.debug.assert(std.mem.isAligned(self.array_offset, @alignOf(ElementType)));
|
||||
|
||||
const array_size_in_bytes = elements.len * @sizeOf(ElementType);
|
||||
const size = self.array_offset + array_size_in_bytes;
|
||||
|
||||
var regions_buffer: [2]vk.BufferCopy = undefined;
|
||||
var regions: std.ArrayList(vk.BufferCopy) = .initBuffer(®ions_buffer);
|
||||
|
||||
if (self.prefix_size > 0) {
|
||||
regions.appendAssumeCapacity(.{
|
||||
.src_offset = 0,
|
||||
.dst_offset = 0,
|
||||
.size = self.prefix_size,
|
||||
});
|
||||
}
|
||||
|
||||
if (array_size_in_bytes > 0) {
|
||||
regions.appendAssumeCapacity(.{
|
||||
.src_offset = self.array_offset,
|
||||
.dst_offset = self.array_offset + offset * @sizeOf(ElementType),
|
||||
.size = array_size_in_bytes,
|
||||
});
|
||||
}
|
||||
|
||||
if (regions.items.len == 0) {
|
||||
std.log.warn("Zero-length StorageBuffer({s}, {s}) write", .{ @typeName(PrefixType), @typeName(ElementType) });
|
||||
return;
|
||||
}
|
||||
|
||||
const fence = try engine.device.createFence(&.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
const data = try engine.vk_allocator.allocator.alloc(u8, size);
|
||||
defer engine.vk_allocator.allocator.free(data);
|
||||
|
||||
@memcpy(data[0..@sizeOf(PrefixType)], std.mem.asBytes(&prefix));
|
||||
@memcpy(data[self.array_offset..], std.mem.sliceAsBytes(elements));
|
||||
|
||||
const staging_buffer: StagingBuffer = .init(engine, data, engine.graphics_queue.allocation.family);
|
||||
var staging_buffer: StagingBuffer = try .init(engine, data, engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
|
||||
const command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
defer engine.freeTransferCommandBuffer(command_buffer);
|
||||
|
||||
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.endCommandBuffer();
|
||||
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
engine: *Engine,
|
||||
params: Params,
|
||||
@@ -92,12 +93,7 @@ pub fn recreate(self: *Swapchain) !void {
|
||||
|
||||
const surface_capabilities = try self.engine.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(self.engine.physical_device, mode.surface);
|
||||
|
||||
const graphics_queue_family = self.engine.graphics_queue.allocation.family;
|
||||
const presentation_queue_family = mode.presentation_queue.allocation.family;
|
||||
|
||||
const single_queue_family = graphics_queue_family == presentation_queue_family;
|
||||
const queue_family_indices: []const u32 = if (single_queue_family) &.{} else &.{ graphics_queue_family, presentation_queue_family };
|
||||
|
||||
const qsm = QSM.resolve(self.engine.graphics_queue.allocation.family, mode.presentation_queue.allocation.family);
|
||||
const new_swapchain = try self.engine.device.createSwapchainKHR(&.{
|
||||
.surface = mode.surface,
|
||||
.min_image_count = self.params.image_count,
|
||||
@@ -106,9 +102,9 @@ pub fn recreate(self: *Swapchain) !void {
|
||||
.image_extent = extent,
|
||||
.image_array_layers = 1,
|
||||
.image_usage = .{ .color_attachment_bit = true },
|
||||
.image_sharing_mode = if (single_queue_family) .exclusive else .concurrent,
|
||||
.queue_family_index_count = @intCast(queue_family_indices.len),
|
||||
.p_queue_family_indices = queue_family_indices.ptr,
|
||||
.image_sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
.pre_transform = surface_capabilities.current_transform,
|
||||
.composite_alpha = .{ .opaque_bit_khr = true },
|
||||
.present_mode = .fifo_khr,
|
||||
|
||||
@@ -4,6 +4,8 @@ const std = @import("std");
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
pub const Usage = enum {
|
||||
base_color,
|
||||
@@ -13,19 +15,19 @@ pub const Usage = enum {
|
||||
|
||||
pub fn format(self: Usage) vk.Format {
|
||||
return switch (self) {
|
||||
.base_color => .r8g8b8_srgb,
|
||||
.normal => .r8g8b8_snorm,
|
||||
.occlusion_roughness_metallic => .r8g8b8_unorm,
|
||||
.emissive => .r16g16b16_sfloat,
|
||||
.base_color => .r8g8b8a8_srgb,
|
||||
.normal => .r8g8b8a8_snorm,
|
||||
.occlusion_roughness_metallic => .r8g8b8a8_unorm,
|
||||
.emissive => .r16g16b16a16_sfloat,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleCount(self: Usage) usize {
|
||||
pub fn sampleCount(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
.base_color => 3,
|
||||
.normal => 3,
|
||||
.occlusion_roughness_metallic => 3,
|
||||
.emissive => 3,
|
||||
.base_color => 4,
|
||||
.normal => 4,
|
||||
.occlusion_roughness_metallic => 4,
|
||||
.emissive => 4,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ pub const Usage = enum {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleSize(self: Usage) usize {
|
||||
pub fn sampleSize(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(SampleType(x)),
|
||||
};
|
||||
@@ -48,7 +50,7 @@ pub const Usage = enum {
|
||||
return [self.sampleCount()]SampleType(self);
|
||||
}
|
||||
|
||||
pub fn texelSize(self: Usage) usize {
|
||||
pub fn texelSize(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(TexelType(x)),
|
||||
};
|
||||
@@ -66,6 +68,7 @@ usage: Usage,
|
||||
pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
const format: vk.Format = usage.format();
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const image = try engine.device.createImage(&.{
|
||||
.image_type = .@"2d",
|
||||
.format = format,
|
||||
@@ -79,10 +82,12 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
.samples = .{ .@"1_bit" = true },
|
||||
.tiling = .optimal,
|
||||
.usage = .{
|
||||
.transfer_src_bit = true,
|
||||
.transfer_dst_bit = true,
|
||||
.sampled_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
.initial_layout = .undefined,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyImage(image, &engine.vk_allocator.interface);
|
||||
@@ -107,7 +112,7 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.base_mip_level = 0,
|
||||
.level_count = 1,
|
||||
.base_array_level = 0,
|
||||
.base_array_layer = 0,
|
||||
.layer_count = 1,
|
||||
},
|
||||
}, &engine.vk_allocator.interface);
|
||||
@@ -119,6 +124,7 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
.memory = memory,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.usage = usage,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -130,10 +136,123 @@ pub fn deinit(self: *Texture, engine: *Engine) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn write(self: Texture, comptime T: type, data: []const T) void {
|
||||
const bytes_per_texel = self.format.texelSize();
|
||||
pub fn write(self: Texture, comptime T: type, engine: *Engine, data: []const T) !void {
|
||||
const bytes_per_texel = self.usage.texelSize();
|
||||
const bytes_per_row = self.width * bytes_per_texel;
|
||||
const byte_length = self.height * bytes_per_row;
|
||||
const byte_length = @as(usize, self.height) * bytes_per_row;
|
||||
|
||||
std.debug.assert(data.len * @sizeOf(T) == byte_length);
|
||||
|
||||
const fence = try engine.device.createFence(&.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
var staging_buffer: StagingBuffer = try .init(engine, std.mem.sliceAsBytes(data), engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
|
||||
const transfer_command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
defer engine.freeTransferCommandBuffer(transfer_command_buffer);
|
||||
|
||||
const graphics_command_buffer = try engine.allocateGraphicsCommandBuffer();
|
||||
defer engine.freeGraphicsCommandBuffer(graphics_command_buffer);
|
||||
|
||||
try transfer_command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const pre_copy_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(
|
||||
.{ .top_of_pipe_bit = true },
|
||||
.{ .transfer_bit = true },
|
||||
.{},
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
pre_copy_barriers.len,
|
||||
&pre_copy_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,
|
||||
);
|
||||
|
||||
try transfer_command_buffer.endCommandBuffer();
|
||||
try engine.submitTransferCommandBuffer(transfer_command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
try engine.device.resetFences(1, @ptrCast(&fence));
|
||||
|
||||
try graphics_command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const post_copy_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(
|
||||
.{ .transfer_bit = true },
|
||||
.{ .fragment_shader_bit = true },
|
||||
.{},
|
||||
0,
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
post_copy_barriers.len,
|
||||
&post_copy_barriers,
|
||||
);
|
||||
|
||||
try graphics_command_buffer.endCommandBuffer();
|
||||
try engine.submitGraphicsCommandBuffer(graphics_command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
@@ -15,14 +16,17 @@ pub fn init(engine: *Engine, comptime VertexType: type, vertex_count: usize) !Ve
|
||||
const vertex_size = @sizeOf(VertexType);
|
||||
const size = std.math.mul(usize, vertex_count, vertex_size) catch return error.OutOfMemory;
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_dst_bit = true,
|
||||
.vertex_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
.sharing_mode = qsm.sharing_mode,
|
||||
.queue_family_index_count = qsm.queue_family_index_count,
|
||||
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
@@ -50,6 +54,36 @@ pub fn write(self: VertexBuffer, comptime VertexType: type, engine: *Engine, ver
|
||||
std.debug.assert(vertices.len == self.vertex_count);
|
||||
std.debug.assert(@sizeOf(VertexType) == self.vertex_size);
|
||||
|
||||
const fence = try engine.device.createFence(.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
|
||||
const size = std.mem.sliceAsBytes(vertices).len;
|
||||
|
||||
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(vertices), engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
|
||||
const command_buffer = try engine.allocateTransferCommandBuffer();
|
||||
defer engine.freeTransferCommandBuffer(command_buffer);
|
||||
|
||||
try command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const regions = [_]vk.BufferCopy{
|
||||
.{
|
||||
.src_offset = 0,
|
||||
.dst_offset = 0,
|
||||
.size = size,
|
||||
},
|
||||
};
|
||||
|
||||
command_buffer.copyBuffer(
|
||||
staging_buffer.buffer,
|
||||
self.buffer,
|
||||
regions.len,
|
||||
®ions,
|
||||
);
|
||||
|
||||
try command_buffer.endCommandBuffer();
|
||||
try engine.submitTransferCommandBuffer(command_buffer, fence);
|
||||
|
||||
_ = try engine.device.waitForFences(1, @ptrCast(&fence), .true, std.math.maxInt(u64));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user