Loading materials and textures
This commit is contained in:
@@ -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));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user