Loading materials and textures
This commit is contained in:
26
src/Game.zig
26
src/Game.zig
@@ -5,6 +5,8 @@ const glfw = @import("zglfw");
|
|||||||
|
|
||||||
const math = @import("math.zig");
|
const math = @import("math.zig");
|
||||||
|
|
||||||
|
const Atoms = @import("assets/Atoms.zig");
|
||||||
|
const Textures = @import("assets/Textures.zig");
|
||||||
const Materials = @import("assets/Materials.zig");
|
const Materials = @import("assets/Materials.zig");
|
||||||
const Swapchain = @import("engine/Swapchain.zig");
|
const Swapchain = @import("engine/Swapchain.zig");
|
||||||
const Iterator3 = math.Iterator3;
|
const Iterator3 = math.Iterator3;
|
||||||
@@ -16,7 +18,9 @@ const Vector3 = math.Vector3;
|
|||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
swapchain: *Swapchain,
|
swapchain: *Swapchain,
|
||||||
|
|
||||||
|
atoms: Atoms,
|
||||||
materials: Materials,
|
materials: Materials,
|
||||||
|
textures: Textures,
|
||||||
|
|
||||||
camera_position: Vector3 = .init(0, 0, 1.62),
|
camera_position: Vector3 = .init(0, 0, 1.62),
|
||||||
camera_pitch: f32 = 0,
|
camera_pitch: f32 = 0,
|
||||||
@@ -38,24 +42,30 @@ const max_directional_lights = 4;
|
|||||||
const player_speed = 5.0;
|
const player_speed = 5.0;
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator, swapchain: *Swapchain) !Game {
|
pub fn init(allocator: std.mem.Allocator, swapchain: *Swapchain) !Game {
|
||||||
var materials = try Materials.init(allocator);
|
var atoms = Atoms.init(allocator);
|
||||||
errdefer materials.deinit();
|
errdefer atoms.deinit();
|
||||||
|
|
||||||
var it = materials.map.iterator();
|
var materials = try Materials.init(allocator, swapchain.engine);
|
||||||
while (it.next()) |entry| {
|
errdefer materials.deinit(swapchain.engine);
|
||||||
std.debug.print("Material: {s}\n", .{entry.key_ptr.*});
|
|
||||||
std.debug.print("Value: {}\n", .{entry.value_ptr.*});
|
var textures = try Textures.init(allocator, swapchain.engine);
|
||||||
}
|
errdefer textures.deinit(swapchain.engine);
|
||||||
|
|
||||||
|
_ = try materials.getOrLoadId(swapchain.engine, &textures, &atoms, try atoms.getOrPutAtom("Bricks.json"));
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.swapchain = swapchain,
|
.swapchain = swapchain,
|
||||||
|
.atoms = atoms,
|
||||||
.materials = materials,
|
.materials = materials,
|
||||||
|
.textures = textures,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Game) void {
|
pub fn deinit(self: *Game) void {
|
||||||
self.materials.deinit();
|
self.textures.deinit(self.swapchain.engine);
|
||||||
|
self.materials.deinit(self.swapchain.engine);
|
||||||
|
self.atoms.deinit();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,219 +0,0 @@
|
|||||||
const std = @import("std");
|
|
||||||
|
|
||||||
const main = @import("main.zig");
|
|
||||||
const zstbi = @import("zstbi");
|
|
||||||
|
|
||||||
pub const Texture = struct {
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
depth: u32,
|
|
||||||
data: []u8,
|
|
||||||
|
|
||||||
pub fn deinit(self: *Texture, allocator: std.mem.Allocator) void {
|
|
||||||
allocator.free(self.data);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const TextureHdr = struct {
|
|
||||||
width: u32,
|
|
||||||
height: u32,
|
|
||||||
depth: u32,
|
|
||||||
data: []f16,
|
|
||||||
|
|
||||||
pub fn deinit(self: *TextureHdr, allocator: std.mem.Allocator) void {
|
|
||||||
allocator.free(self.data);
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const AssetMap = std.hash_map.StringHashMapUnmanaged;
|
|
||||||
|
|
||||||
pub fn visitTextures(allocator: std.mem.Allocator) AssetMap(Texture) {
|
|
||||||
zstbi.init(allocator);
|
|
||||||
defer zstbi.deinit();
|
|
||||||
|
|
||||||
const cwd = std.fs.cwd();
|
|
||||||
const sub_path = "assets/textures";
|
|
||||||
|
|
||||||
var ret: AssetMap(Texture) = .empty;
|
|
||||||
|
|
||||||
var textures_dir = cwd.openDir(sub_path, .{ .iterate = true }) catch |err| {
|
|
||||||
std.log.err("Could not open \"{s}\" directory: {s}", .{ sub_path, @errorName(err) });
|
|
||||||
return ret;
|
|
||||||
};
|
|
||||||
defer textures_dir.close();
|
|
||||||
|
|
||||||
var it = textures_dir.iterate();
|
|
||||||
while (it.next() catch |err| blk: {
|
|
||||||
std.log.err("Directory iteration interrupted due to an error: {s}", .{@errorName(err)});
|
|
||||||
break :blk null;
|
|
||||||
}) |entry| {
|
|
||||||
if (entry.kind != .file) {
|
|
||||||
std.log.warn("Skipping \"{s}\", which is not a file.", .{entry.name});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var texture = visitTexture(allocator, textures_dir, entry.name) catch {
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
const name = allocator.dupe(u8, std.fs.path.stem(entry.name)) catch {
|
|
||||||
std.log.err("Ran out of memory while trying to allocate asset name", .{});
|
|
||||||
texture.deinit(allocator);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
ret.putNoClobber(allocator, name, texture) catch {
|
|
||||||
std.log.err("Ran out of memory while trying to save asset to map", .{});
|
|
||||||
texture.deinit(allocator);
|
|
||||||
allocator.free(name);
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visitTexture(allocator: std.mem.Allocator, dir: std.fs.Dir, filename: []const u8) !Texture {
|
|
||||||
std.log.info("Processing \"{s}\"...", .{filename});
|
|
||||||
|
|
||||||
const file = dir.openFile(filename, .{}) catch |err| {
|
|
||||||
std.log.err("Could not open \"{s}\" file: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
const file_buf = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
|
|
||||||
std.log.err("Could not read \"{s}\" file contents due to an error: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer allocator.free(file_buf);
|
|
||||||
|
|
||||||
var img = zstbi.Image.loadFromMemory(file_buf, 4) catch |err| {
|
|
||||||
std.log.err("Error reading \"{s}\" as an image file: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer img.deinit();
|
|
||||||
|
|
||||||
std.log.debug("size: {}×{} | components: {}", .{ img.width, img.height, img.num_components });
|
|
||||||
|
|
||||||
const grid_w = 4;
|
|
||||||
const grid_h = 4;
|
|
||||||
const tile_count = grid_w * grid_h;
|
|
||||||
|
|
||||||
const tile_w = std.math.divExact(u32, img.width, grid_w) catch |err| {
|
|
||||||
std.log.err("Cannot divide image width ({}) by {}: {s}", .{ img.width, grid_w, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
const tile_h = std.math.divExact(u32, img.height, grid_h) catch |err| {
|
|
||||||
std.log.err("Cannot divide image height ({}) by {}: {s}", .{ img.height, grid_h, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
|
|
||||||
std.log.debug("tile size: {}×{}", .{ tile_w, tile_h });
|
|
||||||
|
|
||||||
const data = allocator.alloc(u8, 4 * tile_w * tile_h * tile_count) catch |err| {
|
|
||||||
std.log.err("Ran out of memory while trying to allocate output buffer", .{});
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
errdefer allocator.free(data);
|
|
||||||
|
|
||||||
rearrange(grid_w, grid_h, tile_w, tile_h, img.data, data);
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.width = tile_w,
|
|
||||||
.height = tile_h,
|
|
||||||
.depth = tile_count,
|
|
||||||
.data = data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn visitSkybox(allocator: std.mem.Allocator) !TextureHdr {
|
|
||||||
zstbi.init(allocator);
|
|
||||||
defer zstbi.deinit();
|
|
||||||
|
|
||||||
const cwd = std.fs.cwd();
|
|
||||||
const filename = "assets/skybox.hdr";
|
|
||||||
std.log.info("Processing \"{s}\"...", .{filename});
|
|
||||||
|
|
||||||
const file = cwd.openFile(filename, .{}) catch |err| {
|
|
||||||
std.log.err("Could not open \"{s}\" file: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer file.close();
|
|
||||||
|
|
||||||
const file_buf = file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
|
|
||||||
std.log.err("Could not read \"{s}\" file contents due to an error: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer allocator.free(file_buf);
|
|
||||||
|
|
||||||
var img = zstbi.Image.loadFromMemory(file_buf, 4) catch |err| {
|
|
||||||
std.log.err("Error reading \"{s}\" as an image file: {s}", .{ filename, @errorName(err) });
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
defer img.deinit();
|
|
||||||
|
|
||||||
std.log.debug("size: {}×{} | components: {} | hdr: {}", .{ img.width, img.height, img.num_components, img.is_hdr });
|
|
||||||
|
|
||||||
const data = allocator.alloc(f16, 4 * img.width * img.height) catch |err| {
|
|
||||||
std.log.err("Ran out of memory while trying to allocate output buffer", .{});
|
|
||||||
return err;
|
|
||||||
};
|
|
||||||
errdefer allocator.free(data);
|
|
||||||
|
|
||||||
@memcpy(data, std.mem.bytesAsSlice(f16, img.data));
|
|
||||||
|
|
||||||
return .{
|
|
||||||
.width = img.width,
|
|
||||||
.height = img.height,
|
|
||||||
.depth = 1,
|
|
||||||
.data = data,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rearrange(grid_w: u32, grid_h: u32, tile_w: u32, tile_h: u32, inbuf: []const u8, outbuf: []u8) void {
|
|
||||||
std.log.debug("rearrange: {}×{} grid of {}×{} tiles", .{ grid_w, grid_h, tile_w, tile_h });
|
|
||||||
|
|
||||||
const row_size = 4 * tile_w;
|
|
||||||
const row_stride = row_size * grid_w;
|
|
||||||
const tile_stride = row_stride * tile_h;
|
|
||||||
|
|
||||||
std.debug.assert(inbuf.len == tile_stride * grid_h);
|
|
||||||
std.debug.assert(outbuf.len == tile_stride * grid_h);
|
|
||||||
|
|
||||||
var outptr: usize = 0;
|
|
||||||
|
|
||||||
var tile_y: u32 = 0;
|
|
||||||
while (tile_y < grid_h) : (tile_y += 1) {
|
|
||||||
const tile_byte_offset = tile_y * tile_stride;
|
|
||||||
|
|
||||||
var tile_x: u32 = 0;
|
|
||||||
while (tile_x < grid_w) : (tile_x += 1) {
|
|
||||||
const column_byte_offset = tile_x * row_size;
|
|
||||||
|
|
||||||
var row: u32 = 0;
|
|
||||||
while (row < tile_h) : (row += 1) {
|
|
||||||
const row_byte_offset = row * row_stride + tile_byte_offset;
|
|
||||||
const byte_offset = row_byte_offset + column_byte_offset;
|
|
||||||
|
|
||||||
@memcpy(
|
|
||||||
outbuf[outptr .. outptr + row_size],
|
|
||||||
inbuf[byte_offset .. byte_offset + row_size],
|
|
||||||
);
|
|
||||||
|
|
||||||
outptr += row_size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinitTextures(allocator: std.mem.Allocator, map: *AssetMap(Texture)) void {
|
|
||||||
var it = map.iterator();
|
|
||||||
while (it.next()) |entry| {
|
|
||||||
allocator.free(entry.key_ptr.*);
|
|
||||||
entry.value_ptr.deinit(allocator);
|
|
||||||
}
|
|
||||||
map.deinit(allocator);
|
|
||||||
}
|
|
||||||
@@ -11,14 +11,14 @@ pub const Atom = extern struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Map = std.StringHashMapUnmanaged(Atom);
|
pub const Map = std.StringHashMapUnmanaged(Atom);
|
||||||
pub const Array = std.ArrayList([]const u16);
|
pub const Array = std.ArrayList([]const u8);
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) Atoms {
|
pub fn init(allocator: std.mem.Allocator) Atoms {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.string_arena_state = .{},
|
.string_arena_state = .{},
|
||||||
.map = .empty,
|
.map = .empty,
|
||||||
.next_index = 0,
|
.array = .empty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ pub fn getOrPutAtom(self: *Atoms, string: []const u8) !Atom {
|
|||||||
if (entry.found_existing) {
|
if (entry.found_existing) {
|
||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
} else {
|
} else {
|
||||||
errdefer self.map.remove(string);
|
errdefer _ = self.map.remove(string);
|
||||||
try self.array.ensureUnusedCapacity(self.allocator, 1);
|
try self.array.ensureUnusedCapacity(self.allocator, 1);
|
||||||
const owned_string = try self.toOwnedString(string);
|
const owned_string = try self.toOwnedString(string);
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ pub fn getOrPutAtom(self: *Atoms, string: []const u8) !Atom {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn toOwnedString(self: *const Atoms, string: []const u8) ![]const u8 {
|
fn toOwnedString(self: *Atoms, string: []const u8) ![]const u8 {
|
||||||
var string_arena = self.string_arena_state.promote(std.heap.page_allocator);
|
var string_arena = self.string_arena_state.promote(std.heap.page_allocator);
|
||||||
defer self.string_arena_state = string_arena.state;
|
defer self.string_arena_state = string_arena.state;
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,15 @@ const vk = @import("vulkan");
|
|||||||
|
|
||||||
const Atoms = @import("Atoms.zig");
|
const Atoms = @import("Atoms.zig");
|
||||||
const Engine = @import("../engine/Engine.zig");
|
const Engine = @import("../engine/Engine.zig");
|
||||||
|
const StorageBuffer = @import("../engine/StorageBuffer.zig");
|
||||||
const Textures = @import("Textures.zig");
|
const Textures = @import("Textures.zig");
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
map: Map,
|
map: Map,
|
||||||
|
storage_buffer: StorageBuffer,
|
||||||
|
next_id: Id,
|
||||||
|
|
||||||
|
pub const initial_capacity = 4;
|
||||||
|
|
||||||
pub const Id = extern struct {
|
pub const Id = extern struct {
|
||||||
id: u32,
|
id: u32,
|
||||||
@@ -30,22 +35,44 @@ pub const Material = extern struct {
|
|||||||
roughness: f32,
|
roughness: f32,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn init(allocator: std.mem.Allocator) !Materials {
|
pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Materials {
|
||||||
var map: Map = .empty;
|
var map: Map = .empty;
|
||||||
errdefer map.deinit(allocator);
|
errdefer map.deinit(allocator);
|
||||||
|
|
||||||
|
var storage_buffer: StorageBuffer = try .init(engine, void, Material, initial_capacity);
|
||||||
|
errdefer storage_buffer.deinit(engine);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.map = map,
|
.map = map,
|
||||||
|
.storage_buffer = storage_buffer,
|
||||||
|
.next_id = .{ .id = 0 },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Materials) void {
|
pub fn deinit(self: *Materials, engine: *Engine) void {
|
||||||
self.arena.deinit();
|
self.storage_buffer.deinit(engine);
|
||||||
|
self.map.deinit(self.allocator);
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *Atoms, key: Atoms.Atom) !Id {
|
pub fn getId(self: *const Materials, key: Atoms.Atom) ?Id {
|
||||||
|
return self.map.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getOrLoadId(self: *Materials, engine: *Engine, textures: *Textures, atoms: *Atoms, key: Atoms.Atom) !Id {
|
||||||
|
const entry = try self.map.getOrPut(self.allocator, key);
|
||||||
|
|
||||||
|
if (entry.found_existing) {
|
||||||
|
return entry.value_ptr.*;
|
||||||
|
} else {
|
||||||
|
const id = try self.loadMaterial(engine, textures, atoms, key);
|
||||||
|
entry.value_ptr.* = id;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loadMaterial(self: *Materials, engine: *Engine, textures: *Textures, atoms: *Atoms, key: Atoms.Atom) !Id {
|
||||||
const MaterialJson = struct {
|
const MaterialJson = struct {
|
||||||
baseColor: [3]f32 = .{ 1, 1, 1 },
|
baseColor: [3]f32 = .{ 1, 1, 1 },
|
||||||
baseColorTexture: ?[]const u8 = null,
|
baseColorTexture: ?[]const u8 = null,
|
||||||
@@ -89,7 +116,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
|
|||||||
const base_color_texture = blk: {
|
const base_color_texture = blk: {
|
||||||
if (material_json.baseColorTexture) |name| {
|
if (material_json.baseColorTexture) |name| {
|
||||||
const atom = try atoms.getOrPutAtom(name);
|
const atom = try atoms.getOrPutAtom(name);
|
||||||
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .base_color });
|
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .base_color });
|
||||||
} else {
|
} else {
|
||||||
break :blk textures.empty_base_color;
|
break :blk textures.empty_base_color;
|
||||||
}
|
}
|
||||||
@@ -98,7 +125,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
|
|||||||
const emissive_texture = blk: {
|
const emissive_texture = blk: {
|
||||||
if (material_json.emissiveTexture) |name| {
|
if (material_json.emissiveTexture) |name| {
|
||||||
const atom = try atoms.getOrPutAtom(name);
|
const atom = try atoms.getOrPutAtom(name);
|
||||||
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .emissive });
|
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .emissive });
|
||||||
} else {
|
} else {
|
||||||
break :blk textures.empty_emissive;
|
break :blk textures.empty_emissive;
|
||||||
}
|
}
|
||||||
@@ -107,7 +134,7 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
|
|||||||
const normal_texture = blk: {
|
const normal_texture = blk: {
|
||||||
if (material_json.normalTexture) |name| {
|
if (material_json.normalTexture) |name| {
|
||||||
const atom = try atoms.getOrPutAtom(name);
|
const atom = try atoms.getOrPutAtom(name);
|
||||||
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .normal });
|
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .normal });
|
||||||
} else {
|
} else {
|
||||||
break :blk textures.empty_normal;
|
break :blk textures.empty_normal;
|
||||||
}
|
}
|
||||||
@@ -116,23 +143,37 @@ fn loadMaterial(self: *Materials, textures: *Textures, engine: *Engine, atoms: *
|
|||||||
const occlusion_roughness_metallic_texture = blk: {
|
const occlusion_roughness_metallic_texture = blk: {
|
||||||
if (material_json.occlusionRoughnessMetallicTexture) |name| {
|
if (material_json.occlusionRoughnessMetallicTexture) |name| {
|
||||||
const atom = try atoms.getOrPutAtom(name);
|
const atom = try atoms.getOrPutAtom(name);
|
||||||
break :blk try textures.getOrLoadId(engine, .{ .atom = atom, .usage = .occlusion_roughness_metallic });
|
break :blk try textures.getOrLoadId(engine, atoms, .{ .atom = atom, .usage = .occlusion_roughness_metallic });
|
||||||
} else {
|
} else {
|
||||||
break :blk textures.empty_occlusuion_roughness_metallic;
|
break :blk textures.empty_occlusuion_roughness_metallic;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const material: Material = .{
|
const next_id = self.next_id;
|
||||||
.base_color = material_json.baseColor,
|
const offset: usize = next_id.id;
|
||||||
.base_color_texture = base_color_texture,
|
|
||||||
.emissive = material_json.emissive,
|
if (offset >= self.storage_buffer.array_capacity) {
|
||||||
.emissive_texture = emissive_texture,
|
try self.storage_buffer.enlarge(void, Material, engine, self.storage_buffer.array_capacity * 2);
|
||||||
.ior = material_json.ior,
|
}
|
||||||
.metallic = material_json.metallic,
|
|
||||||
.normal_scale = material_json.normalScale,
|
const materials = [_]Material{
|
||||||
.normal_texture = normal_texture,
|
.{
|
||||||
.occlusion_roughness_metallic_texture = occlusion_roughness_metallic_texture,
|
.base_color = material_json.baseColor,
|
||||||
.occlusion_texture_strength = material_json.occlusionTextureStrength,
|
.base_color_texture = base_color_texture,
|
||||||
.roughness = material_json.roughness,
|
.emissive = material_json.emissive,
|
||||||
|
.emissive_texture = emissive_texture,
|
||||||
|
.ior = material_json.ior,
|
||||||
|
.metallic = material_json.metallic,
|
||||||
|
.normal_scale = material_json.normalScale,
|
||||||
|
.normal_texture = normal_texture,
|
||||||
|
.occlusion_roughness_metallic_texture = occlusion_roughness_metallic_texture,
|
||||||
|
.occlusion_texture_strength = material_json.occlusionTextureStrength,
|
||||||
|
.roughness = material_json.roughness,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
try self.storage_buffer.writeOffset(void, Material, engine, {}, offset, &materials);
|
||||||
|
self.next_id = .{ .id = next_id.id + 1 };
|
||||||
|
|
||||||
|
return next_id;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
|
|||||||
|
|
||||||
var array: Array = try .initCapacity(allocator, 4);
|
var array: Array = try .initCapacity(allocator, 4);
|
||||||
errdefer {
|
errdefer {
|
||||||
for (array.items) |texture| {
|
for (array.items) |*texture| {
|
||||||
texture.deinit(engine);
|
texture.deinit(engine);
|
||||||
}
|
}
|
||||||
array.deinit(allocator);
|
array.deinit(allocator);
|
||||||
@@ -56,12 +56,13 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
|
|||||||
const empty_occlusuion_roughness_metallic_texture: Texture = try .init(engine, 1, 1, .occlusion_roughness_metallic);
|
const empty_occlusuion_roughness_metallic_texture: Texture = try .init(engine, 1, 1, .occlusion_roughness_metallic);
|
||||||
array.appendAssumeCapacity(empty_occlusuion_roughness_metallic_texture);
|
array.appendAssumeCapacity(empty_occlusuion_roughness_metallic_texture);
|
||||||
|
|
||||||
empty_base_color_texture.write([3]u8, &.{.{ 255, 255, 255 }});
|
try empty_base_color_texture.write([4]u8, engine, &.{.{ 255, 255, 255, 255 }});
|
||||||
empty_emissive_texture.write([3]f32, &.{.{ 1.0, 1.0, 1.0 }});
|
try empty_emissive_texture.write([4]f16, engine, &.{.{ 1.0, 1.0, 1.0, 1.0 }});
|
||||||
empty_normal_texture.write([3]u8, &.{.{ 128, 128, 255 }});
|
try empty_normal_texture.write([4]u8, engine, &.{.{ 128, 128, 255, 255 }});
|
||||||
empty_occlusuion_roughness_metallic_texture.write([3]u8, &.{.{ 255, 255, 255 }});
|
try empty_occlusuion_roughness_metallic_texture.write([4]u8, engine, &.{.{ 255, 255, 255, 255 }});
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
.allocator = allocator,
|
||||||
.map = map,
|
.map = map,
|
||||||
.array = array,
|
.array = array,
|
||||||
|
|
||||||
@@ -72,13 +73,13 @@ pub fn init(allocator: std.mem.Allocator, engine: *Engine) !Textures {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Textures, allocator: std.mem.Allocator, engine: *Engine) void {
|
pub fn deinit(self: *Textures, engine: *Engine) void {
|
||||||
for (self.array.items) |texture| {
|
for (self.array.items) |*texture| {
|
||||||
texture.deinit(engine);
|
texture.deinit(engine);
|
||||||
}
|
}
|
||||||
self.array.deinit(allocator);
|
self.array.deinit(self.allocator);
|
||||||
|
|
||||||
self.map.deinit(allocator);
|
self.map.deinit(self.allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getTexture(self: *const Textures, id: Id) ?*Texture {
|
pub fn getTexture(self: *const Textures, id: Id) ?*Texture {
|
||||||
@@ -90,15 +91,15 @@ pub fn getId(self: *const Textures, key: Key) ?Id {
|
|||||||
return self.map.get(key);
|
return self.map.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getOrLoadId(self: *Textures, engine: *Engine, key: Key) !Id {
|
pub fn getOrLoadId(self: *Textures, engine: *Engine, atoms: *Atoms, key: Key) !Id {
|
||||||
const entry = try self.map.getOrPut(self.allocator, key);
|
const entry = try self.map.getOrPut(self.allocator, key);
|
||||||
|
|
||||||
if (entry.found_existing) {
|
if (entry.found_existing) {
|
||||||
return entry.value_ptr.*;
|
return entry.value_ptr.*;
|
||||||
} else {
|
} else {
|
||||||
errdefer self.map.remove(key);
|
errdefer _ = self.map.remove(key);
|
||||||
try self.array.ensureUnusedCapacity(self.allocator, 1);
|
try self.array.ensureUnusedCapacity(self.allocator, 1);
|
||||||
const texture = try self.loadTexture(engine, key);
|
const texture = try self.loadTexture(engine, atoms, key);
|
||||||
|
|
||||||
const id = self.nextId();
|
const id = self.nextId();
|
||||||
|
|
||||||
@@ -109,13 +110,14 @@ pub fn getOrLoadId(self: *Textures, engine: *Engine, key: Key) !Id {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loadTexture(self: *Textures, engine: *Engine, key: Key) !Texture {
|
fn loadTexture(self: *Textures, engine: *Engine, atoms: *Atoms, key: Key) !Texture {
|
||||||
|
const filename = atoms.getString(key.atom).?;
|
||||||
const cwd = std.fs.cwd();
|
const cwd = std.fs.cwd();
|
||||||
|
|
||||||
var dir = try cwd.openDir("assets/textures", .{});
|
var dir = try cwd.openDir("assets/textures", .{});
|
||||||
defer dir.close();
|
defer dir.close();
|
||||||
|
|
||||||
const file = try dir.openFile(key.name, .{});
|
const file = try dir.openFile(filename, .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const file_buf = try file.readToEndAlloc(self.allocator, std.math.maxInt(usize));
|
const file_buf = try file.readToEndAlloc(self.allocator, std.math.maxInt(usize));
|
||||||
@@ -128,7 +130,7 @@ fn loadTexture(self: *Textures, engine: *Engine, key: Key) !Texture {
|
|||||||
var texture: Texture = try .init(engine, img.width, img.height, key.usage);
|
var texture: Texture = try .init(engine, img.width, img.height, key.usage);
|
||||||
errdefer texture.deinit(engine);
|
errdefer texture.deinit(engine);
|
||||||
|
|
||||||
texture.write(u8, img.data);
|
try texture.write(u8, engine, img.data);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.?);
|
device_wrapper_ptr.* = .load(device_handle, instance.wrapper.dispatch.vkGetDeviceProcAddr.?);
|
||||||
const device = vk.DeviceProxy.init(device_handle, device_wrapper_ptr);
|
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 = .{
|
.mode = if (maybe_window) |window| .{ .surface = .{
|
||||||
.window = window,
|
.window = window,
|
||||||
.surface = surface,
|
.surface = surface,
|
||||||
.presentation_queue = .initAllocation(device, queue_allocations.presentation_queue),
|
.presentation_queue = presentation_queue,
|
||||||
} } else .{ .headless = {} },
|
} } else .{ .headless = {} },
|
||||||
.vk_allocator = vk_allocator,
|
.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_types = memory_types,
|
||||||
.memory_heaps = memory_heaps,
|
.memory_heaps = memory_heaps,
|
||||||
|
|
||||||
.graphics_queue = .initAllocation(device, queue_allocations.graphics_queue),
|
.graphics_queue = graphics_queue,
|
||||||
.compute_queue = .initAllocation(device, queue_allocations.compute_queue),
|
.compute_queue = compute_queue,
|
||||||
.transfer_queue = .initAllocation(device, queue_allocations.transfer_queue),
|
.transfer_queue = transfer_queue,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Engine) void {
|
pub fn deinit(self: *Engine) void {
|
||||||
const allocator = self.vk_allocator.allocator;
|
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);
|
self.device.destroyDevice(&self.vk_allocator.interface);
|
||||||
allocator.destroy(self.device.wrapper);
|
allocator.destroy(self.device.wrapper);
|
||||||
|
|
||||||
@@ -348,13 +362,63 @@ pub fn allocate(self: *const Engine, memory_requirements: vk.MemoryRequirements,
|
|||||||
return try self.device.allocateMemory(&.{
|
return try self.device.allocateMemory(&.{
|
||||||
.allocation_size = memory_requirements.size,
|
.allocation_size = memory_requirements.size,
|
||||||
.memory_type_index = @truncate(i),
|
.memory_type_index = @truncate(i),
|
||||||
});
|
}, &self.vk_allocator.interface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return error.NoSuitableMemoryType;
|
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(
|
fn debugUtilsMessengerCallback(
|
||||||
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
severity: vk.DebugUtilsMessageSeverityFlagsEXT,
|
||||||
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
message_type: vk.DebugUtilsMessageTypeFlagsEXT,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const vk = @import("vulkan");
|
|||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
buffer: vk.Buffer,
|
buffer: vk.Buffer,
|
||||||
memory: vk.DeviceMemory,
|
memory: vk.DeviceMemory,
|
||||||
@@ -13,14 +14,17 @@ index_count: usize,
|
|||||||
pub fn init(engine: *Engine, index_count: usize) !IndexBuffer {
|
pub fn init(engine: *Engine, index_count: usize) !IndexBuffer {
|
||||||
const size = std.math.mul(usize, index_count, @sizeOf(u16)) catch return error.OutOfMemory;
|
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(&.{
|
const buffer = try engine.device.createBuffer(&.{
|
||||||
.size = size,
|
.size = size,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
.transfer_dst_bit = true,
|
.transfer_dst_bit = true,
|
||||||
.index_buffer_bit = true,
|
.index_buffer_bit = true,
|
||||||
},
|
},
|
||||||
.sharing_mode = .exclusive,
|
.sharing_mode = qsm.sharing_mode,
|
||||||
}, null);
|
.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);
|
errdefer engine.device.destroyBuffer(buffer);
|
||||||
|
|
||||||
const memory_requirements = engine.device.getBufferMemoryRequirements(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 {
|
pub fn write(self: IndexBuffer, engine: *Engine, indices: []const u16) !void {
|
||||||
std.debug.assert(indices.len == self.index_count);
|
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);
|
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(indices), engine.graphics_queue.allocation.family);
|
||||||
defer staging_buffer.deinit(engine);
|
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,
|
handle: vk.Queue,
|
||||||
|
command_pool: vk.CommandPool,
|
||||||
allocation: Allocation,
|
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 .{
|
return .{
|
||||||
.handle = device.getDeviceQueue(allocation.family, allocation.index),
|
.handle = device.getDeviceQueue(allocation.family, allocation.index),
|
||||||
.allocation = allocation,
|
.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 vk = @import("vulkan");
|
||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
buffer: vk.Buffer,
|
buffer: vk.Buffer,
|
||||||
memory: vk.DeviceMemory,
|
memory: vk.DeviceMemory,
|
||||||
@@ -11,18 +12,17 @@ memory: vk.DeviceMemory,
|
|||||||
pub fn init(engine: *Engine, data: []const u8, destination_queue_family: u32) !StagingBuffer {
|
pub fn init(engine: *Engine, data: []const u8, destination_queue_family: u32) !StagingBuffer {
|
||||||
const transfer_queue_family = engine.transfer_queue.allocation.family;
|
const transfer_queue_family = engine.transfer_queue.allocation.family;
|
||||||
|
|
||||||
const single_queue_family = transfer_queue_family == destination_queue_family;
|
const qsm = QSM.resolve(destination_queue_family, transfer_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(&.{
|
const buffer = try engine.device.createBuffer(&.{
|
||||||
.size = data.len,
|
.size = data.len,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
.transfer_src_bit = true,
|
.transfer_src_bit = true,
|
||||||
},
|
},
|
||||||
.sharing_mode = if (single_queue_family) .exclusive else .concurrent,
|
.sharing_mode = qsm.sharing_mode,
|
||||||
.p_queue_family_indices = queue_family_indices.ptr,
|
.queue_family_index_count = qsm.queue_family_index_count,
|
||||||
}, null);
|
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||||
errdefer engine.device.destroyBuffer(buffer);
|
}, &engine.vk_allocator.interface);
|
||||||
|
errdefer engine.device.destroyBuffer(buffer, &engine.vk_allocator.interface);
|
||||||
|
|
||||||
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
const memory_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||||
const memory = try engine.allocate(
|
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 {
|
pub fn deinit(self: *StagingBuffer, engine: *Engine) void {
|
||||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
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;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const vk = @import("vulkan");
|
|||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
buffer: vk.Buffer,
|
buffer: vk.Buffer,
|
||||||
memory: vk.DeviceMemory,
|
memory: vk.DeviceMemory,
|
||||||
@@ -19,17 +20,21 @@ pub fn init(engine: *Engine, comptime PrefixType: type, comptime ElementType: ty
|
|||||||
const element_size = @sizeOf(ElementType);
|
const element_size = @sizeOf(ElementType);
|
||||||
|
|
||||||
const array_capacity_in_bytes = std.math.mul(usize, array_capacity, element_size) catch return error.OutOfMemory;
|
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(&.{
|
const buffer = try engine.device.createBuffer(&.{
|
||||||
.size = size,
|
.size = size,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
|
.transfer_src_bit = true,
|
||||||
.transfer_dst_bit = true,
|
.transfer_dst_bit = true,
|
||||||
.storage_buffer_bit = true,
|
.storage_buffer_bit = true,
|
||||||
},
|
},
|
||||||
.sharing_mode = .exclusive,
|
.sharing_mode = qsm.sharing_mode,
|
||||||
}, null);
|
.queue_family_index_count = qsm.queue_family_index_count,
|
||||||
errdefer engine.device.destroyBuffer(buffer);
|
.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_requirements = engine.device.getBufferMemoryRequirements(buffer);
|
||||||
const memory = try engine.allocate(memory_requirements, .{ .device_local_bit = true });
|
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 {
|
pub fn deinit(self: *StorageBuffer, engine: *Engine) void {
|
||||||
engine.device.freeMemory(self.memory, &engine.vk_allocator.interface);
|
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;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, prefix: PrefixType, elements: []const ElementType) !void {
|
pub fn enlarge(self: *StorageBuffer, comptime PrefixType: type, comptime ElementType: type, engine: *Engine, array_capacity: usize) !void {
|
||||||
std.debug.assert(elements.len <= self.array_capacity);
|
std.debug.assert(array_capacity > self.array_capacity);
|
||||||
std.debug.assert(@sizeOf(PrefixType) == self.prefix_size);
|
std.debug.assert(@sizeOf(PrefixType) == self.prefix_size);
|
||||||
std.debug.assert(@sizeOf(ElementType) == self.element_size);
|
std.debug.assert(@sizeOf(ElementType) == self.element_size);
|
||||||
std.debug.assert(std.mem.isAligned(self.array_offset, @alignOf(ElementType)));
|
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;
|
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);
|
const data = try engine.vk_allocator.allocator.alloc(u8, size);
|
||||||
defer engine.vk_allocator.allocator.free(data);
|
defer engine.vk_allocator.allocator.free(data);
|
||||||
|
|
||||||
@memcpy(data[0..@sizeOf(PrefixType)], std.mem.asBytes(&prefix));
|
@memcpy(data[0..@sizeOf(PrefixType)], std.mem.asBytes(&prefix));
|
||||||
@memcpy(data[self.array_offset..], std.mem.sliceAsBytes(elements));
|
@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);
|
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 vk = @import("vulkan");
|
||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
engine: *Engine,
|
engine: *Engine,
|
||||||
params: Params,
|
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 surface_capabilities = try self.engine.instance.getPhysicalDeviceSurfaceCapabilitiesKHR(self.engine.physical_device, mode.surface);
|
||||||
|
|
||||||
const graphics_queue_family = self.engine.graphics_queue.allocation.family;
|
const qsm = QSM.resolve(self.engine.graphics_queue.allocation.family, mode.presentation_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 new_swapchain = try self.engine.device.createSwapchainKHR(&.{
|
const new_swapchain = try self.engine.device.createSwapchainKHR(&.{
|
||||||
.surface = mode.surface,
|
.surface = mode.surface,
|
||||||
.min_image_count = self.params.image_count,
|
.min_image_count = self.params.image_count,
|
||||||
@@ -106,9 +102,9 @@ pub fn recreate(self: *Swapchain) !void {
|
|||||||
.image_extent = extent,
|
.image_extent = extent,
|
||||||
.image_array_layers = 1,
|
.image_array_layers = 1,
|
||||||
.image_usage = .{ .color_attachment_bit = true },
|
.image_usage = .{ .color_attachment_bit = true },
|
||||||
.image_sharing_mode = if (single_queue_family) .exclusive else .concurrent,
|
.image_sharing_mode = qsm.sharing_mode,
|
||||||
.queue_family_index_count = @intCast(queue_family_indices.len),
|
.queue_family_index_count = qsm.queue_family_index_count,
|
||||||
.p_queue_family_indices = queue_family_indices.ptr,
|
.p_queue_family_indices = qsm.p_queue_family_indices,
|
||||||
.pre_transform = surface_capabilities.current_transform,
|
.pre_transform = surface_capabilities.current_transform,
|
||||||
.composite_alpha = .{ .opaque_bit_khr = true },
|
.composite_alpha = .{ .opaque_bit_khr = true },
|
||||||
.present_mode = .fifo_khr,
|
.present_mode = .fifo_khr,
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ const std = @import("std");
|
|||||||
const vk = @import("vulkan");
|
const vk = @import("vulkan");
|
||||||
|
|
||||||
const Engine = @import("Engine.zig");
|
const Engine = @import("Engine.zig");
|
||||||
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
pub const Usage = enum {
|
pub const Usage = enum {
|
||||||
base_color,
|
base_color,
|
||||||
@@ -13,19 +15,19 @@ pub const Usage = enum {
|
|||||||
|
|
||||||
pub fn format(self: Usage) vk.Format {
|
pub fn format(self: Usage) vk.Format {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.base_color => .r8g8b8_srgb,
|
.base_color => .r8g8b8a8_srgb,
|
||||||
.normal => .r8g8b8_snorm,
|
.normal => .r8g8b8a8_snorm,
|
||||||
.occlusion_roughness_metallic => .r8g8b8_unorm,
|
.occlusion_roughness_metallic => .r8g8b8a8_unorm,
|
||||||
.emissive => .r16g16b16_sfloat,
|
.emissive => .r16g16b16a16_sfloat,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sampleCount(self: Usage) usize {
|
pub fn sampleCount(self: Usage) u32 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
.base_color => 3,
|
.base_color => 4,
|
||||||
.normal => 3,
|
.normal => 4,
|
||||||
.occlusion_roughness_metallic => 3,
|
.occlusion_roughness_metallic => 4,
|
||||||
.emissive => 3,
|
.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) {
|
return switch (self) {
|
||||||
inline else => |x| @sizeOf(SampleType(x)),
|
inline else => |x| @sizeOf(SampleType(x)),
|
||||||
};
|
};
|
||||||
@@ -48,7 +50,7 @@ pub const Usage = enum {
|
|||||||
return [self.sampleCount()]SampleType(self);
|
return [self.sampleCount()]SampleType(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texelSize(self: Usage) usize {
|
pub fn texelSize(self: Usage) u32 {
|
||||||
return switch (self) {
|
return switch (self) {
|
||||||
inline else => |x| @sizeOf(TexelType(x)),
|
inline else => |x| @sizeOf(TexelType(x)),
|
||||||
};
|
};
|
||||||
@@ -66,6 +68,7 @@ usage: Usage,
|
|||||||
pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
||||||
const format: vk.Format = usage.format();
|
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(&.{
|
const image = try engine.device.createImage(&.{
|
||||||
.image_type = .@"2d",
|
.image_type = .@"2d",
|
||||||
.format = format,
|
.format = format,
|
||||||
@@ -79,10 +82,12 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
|||||||
.samples = .{ .@"1_bit" = true },
|
.samples = .{ .@"1_bit" = true },
|
||||||
.tiling = .optimal,
|
.tiling = .optimal,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
.transfer_src_bit = true,
|
.transfer_dst_bit = true,
|
||||||
.sampled_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,
|
.initial_layout = .undefined,
|
||||||
}, &engine.vk_allocator.interface);
|
}, &engine.vk_allocator.interface);
|
||||||
errdefer engine.device.destroyImage(image, &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 },
|
.aspect_mask = .{ .color_bit = true },
|
||||||
.base_mip_level = 0,
|
.base_mip_level = 0,
|
||||||
.level_count = 1,
|
.level_count = 1,
|
||||||
.base_array_level = 0,
|
.base_array_layer = 0,
|
||||||
.layer_count = 1,
|
.layer_count = 1,
|
||||||
},
|
},
|
||||||
}, &engine.vk_allocator.interface);
|
}, &engine.vk_allocator.interface);
|
||||||
@@ -119,6 +124,7 @@ pub fn init(engine: *Engine, width: u32, height: u32, usage: Usage) !Texture {
|
|||||||
.memory = memory,
|
.memory = memory,
|
||||||
.width = width,
|
.width = width,
|
||||||
.height = height,
|
.height = height,
|
||||||
|
.usage = usage,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,10 +136,123 @@ pub fn deinit(self: *Texture, engine: *Engine) void {
|
|||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: Texture, comptime T: type, data: []const T) void {
|
pub fn write(self: Texture, comptime T: type, engine: *Engine, data: []const T) !void {
|
||||||
const bytes_per_texel = self.format.texelSize();
|
const bytes_per_texel = self.usage.texelSize();
|
||||||
const bytes_per_row = self.width * bytes_per_texel;
|
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);
|
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 Engine = @import("Engine.zig");
|
||||||
const StagingBuffer = @import("StagingBuffer.zig");
|
const StagingBuffer = @import("StagingBuffer.zig");
|
||||||
|
const QSM = @import("QueueSharingMode.zig");
|
||||||
|
|
||||||
buffer: vk.Buffer,
|
buffer: vk.Buffer,
|
||||||
memory: vk.DeviceMemory,
|
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 vertex_size = @sizeOf(VertexType);
|
||||||
const size = std.math.mul(usize, vertex_count, vertex_size) catch return error.OutOfMemory;
|
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(&.{
|
const buffer = try engine.device.createBuffer(&.{
|
||||||
.size = size,
|
.size = size,
|
||||||
.usage = .{
|
.usage = .{
|
||||||
.transfer_dst_bit = true,
|
.transfer_dst_bit = true,
|
||||||
.vertex_buffer_bit = true,
|
.vertex_buffer_bit = true,
|
||||||
},
|
},
|
||||||
.sharing_mode = .exclusive,
|
.sharing_mode = qsm.sharing_mode,
|
||||||
}, null);
|
.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);
|
errdefer engine.device.destroyBuffer(buffer);
|
||||||
|
|
||||||
const memory_requirements = engine.device.getBufferMemoryRequirements(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(vertices.len == self.vertex_count);
|
||||||
std.debug.assert(@sizeOf(VertexType) == self.vertex_size);
|
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);
|
const staging_buffer: StagingBuffer = .init(engine, std.mem.sliceAsBytes(vertices), engine.graphics_queue.allocation.family);
|
||||||
defer staging_buffer.deinit(engine);
|
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));
|
||||||
}
|
}
|
||||||
|
|||||||
111
src/skybox.zig
111
src/skybox.zig
@@ -1,111 +0,0 @@
|
|||||||
const shaders = @import("shaders");
|
|
||||||
const sokol = @import("sokol");
|
|
||||||
|
|
||||||
const sg = sokol.gfx;
|
|
||||||
|
|
||||||
const ap = @import("asset_pipeline.zig");
|
|
||||||
const game = @import("game.zig");
|
|
||||||
const main = @import("main.zig");
|
|
||||||
const math = @import("math.zig");
|
|
||||||
const samplers = @import("samplers.zig");
|
|
||||||
|
|
||||||
const cubemap_size = 512;
|
|
||||||
|
|
||||||
var skybox_equirectangular_texture: sg.Image = undefined;
|
|
||||||
var skybox_equirectangular_texture_view: sg.View = undefined;
|
|
||||||
|
|
||||||
var skybox_cubemap_texture: sg.Image = undefined;
|
|
||||||
var skybox_cubemap_texture_view: sg.View = undefined;
|
|
||||||
|
|
||||||
pub fn init() void {
|
|
||||||
var image = ap.visitSkybox(main.allocator) catch unreachable;
|
|
||||||
defer image.deinit(main.allocator);
|
|
||||||
|
|
||||||
skybox_equirectangular_texture = sg.makeImage(.{
|
|
||||||
.type = ._2D,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(image.width),
|
|
||||||
.height = @intCast(image.height),
|
|
||||||
.num_slices = @intCast(image.depth),
|
|
||||||
.pixel_format = .RGBA16F,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(image.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.label = "Skybox Equirectangular Texture",
|
|
||||||
});
|
|
||||||
skybox_equirectangular_texture_view = sg.makeView(.{
|
|
||||||
.texture = .{ .image = skybox_equirectangular_texture },
|
|
||||||
.label = "Skybox Equirectangular TV",
|
|
||||||
});
|
|
||||||
|
|
||||||
skybox_cubemap_texture = sg.makeImage(.{
|
|
||||||
.type = .CUBE,
|
|
||||||
.usage = .{
|
|
||||||
.immutable = true,
|
|
||||||
.storage_image = true,
|
|
||||||
},
|
|
||||||
.width = cubemap_size,
|
|
||||||
.height = cubemap_size,
|
|
||||||
.pixel_format = .RGBA16F,
|
|
||||||
.label = "Skybox Cubemap Texture",
|
|
||||||
});
|
|
||||||
skybox_cubemap_texture_view = sg.makeView(.{
|
|
||||||
.texture = .{ .image = skybox_cubemap_texture },
|
|
||||||
.label = "Skybox Cubemap TV",
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
|
||||||
sg.beginPass(.{ .compute = true });
|
|
||||||
defer sg.endPass();
|
|
||||||
|
|
||||||
const pipeline = sg.makePipeline(.{
|
|
||||||
.shader = sg.makeShader(shaders.equirectangularToCubemapShaderDesc(sg.queryBackend())),
|
|
||||||
.compute = true,
|
|
||||||
.label = "EquirectangularToCubemap Compute Pipeline",
|
|
||||||
});
|
|
||||||
defer sg.destroyPipeline(pipeline);
|
|
||||||
|
|
||||||
sg.applyPipeline(pipeline);
|
|
||||||
|
|
||||||
const sampler = samplers.getOrCreateSampler(.{
|
|
||||||
.wrap_u = .REPEAT,
|
|
||||||
.wrap_v = .REPEAT,
|
|
||||||
.wrap_w = .REPEAT,
|
|
||||||
.min_filter = .LINEAR,
|
|
||||||
.mag_filter = .LINEAR,
|
|
||||||
.mipmap_filter = .LINEAR,
|
|
||||||
}) catch unreachable;
|
|
||||||
|
|
||||||
var layer_index: i32 = 0;
|
|
||||||
while (layer_index < 6) : (layer_index += 1) {
|
|
||||||
const skybox_cubemap_image_storage_view = sg.makeView(.{
|
|
||||||
.storage_image = .{
|
|
||||||
.image = skybox_cubemap_texture,
|
|
||||||
.slice = layer_index,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
defer sg.destroyView(skybox_cubemap_image_storage_view);
|
|
||||||
|
|
||||||
var bindings: sg.Bindings = .{};
|
|
||||||
|
|
||||||
bindings.views[shaders.VIEW__EquirectangularTexture] = skybox_equirectangular_texture_view;
|
|
||||||
bindings.views[shaders.VIEW__CubemapImage] = skybox_cubemap_image_storage_view;
|
|
||||||
|
|
||||||
bindings.samplers[shaders.SMP__EquirectangularSampler] = sampler;
|
|
||||||
sg.applyBindings(bindings);
|
|
||||||
|
|
||||||
sg.applyUniforms(0, sg.asRange(&shaders.LayerIndex{
|
|
||||||
._LayerIndex = layer_index,
|
|
||||||
}));
|
|
||||||
|
|
||||||
sg.dispatch(@divExact(cubemap_size, 8), @divExact(cubemap_size, 8), 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit() void {
|
|
||||||
sg.destroyView(skybox_equirectangular_texture_view);
|
|
||||||
sg.destroyImage(skybox_equirectangular_texture);
|
|
||||||
}
|
|
||||||
195
src/tiles.zig
195
src/tiles.zig
@@ -1,195 +0,0 @@
|
|||||||
const shaders = @import("shaders");
|
|
||||||
const sokol = @import("sokol");
|
|
||||||
|
|
||||||
const sg = sokol.gfx;
|
|
||||||
|
|
||||||
const ap = @import("asset_pipeline.zig");
|
|
||||||
const game = @import("game.zig");
|
|
||||||
const main = @import("main.zig");
|
|
||||||
const math = @import("math.zig");
|
|
||||||
const samplers = @import("samplers.zig");
|
|
||||||
|
|
||||||
const Matrix4x4 = math.Matrix4x4;
|
|
||||||
const Quaternion = math.Quaternion;
|
|
||||||
const Vector3 = math.Vector3;
|
|
||||||
|
|
||||||
var vertex_buffer: sg.Buffer = undefined;
|
|
||||||
var index_buffer: sg.Buffer = undefined;
|
|
||||||
|
|
||||||
var pipeline: sg.Pipeline = undefined;
|
|
||||||
|
|
||||||
var base_color_texture: sg.Image = undefined;
|
|
||||||
var base_color_texture_view: sg.View = undefined;
|
|
||||||
|
|
||||||
var occlusion_roughness_metallic_texture: sg.Image = undefined;
|
|
||||||
var occlusion_roughness_metallic_texture_view: sg.View = undefined;
|
|
||||||
|
|
||||||
var normal_texture: sg.Image = undefined;
|
|
||||||
var normal_texture_view: sg.View = undefined;
|
|
||||||
|
|
||||||
var bindings: sg.Bindings = undefined;
|
|
||||||
|
|
||||||
pub fn init() void {
|
|
||||||
var textures = ap.visitTextures(main.allocator);
|
|
||||||
defer ap.deinitTextures(main.allocator, &textures);
|
|
||||||
|
|
||||||
const base_color_image = textures.getPtr("BaseColor").?;
|
|
||||||
const normal_image = textures.getPtr("Normal").?;
|
|
||||||
const occlusion_roughness_metallic_image = textures.getPtr("OcclusionRoughnessMetallic").?;
|
|
||||||
|
|
||||||
vertex_buffer = sg.makeBuffer(.{
|
|
||||||
.data = sg.asRange(&[_]f32{
|
|
||||||
// positionOS texCoord normalOS tangentOS
|
|
||||||
-0.5, -0.5, 0, 0, 1, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
0.5, -0.5, 0, 1, 1, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
-0.5, 0.5, 0, 0, 0, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
0.5, 0.5, 0, 1, 0, 0, 0, 1, 1, 0, 0, -1,
|
|
||||||
}),
|
|
||||||
.usage = .{
|
|
||||||
.immutable = true,
|
|
||||||
.vertex_buffer = true,
|
|
||||||
},
|
|
||||||
.label = "Tile Quad VB",
|
|
||||||
});
|
|
||||||
|
|
||||||
index_buffer = sg.makeBuffer(.{
|
|
||||||
.data = sg.asRange(&[_]u16{ 0, 1, 2, 2, 1, 3 }),
|
|
||||||
.usage = .{
|
|
||||||
.immutable = true,
|
|
||||||
.index_buffer = true,
|
|
||||||
},
|
|
||||||
.label = "Tile Quad IB",
|
|
||||||
});
|
|
||||||
|
|
||||||
pipeline = sg.makePipeline(.{
|
|
||||||
.shader = sg.makeShader(shaders.mainShaderDesc(sg.queryBackend())),
|
|
||||||
.layout = blk: {
|
|
||||||
var ret: sg.VertexLayoutState = .{};
|
|
||||||
ret.attrs[shaders.ATTR_main_positionOS].format = .FLOAT3;
|
|
||||||
ret.attrs[shaders.ATTR_main_texCoord].format = .FLOAT2;
|
|
||||||
ret.attrs[shaders.ATTR_main_normalOS].format = .FLOAT3;
|
|
||||||
ret.attrs[shaders.ATTR_main_tangentOS].format = .FLOAT4;
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.depth = .{
|
|
||||||
.compare = .GREATER,
|
|
||||||
},
|
|
||||||
.primitive_type = .TRIANGLES,
|
|
||||||
.index_type = .UINT16,
|
|
||||||
.cull_mode = .BACK,
|
|
||||||
.face_winding = .CCW,
|
|
||||||
.label = "Tile Pipeline",
|
|
||||||
});
|
|
||||||
|
|
||||||
const sampler = samplers.getOrCreateSampler(.{
|
|
||||||
.wrap_u = .REPEAT,
|
|
||||||
.wrap_v = .REPEAT,
|
|
||||||
.wrap_w = .REPEAT,
|
|
||||||
.min_filter = .LINEAR,
|
|
||||||
.mag_filter = .LINEAR,
|
|
||||||
.mipmap_filter = .LINEAR,
|
|
||||||
}) catch unreachable;
|
|
||||||
|
|
||||||
base_color_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(base_color_image.width),
|
|
||||||
.height = @intCast(base_color_image.height),
|
|
||||||
.num_slices = @intCast(base_color_image.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(base_color_image.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.label = "Tile BaseColor Texture",
|
|
||||||
});
|
|
||||||
base_color_texture_view = sg.makeView(.{
|
|
||||||
.texture = .{ .image = base_color_texture },
|
|
||||||
.label = "Tile BaseColor TV",
|
|
||||||
});
|
|
||||||
|
|
||||||
occlusion_roughness_metallic_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(occlusion_roughness_metallic_image.width),
|
|
||||||
.height = @intCast(occlusion_roughness_metallic_image.height),
|
|
||||||
.num_slices = @intCast(occlusion_roughness_metallic_image.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(occlusion_roughness_metallic_image.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.label = "Tile ORM Texture",
|
|
||||||
});
|
|
||||||
occlusion_roughness_metallic_texture_view = sg.makeView(.{
|
|
||||||
.texture = .{ .image = occlusion_roughness_metallic_texture },
|
|
||||||
.label = "Tile ORM TV",
|
|
||||||
});
|
|
||||||
|
|
||||||
normal_texture = sg.makeImage(.{
|
|
||||||
.type = .ARRAY,
|
|
||||||
.usage = .{ .immutable = true },
|
|
||||||
.width = @intCast(normal_image.width),
|
|
||||||
.height = @intCast(normal_image.height),
|
|
||||||
.num_slices = @intCast(normal_image.depth),
|
|
||||||
.pixel_format = .RGBA8,
|
|
||||||
.data = blk: {
|
|
||||||
var ret: sg.ImageData = .{};
|
|
||||||
ret.mip_levels[0] = sg.asRange(normal_image.data);
|
|
||||||
break :blk ret;
|
|
||||||
},
|
|
||||||
.label = "Tile Normal Texture",
|
|
||||||
});
|
|
||||||
normal_texture_view = sg.makeView(.{
|
|
||||||
.texture = .{ .image = normal_texture },
|
|
||||||
.label = "Tile Normal TV",
|
|
||||||
});
|
|
||||||
|
|
||||||
bindings = .{};
|
|
||||||
|
|
||||||
bindings.vertex_buffers[0] = vertex_buffer;
|
|
||||||
bindings.index_buffer = index_buffer;
|
|
||||||
|
|
||||||
bindings.views[shaders.VIEW_Point_Lights] = game.point_light_buffer_view;
|
|
||||||
bindings.views[shaders.VIEW_Directional_Lights] = game.directional_light_buffer_view;
|
|
||||||
bindings.views[shaders.VIEW__BaseColorTexture] = base_color_texture_view;
|
|
||||||
bindings.views[shaders.VIEW__OcclusionRoughnessMetallicTexture] = occlusion_roughness_metallic_texture_view;
|
|
||||||
bindings.views[shaders.VIEW__NormalTexture] = normal_texture_view;
|
|
||||||
|
|
||||||
bindings.samplers[shaders.SMP__Sampler] = sampler;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit() void {
|
|
||||||
sg.destroyView(normal_texture_view);
|
|
||||||
sg.destroyImage(normal_texture);
|
|
||||||
sg.destroyView(occlusion_roughness_metallic_texture_view);
|
|
||||||
sg.destroyImage(occlusion_roughness_metallic_texture);
|
|
||||||
sg.destroyView(base_color_texture_view);
|
|
||||||
sg.destroyImage(base_color_texture);
|
|
||||||
sg.destroyPipeline(pipeline);
|
|
||||||
sg.destroyBuffer(index_buffer);
|
|
||||||
sg.destroyBuffer(vertex_buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn bind() void {
|
|
||||||
sg.applyPipeline(pipeline);
|
|
||||||
sg.applyBindings(bindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn draw(translation: Vector3, rotation: Quaternion, texture_index: u32) void {
|
|
||||||
const matrix_os_to_ws = Matrix4x4.initTranslationRotationScale(translation, rotation, .one);
|
|
||||||
const matrix_os_to_ws_normal = Matrix4x4.inverseTransposeAffine(matrix_os_to_ws);
|
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Material_Uniforms, sg.asRange(&shaders.MaterialUniforms{
|
|
||||||
._TextureIndex = @intCast(texture_index),
|
|
||||||
}));
|
|
||||||
|
|
||||||
sg.applyUniforms(shaders.UB_Object_Uniforms, sg.asRange(&shaders.ObjectUniforms{
|
|
||||||
._MatrixOStoWS = matrix_os_to_ws.asArray(),
|
|
||||||
._MatrixOStoWSNormal = matrix_os_to_ws_normal.asArray(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
sg.draw(0, 6, 1);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user