Refactor literally everything
This commit is contained in:
@@ -5,7 +5,7 @@ const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
const QSM = @import("QueueSharingMode.zig");
|
||||
const TargetQueue = @import("TargetQueue.zig").TargetQueue;
|
||||
|
||||
pub const Usage = enum {
|
||||
base_color,
|
||||
@@ -13,7 +13,7 @@ pub const Usage = enum {
|
||||
occlusion_roughness_metallic,
|
||||
emissive,
|
||||
|
||||
pub fn format(self: Usage) vk.Format {
|
||||
pub fn vkFormat(self: Usage) vk.Format {
|
||||
return switch (self) {
|
||||
.base_color => .r8g8b8a8_srgb,
|
||||
.normal => .r8g8b8a8_snorm,
|
||||
@@ -22,7 +22,7 @@ pub const Usage = enum {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleCount(self: Usage) u32 {
|
||||
pub fn samplesPerTexel(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
.base_color => 4,
|
||||
.normal => 4,
|
||||
@@ -34,47 +34,58 @@ pub const Usage = enum {
|
||||
pub fn SampleType(comptime self: Usage) type {
|
||||
return switch (self) {
|
||||
.base_color => u8,
|
||||
.normal => u8,
|
||||
.normal => i8,
|
||||
.occlusion_roughness_metallic => u8,
|
||||
.emissive => f16,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleSize(self: Usage) u32 {
|
||||
pub fn bytesPerSample(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(SampleType(x)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn TexelType(comptime self: Usage) type {
|
||||
return [self.sampleCount()]SampleType(self);
|
||||
return [self.samplesPerTexel()]SampleType(self);
|
||||
}
|
||||
|
||||
pub fn texelSize(self: Usage) u32 {
|
||||
pub fn bytesPerTexel(self: Usage) u32 {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(TexelType(x)),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const InitInfo = struct {
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage: Usage,
|
||||
target_queue: TargetQueue,
|
||||
};
|
||||
|
||||
image: vk.Image,
|
||||
image_view: vk.ImageView,
|
||||
memory: vk.DeviceMemory,
|
||||
device_memory: vk.DeviceMemory,
|
||||
target_queue: TargetQueue,
|
||||
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage: Usage,
|
||||
|
||||
pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
const format: vk.Format = usage.format();
|
||||
pub fn init(engine: *Engine, init_info: InitInfo) !Texture {
|
||||
const target_queue_family = switch (init_info.target_queue) {
|
||||
.graphics => engine.graphics_queue.allocation.family,
|
||||
.compute => engine.compute_queue.allocation.family,
|
||||
};
|
||||
const transfer_queue_family = engine.transfer_queue.allocation.family;
|
||||
|
||||
const qsm = QSM.resolve(engine.graphics_queue.allocation.family, engine.transfer_queue.allocation.family);
|
||||
const image = try engine.device.createImage(&.{
|
||||
const image = try engine.createImage(.{
|
||||
.image_type = .@"2d",
|
||||
.format = format,
|
||||
.format = init_info.usage.vkFormat(),
|
||||
.extent = .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.width = init_info.width,
|
||||
.height = init_info.height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mip_levels = 1,
|
||||
@@ -85,29 +96,21 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
.transfer_dst_bit = true,
|
||||
.sampled_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,
|
||||
.queue_family_indices = &.{ target_queue_family, transfer_queue_family },
|
||||
.initial_layout = .undefined,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyImage(image, &engine.vk_allocator.interface);
|
||||
});
|
||||
errdefer engine.destroyImage(image);
|
||||
|
||||
const memory_requirements = engine.device.getImageMemoryRequirements(image);
|
||||
const memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
||||
errdefer engine.device.freeMemory(memory, &engine.vk_allocator.interface);
|
||||
const device_memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
||||
errdefer engine.freeMemory(device_memory);
|
||||
|
||||
try engine.device.bindImageMemory(image, memory, 0);
|
||||
try engine.device.bindImageMemory(image, device_memory, 0);
|
||||
|
||||
const image_view = try engine.device.createImageView(&.{
|
||||
const image_view = try engine.createImageView(.{
|
||||
.image = image,
|
||||
.view_type = .@"2d",
|
||||
.format = format,
|
||||
.components = .{
|
||||
.r = .identity,
|
||||
.g = .identity,
|
||||
.b = .identity,
|
||||
.a = .identity,
|
||||
},
|
||||
.format = init_info.usage.vkFormat(),
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.base_mip_level = 0,
|
||||
@@ -115,49 +118,72 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
.base_array_layer = 0,
|
||||
.layer_count = 1,
|
||||
},
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyImageView(image_view, &engine.vk_allocator.interface);
|
||||
});
|
||||
errdefer engine.destroyImageView(image_view);
|
||||
|
||||
return .{
|
||||
.image = image,
|
||||
.image_view = image_view,
|
||||
.memory = memory,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.usage = usage,
|
||||
.device_memory = device_memory,
|
||||
.target_queue = init_info.target_queue,
|
||||
.width = init_info.width,
|
||||
.height = init_info.height,
|
||||
.usage = init_info.usage,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Texture, engine: *Engine) void {
|
||||
engine.device.destroyImageView(self.image_view, &engine.vk_allocator.interface);
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyImage(self.image, &engine.vk_allocator.interface);
|
||||
engine.destroyImageView(self.image_view);
|
||||
engine.freeMemory(self.device_memory);
|
||||
engine.destroyImage(self.image);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
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 = @as(usize, self.height) * bytes_per_row;
|
||||
pub fn writeTexels(self: Texture, comptime TexelType: type, engine: *Engine, texels: []const TexelType) !void {
|
||||
const texel_count = try std.math.mul(u32, self.width, self.height);
|
||||
std.debug.assert(texels.len == texel_count);
|
||||
switch (self.usage) {
|
||||
inline else => |x| std.debug.assert(TexelType == x.TexelType()),
|
||||
}
|
||||
|
||||
std.debug.assert(data.len * @sizeOf(T) == byte_length);
|
||||
try self.writeRaw(engine, std.mem.sliceAsBytes(texels));
|
||||
}
|
||||
|
||||
const fence = try engine.device.createFence(&.{}, &engine.vk_allocator.interface);
|
||||
defer engine.device.destroyFence(fence, &engine.vk_allocator.interface);
|
||||
pub fn writeSamples(self: Texture, comptime SampleType: type, engine: *Engine, samples: []const SampleType) !void {
|
||||
const texel_count = try std.math.mul(u32, self.width, self.height);
|
||||
const sample_count = try std.math.mul(u32, texel_count, self.usage.samplesPerTexel());
|
||||
std.debug.assert(samples.len == sample_count);
|
||||
switch (self.usage) {
|
||||
inline else => |x| std.debug.assert(SampleType == x.SampleType()),
|
||||
}
|
||||
|
||||
var staging_buffer: StagingBuffer = try .init(engine, std.mem.sliceAsBytes(data), engine.graphics_queue.allocation.family);
|
||||
try self.writeRaw(engine, std.mem.sliceAsBytes(samples));
|
||||
}
|
||||
|
||||
pub fn writeRaw(self: Texture, engine: *Engine, data: []const u8) !void {
|
||||
const texel_count = try std.math.mul(u32, self.width, self.height);
|
||||
const byte_length = try std.math.mul(u32, texel_count, self.usage.bytesPerTexel());
|
||||
std.debug.assert(data.len == byte_length);
|
||||
|
||||
var staging_buffer = try StagingBuffer.init(engine, .{
|
||||
.capacity = @intCast(byte_length),
|
||||
.target_queue = self.target_queue,
|
||||
});
|
||||
defer staging_buffer.deinit(engine);
|
||||
|
||||
const staging_memory = try staging_buffer.map(engine);
|
||||
@memcpy(staging_memory, data);
|
||||
staging_buffer.unmap(engine);
|
||||
|
||||
// --- TRANSITION TO TRANSFER_DST_OPTIMAL AND COPY -----------------
|
||||
|
||||
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{
|
||||
const transfer_transition_barriers = [_]vk.ImageMemoryBarrier{
|
||||
.{
|
||||
.src_access_mask = .{},
|
||||
.dst_access_mask = .{ .transfer_write_bit = true },
|
||||
@@ -184,8 +210,8 @@ pub fn write(self: Texture, comptime T: type, engine: *Engine, data: []const T)
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
pre_copy_barriers.len,
|
||||
&pre_copy_barriers,
|
||||
transfer_transition_barriers.len,
|
||||
&transfer_transition_barriers,
|
||||
);
|
||||
|
||||
const regions = [_]vk.BufferImageCopy{
|
||||
@@ -213,14 +239,28 @@ pub fn write(self: Texture, comptime T: type, engine: *Engine, data: []const T)
|
||||
);
|
||||
|
||||
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));
|
||||
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);
|
||||
|
||||
// --- TRANSITION TO SHADER_READ_ONLY_OPTIMAL ----------------------
|
||||
|
||||
const graphics_command_buffer = try engine.allocateGraphicsCommandBuffer();
|
||||
defer engine.freeGraphicsCommandBuffer(graphics_command_buffer);
|
||||
|
||||
try graphics_command_buffer.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } });
|
||||
|
||||
const post_copy_barriers = [_]vk.ImageMemoryBarrier{
|
||||
const graphics_transition_barriers = [_]vk.ImageMemoryBarrier{
|
||||
.{
|
||||
.src_access_mask = .{ .transfer_write_bit = true },
|
||||
.dst_access_mask = .{ .shader_read_bit = true },
|
||||
@@ -247,12 +287,29 @@ pub fn write(self: Texture, comptime T: type, engine: *Engine, data: []const T)
|
||||
null,
|
||||
0,
|
||||
null,
|
||||
post_copy_barriers.len,
|
||||
&post_copy_barriers,
|
||||
graphics_transition_barriers.len,
|
||||
&graphics_transition_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));
|
||||
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 engine.waitForFence(fence);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user