Begin new Asset Pipeline
This commit is contained in:
51
src/engine/IndexBuffer.zig
Normal file
51
src/engine/IndexBuffer.zig
Normal file
@@ -0,0 +1,51 @@
|
||||
const IndexBuffer = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
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 buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_dst_bit = true,
|
||||
.index_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
|
||||
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);
|
||||
|
||||
return .{
|
||||
.buffer = buffer,
|
||||
.memory = memory,
|
||||
.index_count = index_count,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *IndexBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn write(self: IndexBuffer, engine: *Engine, indices: []const u16) !void {
|
||||
std.debug.assert(indices.len == self.index_count);
|
||||
|
||||
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(indices), engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
}
|
||||
54
src/engine/StagingBuffer.zig
Normal file
54
src/engine/StagingBuffer.zig
Normal file
@@ -0,0 +1,54 @@
|
||||
const StagingBuffer = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
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 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);
|
||||
|
||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||
const memory = try engine.allocate(
|
||||
memory_requirements,
|
||||
.{
|
||||
.host_visible_bit = true,
|
||||
.host_coherent_bit = true,
|
||||
},
|
||||
);
|
||||
errdefer engine.device.freeMemory(memory, &engine.vk_allocator.interface);
|
||||
|
||||
try engine.device.bindBufferMemory(buffer, memory, 0);
|
||||
|
||||
const mapped_memory: [*]u8 = @ptrCast(try engine.device.mapMemory(memory, 0, data.len, .{}) orelse return error.OutOfMemory);
|
||||
defer engine.device.unmapMemory(memory);
|
||||
@memcpy(mapped_memory, data);
|
||||
|
||||
return .{
|
||||
.buffer = buffer,
|
||||
.memory = memory,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *StagingBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
74
src/engine/StorageBuffer.zig
Normal file
74
src/engine/StorageBuffer.zig
Normal file
@@ -0,0 +1,74 @@
|
||||
const StorageBuffer = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
prefix_size: usize,
|
||||
element_size: usize,
|
||||
array_offset: usize,
|
||||
array_capacity: usize,
|
||||
|
||||
pub fn init(engine: *Engine, comptime PrefixType: type, comptime ElementType: type, array_capacity: usize) !StorageBuffer {
|
||||
const prefix_size = @sizeOf(PrefixType);
|
||||
const array_offset = std.mem.alignForward(usize, prefix_size, @alignOf(ElementType));
|
||||
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 buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_dst_bit = true,
|
||||
.storage_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
|
||||
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);
|
||||
|
||||
return .{
|
||||
.buffer = buffer,
|
||||
.memory = memory,
|
||||
.prefix_size = prefix_size,
|
||||
.element_size = element_size,
|
||||
.array_offset = array_offset,
|
||||
.array_capacity = array_capacity,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *StorageBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
|
||||
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);
|
||||
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 size = self.array_offset + array_size_in_bytes;
|
||||
|
||||
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);
|
||||
defer staging_buffer.deinit(engine);
|
||||
}
|
||||
139
src/engine/Texture.zig
Normal file
139
src/engine/Texture.zig
Normal file
@@ -0,0 +1,139 @@
|
||||
const Texture = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
|
||||
pub const Usage = enum {
|
||||
base_color,
|
||||
normal,
|
||||
occlusion_roughness_metallic,
|
||||
emissive,
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleCount(self: Usage) usize {
|
||||
return switch (self) {
|
||||
.base_color => 3,
|
||||
.normal => 3,
|
||||
.occlusion_roughness_metallic => 3,
|
||||
.emissive => 3,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn SampleType(comptime self: Usage) type {
|
||||
return switch (self) {
|
||||
.base_color => u8,
|
||||
.normal => u8,
|
||||
.occlusion_roughness_metallic => u8,
|
||||
.emissive => f16,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn sampleSize(self: Usage) usize {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(SampleType(x)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn TexelType(comptime self: Usage) type {
|
||||
return [self.sampleCount()]SampleType(self);
|
||||
}
|
||||
|
||||
pub fn texelSize(self: Usage) usize {
|
||||
return switch (self) {
|
||||
inline else => |x| @sizeOf(TexelType(x)),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
image: vk.Image,
|
||||
image_view: vk.ImageView,
|
||||
memory: vk.DeviceMemory,
|
||||
|
||||
width: u32,
|
||||
height: u32,
|
||||
usage: Usage,
|
||||
|
||||
pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||
const format: vk.Format = usage.format();
|
||||
|
||||
const image = try engine.device.createImage(&.{
|
||||
.image_type = .@"2d",
|
||||
.format = format,
|
||||
.extent = .{
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depth = 1,
|
||||
},
|
||||
.mip_levels = 1,
|
||||
.array_layers = 1,
|
||||
.samples = .{ .@"1_bit" = true },
|
||||
.tiling = .optimal,
|
||||
.usage = .{
|
||||
.transfer_src_bit = true,
|
||||
.sampled_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
.initial_layout = .undefined,
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyImage(image, &engine.vk_allocator.interface);
|
||||
|
||||
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);
|
||||
|
||||
try engine.device.bindImageMemory(image, memory, 0);
|
||||
|
||||
const image_view = try engine.device.createImageView(&.{
|
||||
.image = image,
|
||||
.view_type = .@"2d",
|
||||
.format = format,
|
||||
.components = .{
|
||||
.r = .identity,
|
||||
.g = .identity,
|
||||
.b = .identity,
|
||||
.a = .identity,
|
||||
},
|
||||
.subresource_range = .{
|
||||
.aspect_mask = .{ .color_bit = true },
|
||||
.base_mip_level = 0,
|
||||
.level_count = 1,
|
||||
.base_array_level = 0,
|
||||
.layer_count = 1,
|
||||
},
|
||||
}, &engine.vk_allocator.interface);
|
||||
errdefer engine.device.destroyImageView(image_view, &engine.vk_allocator.interface);
|
||||
|
||||
return .{
|
||||
.image = image,
|
||||
.image_view = image_view,
|
||||
.memory = memory,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn write(self: Texture, comptime T: type, data: []const T) void {
|
||||
const bytes_per_texel = self.format.texelSize();
|
||||
const bytes_per_row = self.width * bytes_per_texel;
|
||||
const byte_length = self.height * bytes_per_row;
|
||||
|
||||
std.debug.assert(data.len * @sizeOf(T) == byte_length);
|
||||
}
|
||||
55
src/engine/VertexBuffer.zig
Normal file
55
src/engine/VertexBuffer.zig
Normal file
@@ -0,0 +1,55 @@
|
||||
const VertexBuffer = @This();
|
||||
const std = @import("std");
|
||||
|
||||
const vk = @import("vulkan");
|
||||
|
||||
const Engine = @import("Engine.zig");
|
||||
const StagingBuffer = @import("StagingBuffer.zig");
|
||||
|
||||
buffer: vk.Buffer,
|
||||
memory: vk.DeviceMemory,
|
||||
vertex_size: usize,
|
||||
vertex_count: usize,
|
||||
|
||||
pub fn init(engine: *Engine, comptime VertexType: type, vertex_count: usize) !VertexBuffer {
|
||||
const vertex_size = @sizeOf(VertexType);
|
||||
const size = std.math.mul(usize, vertex_count, vertex_size) catch return error.OutOfMemory;
|
||||
|
||||
const buffer = try engine.device.createBuffer(&.{
|
||||
.size = size,
|
||||
.usage = .{
|
||||
.transfer_dst_bit = true,
|
||||
.vertex_buffer_bit = true,
|
||||
},
|
||||
.sharing_mode = .exclusive,
|
||||
}, null);
|
||||
errdefer engine.device.destroyBuffer(buffer);
|
||||
|
||||
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);
|
||||
|
||||
return .{
|
||||
.buffer = buffer,
|
||||
.memory = memory,
|
||||
.vertex_size = vertex_size,
|
||||
.vertex_count = vertex_count,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *VertexBuffer, engine: *Engine) void {
|
||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
||||
engine.device.destroyBuffer(self.buffer);
|
||||
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
pub fn write(self: VertexBuffer, comptime VertexType: type, engine: *Engine, vertices: []const VertexType) !void {
|
||||
std.debug.assert(vertices.len == self.vertex_count);
|
||||
std.debug.assert(@sizeOf(VertexType) == self.vertex_size);
|
||||
|
||||
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(vertices), engine.graphics_queue.allocation.family);
|
||||
defer staging_buffer.deinit(engine);
|
||||
}
|
||||
Reference in New Issue
Block a user