diff --git a/assets/shaders/unlit.glsl b/assets/shaders/unlit.glsl index 4cf985a..ee3dd8d 100644 --- a/assets/shaders/unlit.glsl +++ b/assets/shaders/unlit.glsl @@ -4,6 +4,32 @@ #include "global.glsl" +layout(std430, buffer_reference, buffer_reference_align = 4) readonly buffer PositionBuffer +{ + vec3 positions[]; +}; + +struct OtherData +{ + vec3 normal; + vec3 tangent; + vec2 uv; +}; + +layout(std430, buffer_reference, buffer_reference_align = 4) readonly buffer OtherDataBuffer +{ + OtherData other_data[]; +}; + +layout(push_constant, std430) uniform constants +{ + mat4 local_to_world; + PositionBuffer positions; + OtherDataBuffer other_data; + uint color_texture; + uint color_sampler; +} PushConstants; + #if VERTEX_SHADER // QUAD @@ -20,10 +46,12 @@ vec2 positions[6] = vec2[]( layout(location = 0) out vec2 OutUV; void main() { - OutUV = positions[gl_VertexIndex] * 0.5 + 0.5; - OutUV.y = 1 - OutUV.y; + PositionBuffer positions_ptr = PushConstants.positions; + OtherDataBuffer other_data_ptr = PushConstants.other_data; - gl_Position = vec4(positions[gl_VertexIndex] + vec2(gl_InstanceIndex, 0), gl_InstanceIndex, 1.0) * Global.view.world_to_clip; + OutUV = other_data_ptr.other_data[gl_VertexIndex].uv; + + gl_Position = vec4(positions_ptr.positions[gl_VertexIndex], 1.0) * PushConstants.local_to_world * Global.view.world_to_clip; } #endif @@ -31,16 +59,10 @@ void main() { #if FRAGMENT_SHADER layout(location = 0) in vec2 InUV; - layout(location = 0) out vec4 FragColor; -layout(push_constant, std430) uniform constants { - uint color_texture; - uint color_sampler; -} PushConstants; - void main() { - FragColor = vec4(texture(sampler2D(global_textures2d[PushConstants.color_texture], global_samplers[PushConstants.color_sampler]), InUV).rgb, 1.0); + FragColor = vec4(1); // vec4(texture(sampler2D(global_textures2d[PushConstants.color_texture], global_samplers[PushConstants.color_sampler]), InUV).rgb, 1.0); } #endif diff --git a/src/AssetManager.zig b/src/AssetManager.zig index 5755299..e5629cc 100644 --- a/src/AssetManager.zig +++ b/src/AssetManager.zig @@ -182,7 +182,7 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *G .frame_arena = frame_arena, .exe_dir = exe_dir, .texture_heap = try BuddyAllocator.init(allocator, 64, 22), // 256MB - .vertex_heap = VertexBufferHeap.init(allocator) catch @panic("OOM"), + .vertex_heap = VertexBufferHeap.init(allocator, gc) catch @panic("OOM"), .gc = gc, .descriptorman = descriptorman, .frame_state = frame_state, @@ -283,6 +283,20 @@ pub fn resolveShaderProgram(self: *AssetManager, handle: Handle.ShaderProgram) L pub fn resolveMesh(self: *AssetManager, handle: Handle.Mesh) LoadedMesh { if (handle.id == 0) return NullMesh; + if (self.resolveLoadingAsset(handle.id)) |loading_mesh| { + const status = self.gc.device.getFenceStatus(loading_mesh.mesh.transfer_fence) catch @panic("getFenceStatus"); + + switch (status) { + .success => { + self.finishLoadingAsset(handle.id); + }, + .not_ready => { + return NullMesh; + }, + else => unreachable, + } + } + if (self.resolveAsset(handle.id)) |asset| { switch (asset.*) { .mesh => |mesh| { @@ -552,34 +566,10 @@ const NullShaderProgram = LoadedShaderProgram{ const NullMesh = LoadedMesh{ .aabb = .{}, - .heap_handle = .{}, - .positions = BufferSlice{ - .buffer = 0, - .offset = 0, - .stride = 0, - }, - .normals = BufferSlice{ - .buffer = 0, - .offset = 0, - .stride = 0, - }, - .tangents = BufferSlice{ - .buffer = 0, - .offset = 0, - .stride = 0, - }, - .uvs = BufferSlice{ - .buffer = 0, - .offset = 0, - .stride = 0, - }, - .indices = IndexSlice{ - .buffer = 0, - .offset = 0, - .count = 0, - .type = gl.UNSIGNED_SHORT, - .base_vertex = 0, - }, + .allocation = .{}, + .positions = 0, + .other_data = 0, + .indices_offset = 0, .material = .{}, }; @@ -609,67 +599,194 @@ fn loadMeshErr(self: *AssetManager, id: AssetId) !LoadedMesh { defer self.frame_arena.free(data.bytes); const mesh = formats.Mesh.fromBuffer(data.bytes); - const vertices_len = mesh.vertices.len; + const vertices_len = mesh.positions.len; const allocation = try self.vertex_heap.alloc(vertices_len, mesh.indices.len); + const positions_size = @sizeOf(formats.Vector3) * vertices_len; + const other_data_size = @sizeOf(formats.Mesh.VertexDataForBasePass) * vertices_len; + const indices_size = @sizeOf(formats.Index) * mesh.indices.len; - const vertex_offset = allocation.vertex.offset; + const data_size = positions_size + other_data_size + indices_size; - gl.namedBufferSubData(self.vertex_heap.vertices.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.vertices.ptr)); - checkGLError(); - gl.namedBufferSubData(self.vertex_heap.normals.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.normals.ptr)); - checkGLError(); - gl.namedBufferSubData(self.vertex_heap.tangents.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector3)), @intCast(vertices_len * @sizeOf(formats.Vector3)), @ptrCast(mesh.tangents.ptr)); - checkGLError(); - gl.namedBufferSubData(self.vertex_heap.uvs.buffer, @intCast(vertex_offset * @sizeOf(formats.Vector2)), @intCast(vertices_len * @sizeOf(formats.Vector2)), @ptrCast(mesh.uvs.ptr)); - checkGLError(); + const staging_buffer = try self.gc.device.createBuffer(&.{ + .usage = .{ .transfer_src_bit = true }, + .sharing_mode = .exclusive, + .size = data_size, + }, null); + errdefer self.gc.device.destroyBuffer(staging_buffer, null); - const index_offset = allocation.index.offset; - gl.namedBufferSubData(self.vertex_heap.indices.buffer, @intCast(index_offset * @sizeOf(formats.Index)), @intCast(mesh.indices.len * @sizeOf(formats.Index)), @ptrCast(mesh.indices.ptr)); + const staging_mem_reqs = self.gc.device.getBufferMemoryRequirements(staging_buffer); - const loaded_mesh = LoadedMesh{ + const staging_mem = try self.gc.device.allocateMemory(&.{ + .memory_type_index = self.gc.memory_config.cpu.type_index, + .allocation_size = staging_mem_reqs.size, + }, null); + errdefer self.gc.device.freeMemory(staging_mem, null); + + try self.gc.device.bindBufferMemory(staging_buffer, staging_mem, 0); + + const staging_bytes: []u8 = @as([*]u8, @ptrCast(try self.gc.device.mapMemory(staging_mem, 0, data_size, .{})))[0..data_size]; + const positions_offset = 0; + var size = positions_size; + const positions = std.mem.bytesAsSlice(formats.Vector3, staging_bytes[positions_offset .. positions_offset + size]); + + const other_data_offset = positions_offset + positions_size; + size = other_data_size; + const other_data = std.mem.bytesAsSlice(formats.Mesh.VertexDataForBasePass, staging_bytes[other_data_offset .. other_data_offset + size]); + + const indices_offset = other_data_offset + other_data_size; + size = indices_size; + const indices = std.mem.bytesAsSlice(formats.Index, staging_bytes[indices_offset .. indices_offset + size]); + + @memcpy(positions, mesh.positions); + @memcpy(other_data, mesh.other_data); + @memcpy(indices, mesh.indices); + + self.gc.device.unmapMemory(staging_mem); + + const cmds = try self.command_pool.allocateCommandBuffer(); + + try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); + + { + cmds.pipelineBarrier2(&.{ + .memory_barrier_count = 0, + .buffer_memory_barrier_count = 4, + .p_buffer_memory_barriers = &.{ + vk.BufferMemoryBarrier2{ + .buffer = staging_buffer, + .src_stage_mask = .{ .host_bit = true }, + .src_access_mask = .{ .host_write_bit = true }, + .dst_stage_mask = .{ .copy_bit = true }, + .dst_access_mask = .{ .transfer_read_bit = true }, + .offset = 0, + .size = data_size, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + }, + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{}, + .src_access_mask = .{}, + .dst_stage_mask = .{ .copy_bit = true }, + .dst_access_mask = .{ .transfer_write_bit = true }, + .offset = allocation.positions.offset, + .size = positions_size, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + }, + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{}, + .src_access_mask = .{}, + .dst_stage_mask = .{ .copy_bit = true }, + .dst_access_mask = .{ .transfer_write_bit = true }, + .offset = allocation.other_data.offset, + .size = other_data_size, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + }, + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{}, + .src_access_mask = .{}, + .dst_stage_mask = .{ .copy_bit = true }, + .dst_access_mask = .{ .transfer_write_bit = true }, + .offset = allocation.indices.offset, + .size = indices_size, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + }, + }, + }); + } + + cmds.copyBuffer(staging_buffer, self.vertex_heap.heap_buffer, 3, &.{ + vk.BufferCopy{ + .src_offset = positions_offset, + .dst_offset = allocation.positions.offset, + .size = positions_size, + }, + vk.BufferCopy{ + .src_offset = other_data_offset, + .dst_offset = allocation.other_data.offset, + .size = other_data_size, + }, + vk.BufferCopy{ + .src_offset = indices_offset, + .dst_offset = allocation.indices.offset, + .size = indices_size, + }, + }); + + cmds.pipelineBarrier2(&.{ + .buffer_memory_barrier_count = 3, + .p_buffer_memory_barriers = &.{ + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{ .copy_bit = true }, + .src_access_mask = .{ .transfer_write_bit = true }, + .dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true }, + .dst_access_mask = .{ .shader_storage_read_bit = true }, + .src_queue_family_index = self.queue.family, + .dst_queue_family_index = self.gc.queues.graphics.family, + .offset = allocation.positions.offset, + .size = positions_size, + }, + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{ .copy_bit = true }, + .src_access_mask = .{ .transfer_write_bit = true }, + .dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true }, + .dst_access_mask = .{ .shader_storage_read_bit = true }, + .src_queue_family_index = self.queue.family, + .dst_queue_family_index = self.gc.queues.graphics.family, + .offset = allocation.other_data.offset, + .size = other_data_size, + }, + vk.BufferMemoryBarrier2{ + .buffer = self.vertex_heap.heap_buffer, + .src_stage_mask = .{ .copy_bit = true }, + .src_access_mask = .{ .transfer_write_bit = true }, + .dst_stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true, .compute_shader_bit = true, .index_input_bit = true }, + .dst_access_mask = .{ .shader_storage_read_bit = true, .index_read_bit = true }, + .src_queue_family_index = self.queue.family, + .dst_queue_family_index = self.gc.queues.graphics.family, + .offset = allocation.indices.offset, + .size = indices_size, + }, + }, + }); + + try cmds.endCommandBuffer(); + + const copy_fence = try self.gc.device.createFence(&.{}, null); + + try self.queue.submit(&.{ .command_buffers = &.{cmds.handle} }, copy_fence); + + const loading_mesh = LoadingMesh{ .aabb = .{ .min = Vec3.new(mesh.aabb.min.x, mesh.aabb.min.y, mesh.aabb.min.z), .max = Vec3.new(mesh.aabb.max.x, mesh.aabb.max.y, mesh.aabb.max.z), }, - .heap_handle = allocation, .material = mesh.material, - .positions = .{ - .buffer = self.vertex_heap.vertices.buffer, - .offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)), - .stride = @sizeOf(formats.Vector3), - }, - .normals = .{ - .buffer = self.vertex_heap.normals.buffer, - .offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)), - .stride = @sizeOf(formats.Vector3), - }, - .tangents = .{ - .buffer = self.vertex_heap.tangents.buffer, - .offset = @intCast(vertex_offset * @sizeOf(formats.Vector3)), - .stride = @sizeOf(formats.Vector3), - }, - .uvs = .{ - .buffer = self.vertex_heap.uvs.buffer, - .offset = @intCast(vertex_offset * @sizeOf(formats.Vector2)), - .stride = @sizeOf(formats.Vector2), - }, - .indices = .{ - .buffer = self.vertex_heap.indices.buffer, - .offset = @intCast(index_offset * @sizeOf(formats.Index)), - .count = @intCast(mesh.indices.len), - .type = gl.UNSIGNED_INT, - .base_vertex = @intCast(vertex_offset), - }, + .vertex_count = @intCast(vertices_len), + .index_count = @intCast(mesh.indices.len), + .allocation = allocation, + .transfer_fence = copy_fence, + .staging_buf = staging_buffer, + .staging_memory = staging_mem, + .command_buffer = cmds.handle, }; { self.rw_lock.lock(); defer self.rw_lock.unlock(); - try self.loaded_assets.put(self.allocator, id, .{ .mesh = loaded_mesh }); + try self.loading_assets.put(self.allocator, id, .{ .mesh = loading_mesh }); try self.modified_times.put(self.allocator, id, data.modified); } - return loaded_mesh; + + return NullMesh; } fn loadTexture(self: *AssetManager, id: AssetId) LoadedTexture { @@ -770,6 +887,8 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture { offset += texture.data[mip].len; } + self.gc.device.unmapMemory(staging_mem); + const cmds = try self.command_pool.allocateCommandBuffer(); try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); @@ -881,56 +1000,6 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture { } return NullTexture; - - // return loaded_texture; - - // var name: gl.GLuint = 0; - // gl.createTextures(gl.TEXTURE_2D, 1, &name); - // if (name == 0) { - // return error.GLCreateTexture; - // } - // errdefer gl.deleteTextures(1, &name); - - // const gl_format: gl.GLenum = switch (texture.header.format) { - // .bc7 => gl.COMPRESSED_RGBA_BPTC_UNORM, - // .bc5 => gl.COMPRESSED_RG_RGTC2, - // .bc6 => gl.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, - // }; - - // gl.textureStorage2D( - // name, - // @intCast(texture.mipLevels()), - // gl_format, - // @intCast(texture.header.padded_width), - // @intCast(texture.header.padded_height), - // ); - // checkGLError(); - - // for (0..texture.mipLevels()) |mip_level| { - // const desc = texture.getMipDesc(mip_level); - // gl.compressedTextureSubImage2D( - // name, - // @intCast(mip_level), - // 0, - // 0, - // @intCast(desc.width), - // @intCast(desc.height), - // gl_format, - // @intCast(texture.data[mip_level].len), - // @ptrCast(texture.data[mip_level].ptr), - // ); - // checkGLError(); - // } - - // const uv_scale = Vec2.new( - // @as(f32, @floatFromInt(texture.header.width)) / @as(f32, @floatFromInt(texture.header.padded_width)), - // @as(f32, @floatFromInt(texture.header.height)) / @as(f32, @floatFromInt(texture.header.padded_height)), - // ); - - // const handle = gl.GL_ARB_bindless_texture.getTextureHandleARB(name); - // gl.GL_ARB_bindless_texture.makeTextureHandleResidentARB(handle); - // errdefer gl.GL_ARB_bindless_texture.makeTextureHandleNonResidentARB(handle); - } fn loadScene(self: *AssetManager, id: AssetId) LoadedScene { @@ -1002,6 +1071,32 @@ fn loadMaterialErr(self: *AssetManager, id: AssetId) !formats.Material { fn finishLoadingAsset(self: *AssetManager, id: AssetId) void { if (self.resolveLoadingAsset(id)) |loading_asset| { switch (loading_asset.*) { + .mesh => |loading_mesh| { + { + self.rw_lock.lock(); + defer self.rw_lock.unlock(); + + _ = self.loading_assets.remove(id); + + self.loaded_assets.put(self.allocator, id, LoadedAsset{ + .mesh = LoadedMesh{ + .aabb = loading_mesh.aabb, + .material = loading_mesh.material, + .vertex_count = loading_mesh.vertex_count, + .index_count = loading_mesh.index_count, + .allocation = loading_mesh.allocation, + .positions = self.vertex_heap.heap_address + loading_mesh.allocation.positions.offset, + .other_data = self.vertex_heap.heap_address + loading_mesh.allocation.other_data.offset, + .indices_offset = loading_mesh.allocation.indices.offset, + }, + }) catch @panic("OOM"); + } + + self.gc.device.freeCommandBuffers(self.command_pool.handle, 1, &.{loading_mesh.command_buffer}); + self.gc.device.destroyBuffer(loading_mesh.staging_buf, null); + self.gc.device.freeMemory(loading_mesh.staging_memory, null); + self.gc.device.destroyFence(loading_mesh.transfer_fence, null); + }, .texture => |loading_texture| { { self.rw_lock.lock(); @@ -1037,7 +1132,7 @@ const AssetType = enum { const LoadingAsset = union(AssetType) { shader: void, shaderProgram: void, - mesh: void, + mesh: LoadingMesh, texture: LoadingTexture, scene: void, material: void, @@ -1061,15 +1156,32 @@ const LoadedShaderProgram = struct { pipeline: vk.Pipeline, }; +pub const LoadingMesh = struct { + aabb: AABB, + material: formats.Material, + vertex_count: u32 = 0, + index_count: u32 = 0, + allocation: VertexBufferHeap.Alloc, + + transfer_fence: vk.Fence, + staging_buf: vk.Buffer, + staging_memory: vk.DeviceMemory, + command_buffer: vk.CommandBuffer, +}; + pub const LoadedMesh = struct { aabb: AABB, - heap_handle: VertexBufferHeap.Alloc, - positions: BufferSlice, - normals: BufferSlice, - tangents: BufferSlice, - uvs: BufferSlice, - indices: IndexSlice, + allocation: VertexBufferHeap.Alloc, material: formats.Material, + + vertex_count: u32 = 0, + index_count: u32 = 0, + + positions: u64, // Buffer Device Address + other_data: u64, + + // Offset from start of buffer + indices_offset: u32, }; const LoadingTexture = struct { @@ -1129,53 +1241,6 @@ pub const AABB = struct { } }; -pub const BufferSlice = struct { - buffer: gl.GLuint, - offset: gl.GLintptr, - stride: gl.GLsizei, - - pub fn bind(self: *const BufferSlice, index: gl.GLuint) void { - gl.bindVertexBuffer(index, self.buffer, 0, self.stride); - } -}; - -pub const IndexSlice = struct { - buffer: gl.GLuint, - offset: gl.GLuint, - count: gl.GLuint, - type: gl.GLenum, - base_vertex: gl.GLint, - - pub fn bind(self: *const IndexSlice) void { - gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.buffer); - } -}; - -pub const ShaderType = enum { - vertex, - fragment, - compute, - - pub fn goGLType(self: ShaderType) gl.GLenum { - return switch (self) { - .vertex => gl.VERTEX_SHADER, - .fragment => gl.FRAGMENT_SHADER, - .compute => gl.COMPUTE_SHADER, - }; - } - - const VERTEX_DEFINES = "#version 460 core\n#define VERTEX_SHADER 1\n#define VERTEX_EXPORT out\n"; - const FRAGMENT_DEFINES = "#version 460 core\n#define FRAGMENT_SHADER 1\n#define VERTEX_EXPORT in\n"; - const COMPUTE_DEFINES = "#version 460 core\n#define COMPUTE_SHADER 1\n"; - pub fn getDefines(self: ShaderType) []const u8 { - return switch (self) { - .vertex => VERTEX_DEFINES, - .fragment => FRAGMENT_DEFINES, - .compute => COMPUTE_DEFINES, - }; - } -}; - const AssetData = struct { bytes: []u8, modified: i128, @@ -1190,13 +1255,6 @@ fn loadFile(self: *AssetManager, allocator: std.mem.Allocator, path: []const u8, return .{ .bytes = bytes, .modified = meta.modified() }; } -fn loadShader(self: *AssetManager, id: AssetId, permuted_id: AssetId, defines: []const DefinePair) LoadedShader { - return self.loadShaderErr(id, permuted_id, defines) catch |err| { - std.log.err("Error: {} when loading shader id {} {s}", .{ err, id, asset_manifest.getPath(id) }); - return NullShader; - }; -} - const ShaderTokenizer = struct { const Self = @This(); @@ -1732,124 +1790,6 @@ test "ShaderTokenizer" { } } -fn loadShaderErr(self: *AssetManager, id: AssetId, permuted_id: AssetId, defines: []const DefinePair) !LoadedShader { - const path = asset_manifest.getPath(id); - const dir = std.fs.path.dirname(path) orelse @panic("No dir"); - - const data = try self.loadFile(self.frame_arena, path, SHADER_MAX_BYTES); - - var included_asset_ids = std.ArrayList(AssetId).init(self.frame_arena); - var preprocessed_segments = std.SegmentedList([]const u8, 64){}; - var final_len: usize = 0; - - // Just append defines here, no need to manually preprocess - for (defines) |define| { - const define_str = try std.fmt.allocPrint(self.frame_arena, "#define {s} {s}\n", .{ define.key, define.value }); - try preprocessed_segments.append(self.frame_arena, define_str); - final_len += define_str.len; - } - - // Preprocess - { - var tokenizer = ShaderTokenizer.init(data.bytes); - - var last_offset: usize = 0; - - var token = tokenizer.next(); - while (token.type != .End) : (token = tokenizer.next()) { - switch (token.type) { - .Directive => { - if (std.mem.eql(u8, token.text, "include")) { - // Append section of text up to this directive - try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..token.start]); - final_len += token.start - last_offset; - - const include_path = tokenizer.next(); - // Next section will start after this directive, this allows replacing #include with its content - last_offset = include_path.end; - - if (include_path.type != .String) { - return error.InvalidInclude; - } - - const included_file_path = try std.fs.path.resolve(self.frame_arena, &.{ dir, include_path.text }); - - const included_asset_id = assets.AssetPath.fromString(included_file_path).hash(); - if (included_asset_id != 0) { - const included_shader = self.resolveShaderWithDefines(.{ .id = included_asset_id }, defines); - try included_asset_ids.append(included_shader.permuted_id); - try preprocessed_segments.append(self.frame_arena, included_shader.source); - final_len += included_shader.source.len; - } - } - }, - else => {}, - } - } - - { - const remaining = data.bytes.len - last_offset; - if (remaining > 0) { - try preprocessed_segments.append(self.frame_arena, data.bytes[last_offset..data.bytes.len]); - final_len += remaining; - } - } - } - - var result_source = try self.allocator.alloc(u8, final_len); - - // Join source sections - { - var cursor: usize = 0; - var iter = preprocessed_segments.constIterator(0); - - while (iter.next()) |slice| { - @memcpy(result_source[cursor .. cursor + slice.len], slice.*); - cursor += slice.len; - } - } - - const loaded_shader = LoadedShader{ .source = result_source, .permuted_id = permuted_id }; - { - self.rw_lock.lock(); - defer self.rw_lock.unlock(); - - try self.loaded_assets.put(self.allocator, permuted_id, .{ .shader = loaded_shader }); - try self.modified_times.put(self.allocator, id, data.modified); - - try self.addDependencies(permuted_id, &.{id}); - try self.addDependencies(permuted_id, included_asset_ids.items); - } - - return loaded_shader; -} - -fn compileShader(self: *AssetManager, source: []const u8, shader_type: ShaderType) !gl.GLuint { - const shader = gl.createShader(shader_type.goGLType()); - errdefer gl.deleteShader(shader); - std.debug.assert(shader != 0); // should only happen if incorect shader type is passed - const defines = shader_type.getDefines(); - // Spirv - gl.shaderBinary(1, &shader, 0x9551, source.ptr, @intCast(source.len)); - gl.compileShader(shader); - var success: c_int = 0; - gl.getShaderiv(shader, gl.COMPILE_STATUS, &success); - if (success == 0) { - var info_len: gl.GLint = 0; - gl.getShaderiv(shader, gl.INFO_LOG_LENGTH, &info_len); - if (info_len > 0) { - const info_log = try self.frame_arena.allocSentinel(u8, @intCast(info_len - 1), 0); - gl.getShaderInfoLog(shader, @intCast(info_log.len), null, info_log); - std.log.err("ERROR::SHADER::COMPILATION_FAILED\n{s}\n{s}\n", .{ defines, info_log }); - } else { - std.log.err("ERROR::SHADER::COMPILIATION_FAILED\n{s}\nNo info log.\n", .{defines}); - } - return error.ShaderCompilationFailed; - } - - return shader; -} - fn addDependencies(self: *AssetManager, id: AssetId, dependencies: []const AssetId) !void { { const gop = try self.dependencies.getOrPut(self.allocator, id); @@ -1882,7 +1822,7 @@ fn freeAsset(self: *AssetManager, asset: *LoadedAsset) void { const destroy_queue = &self.frame_state.frame_data[self.frame_state.frame].destroy_queue; switch (asset.*) { .mesh => |*mesh| { - self.vertex_heap.free(mesh.heap_handle); + self.vertex_heap.free(mesh.allocation); }, .shader => |*shader| { self.allocator.free(shader.source); @@ -1922,122 +1862,84 @@ const VertexBufferHeap = struct { const Self = @This(); pub const Alloc = struct { - vertex: BuddyAllocator.Alloc = .{}, - index: BuddyAllocator.Alloc = .{}, + positions: BuddyAllocator.Alloc = .{}, + other_data: BuddyAllocator.Alloc = .{}, + indices: BuddyAllocator.Alloc = .{}, }; - pub const Buffer = struct { - buffer: gl.GLuint, - stride: gl.GLsizei, + gc: *GraphicsContext, + buddy: BuddyAllocator, + // Heap contains both vertex and index data, split manually in two + heap_memory: vk.DeviceMemory, + heap_buffer: vk.Buffer, + heap_address: vk.DeviceAddress, - pub fn init(name: gl.GLuint, stride: usize) Buffer { - return .{ - .buffer = name, - .stride = @intCast(stride), - }; + pub fn init(allocator: std.mem.Allocator, gc: *GraphicsContext) !Self { + const device = gc.device; + + var buddy = try BuddyAllocator.init(allocator, 64, 23); // 512MB + errdefer buddy.deinit(); + + const heap_buffer = try device.createBuffer(&vk.BufferCreateInfo{ + .size = buddy.getSize(), + .sharing_mode = .exclusive, + .usage = .{ .shader_device_address_bit = true, .storage_buffer_bit = true, .transfer_dst_bit = true, .index_buffer_bit = true }, + }, null); + errdefer device.destroyBuffer(heap_buffer, null); + const mem_reqs = device.getBufferMemoryRequirements(heap_buffer); + + const heap_memory = try device.allocateMemory(&vk.MemoryAllocateInfo{ + .p_next = &vk.MemoryAllocateFlagsInfo{ + .flags = .{ .device_address_bit = true }, + .device_mask = 0, + }, + .allocation_size = mem_reqs.size, + .memory_type_index = gc.memory_config.gpu.type_index, + }, null); + errdefer device.freeMemory(heap_memory, null); + + try device.bindBufferMemory(heap_buffer, heap_memory, 0); + + const heap_address = device.getBufferDeviceAddress(&vk.BufferDeviceAddressInfo{ + .buffer = heap_buffer, + }); + if (heap_address == 0) { + return error.InvalidBDA; } - pub fn bind(self: *const Buffer, index: gl.GLuint) void { - gl.bindVertexBuffer(index, self.buffer, 0, self.stride); - } - }; - - vertex_buddy: BuddyAllocator, - index_buddy: BuddyAllocator, - vertices: Buffer, - normals: Buffer, - tangents: Buffer, - uvs: Buffer, - indices: Buffer, - - pub fn init(allocator: std.mem.Allocator) !Self { - var vertex_buddy = try BuddyAllocator.init(allocator, 4096, 13); - errdefer vertex_buddy.deinit(); - - var index_buddy = try BuddyAllocator.init(allocator, 4096, 13); - errdefer index_buddy.deinit(); - - // const vertex_buf_size = vertex_buddy.getSize(); - // const index_buf_size = index_buddy.getSize(); - - const bufs = [_]gl.GLuint{ 0, 0, 0, 0, 0 }; - // gl.createBuffers(bufs.len, &bufs); - // errdefer gl.deleteBuffers(bufs.len, &bufs); - - // for (bufs) |buf| { - // if (buf == 0) { - // return error.BufferAllocationFailed; - // } - // } - - const vertices = Buffer.init(bufs[0], @sizeOf(formats.Vector3)); - const normals = Buffer.init(bufs[1], @sizeOf(formats.Vector3)); - const tangents = Buffer.init(bufs[2], @sizeOf(formats.Vector3)); - const uvs = Buffer.init(bufs[3], @sizeOf(formats.Vector2)); - const indices = Buffer.init(bufs[4], @sizeOf(formats.Index)); - - // gl.namedBufferStorage( - // vertices.buffer, - // @intCast(vertex_buf_size * @sizeOf(formats.Vector3)), - // null, - // gl.DYNAMIC_STORAGE_BIT, - // ); - // gl.namedBufferStorage( - // normals.buffer, - // @intCast(vertex_buf_size * @sizeOf(formats.Vector3)), - // null, - // gl.DYNAMIC_STORAGE_BIT, - // ); - // gl.namedBufferStorage( - // tangents.buffer, - // @intCast(vertex_buf_size * @sizeOf(formats.Vector3)), - // null, - // gl.DYNAMIC_STORAGE_BIT, - // ); - // gl.namedBufferStorage( - // uvs.buffer, - // @intCast(vertex_buf_size * @sizeOf(formats.Vector2)), - // null, - // gl.DYNAMIC_STORAGE_BIT, - // ); - // gl.namedBufferStorage( - // indices.buffer, - // @intCast(index_buf_size * @sizeOf(formats.Index)), - // null, - // gl.DYNAMIC_STORAGE_BIT, - // ); - return .{ - .vertex_buddy = vertex_buddy, - .index_buddy = index_buddy, - .vertices = vertices, - .normals = normals, - .tangents = tangents, - .uvs = uvs, - .indices = indices, + .gc = gc, + .buddy = buddy, + .heap_memory = heap_memory, + .heap_buffer = heap_buffer, + .heap_address = heap_address, }; } pub fn deinit(self: *Self) void { - self.index_buddy.deinit(); - self.vertex_buddy.deinit(); - - const bufs = [_]gl.GLuint{ self.vertices, self.normals, self.tangents, self.uvs, self.indices }; - gl.deleteBuffers(bufs.len, &bufs); + self.buddy.deinit(); } pub fn alloc(self: *Self, vertex_len: usize, index_len: usize) !Alloc { - const vertex_alloc = try self.vertex_buddy.alloc(vertex_len); - errdefer self.vertex_buddy.free(vertex_alloc); + const positions_alloc = try self.buddy.alloc(@sizeOf(formats.Vector3) * vertex_len); + errdefer self.buddy.free(positions_alloc); - const index_alloc = try self.index_buddy.alloc(index_len); - errdefer self.index_buddy.free(index_alloc); + const other_data_alloc = try self.buddy.alloc(@sizeOf(formats.Mesh.VertexDataForBasePass) * vertex_len); + errdefer self.buddy.free(other_data_alloc); - return Alloc{ .vertex = vertex_alloc, .index = index_alloc }; + const index_alloc = try self.buddy.alloc(index_len); + errdefer self.buddy.free(index_alloc); + + return Alloc{ + .positions = positions_alloc, + .other_data = other_data_alloc, + .indices = index_alloc, + }; } pub fn free(self: *Self, allocation: Alloc) void { - self.vertex_buddy.free(allocation.vertex); - self.index_buddy.free(allocation.index); + self.buddy.free(allocation.positions); + self.buddy.free(allocation.other_data); + self.buddy.free(allocation.indices); } }; diff --git a/src/Render.zig b/src/Render.zig index 4b62cdc..e57d683 100644 --- a/src/Render.zig +++ b/src/Render.zig @@ -1177,7 +1177,7 @@ pub fn finish(self: *Render) void { gl.bindVertexArray(self.z_prepass_vao); gl.depthFunc(gl.LESS); - self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value()); + self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value()); checkGLError(); self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value()); checkGLError(); @@ -1210,7 +1210,7 @@ pub fn finish(self: *Render) void { checkGLError(); self.assetman.vertex_heap.uvs.bind(Render.Attrib.UV.value()); checkGLError(); - self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value()); + self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value()); checkGLError(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer); checkGLError(); @@ -1439,7 +1439,7 @@ fn renderShadow(self: *Render, frustum: *const math.Frustum) void { _ = frustum; // autofix const zone = tracy.initZone(@src(), .{ .name = "Render.renderShadow" }); defer zone.deinit(); - self.assetman.vertex_heap.vertices.bind(Render.Attrib.Position.value()); + self.assetman.vertex_heap.vertex_data.bind(Render.Attrib.Position.value()); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.assetman.vertex_heap.indices.buffer); // TODO: this wastes space in temp allocator diff --git a/src/Render2.zig b/src/Render2.zig index 3995c7f..cb5a11a 100644 --- a/src/Render2.zig +++ b/src/Render2.zig @@ -8,6 +8,7 @@ const za = @import("zalgebra"); const Vec3 = za.Vec3; const Mat4 = za.Mat4; const common = @import("common.zig"); +const formats = @import("formats.zig"); const render_common = @import("render_common.zig"); const MAX_FRAME_LAG = render_common.MAX_FRAME_LAG; const DeferredDestroyQueue = render_common.DeferredDestroyQueue; @@ -44,6 +45,9 @@ command_pool: GraphicsContext.CommandPool, vulkan_frame_arena: VulkanPerFrameArena, camera: *Camera = &default_camera, +draw_commands: [4096]DrawCommand = undefined, +draw_command_count: u32 = 0, + // Global sampler to use for reading screen color in post processing screen_color_sampler: vk.Sampler = .null_handle, screen_color_sampler_descriptor_handle: DescriptorManager.DescriptorHandle = .{}, @@ -424,7 +428,18 @@ fn pushConstants(self: *Render2, cmds: GraphicsContext.CommandBuffer, stage_flag cmds.pushConstants(self.descriptorman.pipeline_layout, stage_flags, 0, @sizeOf(@TypeOf(value)), &value); } -pub fn draw(self: *Render2) !void { +pub const DrawCommand = struct { + mesh: AssetManager.Handle.Mesh, + material_override: ?formats.Material, + transform: Mat4, +}; + +pub fn draw(self: *Render2, cmd: DrawCommand) void { + self.draw_commands[self.draw_command_count] = cmd; + self.draw_command_count += 1; +} + +pub fn finish(self: *Render2) !void { const gc = self.gc; const device = gc.device; const frame = &self.frame_state.frame_data[self.frame_state.frame]; @@ -573,11 +588,6 @@ pub fn draw(self: *Render2) !void { cmds.bindPipeline(.graphics, unlit.pipeline); cmds.bindDescriptorSets(.graphics, self.descriptorman.pipeline_layout, 0, 1, &.{global_descriptor_set}, 0, null); - self.pushConstants(cmds, .{ .vertex_bit = true, .fragment_bit = true }, UnlitPushConstants{ - .color_texture = self.assetman.resolveTexture(a.Textures.bunny_tex1).descriptor_handle.index, - .color_sampler = self.screen_color_sampler_descriptor_handle.index, - }); - cmds.setViewportWithCount(1, &.{vk.Viewport{ .x = 0, .y = 0, @@ -591,7 +601,21 @@ pub fn draw(self: *Render2) !void { .extent = gc.swapchain_extent, }}); - cmds.draw(6, 2, 0, 0); + cmds.bindIndexBuffer(self.assetman.vertex_heap.heap_buffer, 0, vk.IndexType.uint32); + + for (self.draw_commands[0..self.draw_command_count]) |cmd| { + const mesh = self.assetman.resolveMesh(cmd.mesh); + + self.pushConstants(cmds, .{ .vertex_bit = true, .fragment_bit = true }, UnlitPushConstants{ + .local_to_world = cmd.transform, + .positions_address = mesh.positions, + .other_data_address = mesh.other_data, + .color_texture = self.assetman.resolveTexture(a.Textures.bunny_tex1).descriptor_handle.index, + .color_sampler = self.screen_color_sampler_descriptor_handle.index, + }); + + cmds.drawIndexed(mesh.index_count, 1, mesh.indices_offset, 0, 0); + } } // Post process and convert from f16 to rgba8_unorm @@ -668,6 +692,8 @@ pub fn draw(self: *Render2) !void { } try cmds.endCommandBuffer(); + self.draw_command_count = 0; + try gc.queues.graphics.submit( &GraphicsContext.SubmitInfo{ .wait_semaphores = &.{frame.acquire_swapchain_image}, @@ -716,6 +742,9 @@ const GlobalUniform = extern struct { }; const UnlitPushConstants = extern struct { + local_to_world: Mat4, + positions_address: u64, + other_data_address: u64, color_texture: u32, color_sampler: u32, }; diff --git a/src/formats.zig b/src/formats.zig index 229cb51..f15e83e 100644 --- a/src/formats.zig +++ b/src/formats.zig @@ -23,14 +23,19 @@ pub const AABB = extern struct { }; pub const Index = u32; +/// On gpu positions will go packed into one buffer normals, tangents and uvs will go to another +/// buffer. This is to allow a more efficient depth only pass that requires positions only. pub const Mesh = struct { + pub const VertexDataForBasePass = extern struct { + normal: Vector3, + tangent: Vector3, + uv: Vector2, + }; + aabb: AABB, material: Material, - - vertices: []align(1) Vector3, - normals: []align(1) Vector3, - tangents: []align(1) Vector3, - uvs: []align(1) Vector2, + positions: []align(1) Vector3, + other_data: []align(1) VertexDataForBasePass, indices: []align(1) Index, // This will panic if data is incorrect @@ -61,15 +66,11 @@ pub const Mesh = struct { offset += @sizeOf(usize); size = vert_len * @sizeOf(Vector3); - const vertices = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]); - offset += size; - const normals = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]); - offset += size; - const tangents = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]); + const positions = std.mem.bytesAsSlice(Vector3, buffer[offset .. offset + size]); offset += size; - size = vert_len * @sizeOf(Vector2); - const uvs = std.mem.bytesAsSlice(Vector2, buffer[offset .. offset + size]); + size = vert_len * @sizeOf(VertexDataForBasePass); + const other_data = std.mem.bytesAsSlice(VertexDataForBasePass, buffer[offset .. offset + size]); offset += size; size = ind_len * @sizeOf(Index); @@ -79,17 +80,15 @@ pub const Mesh = struct { return .{ .aabb = aabb, .material = material.*, - .vertices = vertices, - .normals = normals, - .tangents = tangents, - .uvs = uvs, + .positions = positions, + .other_data = other_data, .indices = indices, }; } }; pub fn writeMesh(writer: anytype, value: Mesh, endian: std.builtin.Endian) !void { - std.debug.assert(value.vertices.len == value.normals.len); + std.debug.assert(value.positions.len == value.other_data.len); // AABB { @@ -100,20 +99,16 @@ pub fn writeMesh(writer: anytype, value: Mesh, endian: std.builtin.Endian) !void try writer.writeStruct(value.material); // Sizes - try writer.writeInt(usize, value.vertices.len, endian); + try writer.writeInt(usize, value.positions.len, endian); try writer.writeInt(usize, value.indices.len, endian); - for (value.vertices) |v| { + for (value.positions) |v| { try writeVector3(writer, v, endian); } - for (value.normals) |n| { - try writeVector3(writer, n, endian); - } - for (value.tangents) |t| { - try writeVector3(writer, t, endian); - } - for (value.uvs) |uv| { - try writeVector2(writer, uv, endian); + for (value.other_data) |d| { + try writeVector3(writer, d.normal, endian); + try writeVector3(writer, d.tangent, endian); + try writeVector2(writer, d.uv, endian); } for (value.indices) |i| { try writer.writeInt(Index, i, endian); diff --git a/src/game.zig b/src/game.zig index bfe363d..f8e4848 100644 --- a/src/game.zig +++ b/src/game.zig @@ -79,6 +79,8 @@ fn game_init_window_err(global_allocator: std.mem.Allocator) !void { .height = globals.DEFAULT_HEIGHT, }; + // TODO: move this into game_init so that if game is recreated vulkan device is also recreated. + // This means all gpu resources will be destroyed together with the device. Seems like an easier way to handle this case try globals.g_init.gc.init(global_allocator, window); const version = &globals.g_init.syswm_info.version; @@ -234,62 +236,62 @@ export fn game_init(global_allocator: *std.mem.Allocator) void { // }); // Plane - // _ = globals.g_mem.world.addEntity(.{ - // .flags = .{ .mesh = true }, - // .transform = .{ .scale = Vec3.one().scale(10) }, - // .mesh = .{ - // .handle = a.Meshes.plane.Plane, - // .material = .{ - // .albedo = Vec4.one(), - // .normal_map = a.Textures.@"tile.norm", - // }, - // .override_material = true, - // }, - // }); + _ = globals.g_mem.world.addEntity(.{ + .flags = .{ .mesh = true }, + .transform = .{ .scale = Vec3.one().scale(10) }, + .mesh = .{ + .handle = a.Meshes.plane.Plane, + .material = .{ + .albedo = Vec4.one(), + .normal_map = a.Textures.@"tile.norm", + }, + .override_material = true, + }, + }); // 10 dielectric bunnies - // { - // for (0..100) |y| { - // for (0..1) |x| { - // _ = globals.g_mem.world.addEntity(.{ - // .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(x)) * 0.3 - 0.3 * 4.5, 0, @as(f32, @floatFromInt(y)) * 0.3 - 0.3 * 4.5) }, + { + for (0..100) |y| { + for (0..1) |x| { + _ = globals.g_mem.world.addEntity(.{ + .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(x)) * 0.3 - 0.3 * 4.5, 0, @as(f32, @floatFromInt(y)) * 0.3 - 0.3 * 4.5) }, - // .flags = .{ .mesh = true }, - // .mesh = .{ - // .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1, - // .material = .{ - // .albedo_map = a.Textures.bunny_tex1, - // // .normal_map = a.Textures.@"tile.norm", - // .roughness = @as(f32, @floatFromInt(y)) / 100.0, - // }, - // .override_material = true, - // }, - // }); - // } - // } - // } - // // 10 metallic bunnies - // { - // for (0..10) |i| { - // _ = globals.g_mem.world.addEntity(.{ - // .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) }, + .flags = .{ .mesh = true }, + .mesh = .{ + .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1, + .material = .{ + .albedo_map = a.Textures.bunny_tex1, + // .normal_map = a.Textures.@"tile.norm", + .roughness = @as(f32, @floatFromInt(y)) / 100.0, + }, + .override_material = true, + }, + }); + } + } + } + // 10 metallic bunnies + { + for (0..10) |i| { + _ = globals.g_mem.world.addEntity(.{ + .transform = .{ .pos = Vec3.new(@as(f32, @floatFromInt(i)) * 0.3 - 0.3 * 4.5, 0.3, 0) }, - // .flags = .{ .mesh = true }, - // .mesh = .{ - // .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1, - // .material = .{ - // .blend_mode = .AlphaBlend, - // .albedo = Vec4.new(1.000, 0.766, 0.336, 0.5), - // // .albedo_map = a.Textures.bunny_tex1, - // // .normal_map = a.Textures.@"tile.norm", - // .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0, - // .metallic = 1.0, - // }, - // .override_material = true, - // }, - // }); - // } - // } + .flags = .{ .mesh = true }, + .mesh = .{ + .handle = a.Meshes.bunny.BunnyStanfordUVUnwrapped_res1_bun_zipper_res1, + .material = .{ + .blend_mode = .AlphaBlend, + .albedo = Vec4.new(1.000, 0.766, 0.336, 0.5), + // .albedo_map = a.Textures.bunny_tex1, + // .normal_map = a.Textures.@"tile.norm", + .roughness = @as(f32, @floatFromInt(i + 1)) / 10.0, + .metallic = 1.0, + }, + .override_material = true, + }, + }); + } + } // const scene = globals.g_mem.world.createScene(globals.g_assetman.resolveScene(a.Scenes.bistro.scene)); // const ent = globals.g_mem.world.getEntity(scene) orelse @panic("WTF"); @@ -461,14 +463,11 @@ export fn game_update() bool { } } - gmem.render2.draw() catch @panic("RENDER ERROR"); - // Render - if (false) { + { const zone = tracy.initZone(@src(), .{ .name = "game.render()" }); defer zone.deinit(); - gmem.render.begin(); - defer gmem.render.finish(); + defer gmem.render2.finish() catch @panic("render.finish()"); // Collect point lights { @@ -478,46 +477,43 @@ export fn game_update() bool { if (ent.data.flags.mesh) { const mat_override: ?formats.Material = if (ent.data.mesh.override_material) ent.data.mesh.material else null; - gmem.render.draw(.{ + gmem.render2.draw(.{ .mesh = ent.data.mesh.handle, .material_override = mat_override, .transform = ent.globalMatrix(&gmem.world).*, }); } else if (ent.data.flags.point_light) { - gmem.render.draw(.{ + gmem.render2.draw(.{ .mesh = a.Meshes.sphere.Icosphere, .material_override = .{ .albedo = Vec4.new(0, 0, 0, 1), .emission = ent.data.light.premultipliedColor() }, .transform = ent.globalMatrix(&gmem.world).*, }); } - if (ent.data.flags.point_light) { - const pos = ent.globalMatrix(&gmem.world).extractTranslation(); - const color = ent.data.light.premultipliedColor(); + // if (ent.data.flags.point_light) { + // const pos = ent.globalMatrix(&gmem.world).extractTranslation(); + // const color = ent.data.light.premultipliedColor(); - gmem.render.drawLight(.{ - .point = .{ - .pos = pos, - .radius = ent.data.point_light.radius, - .color = color, - }, - }); - } - if (ent.data.flags.dir_light) { - const dir4 = ent.globalMatrix(&gmem.world).mulByVec4(Vec4.forward()); - const color = ent.data.light.premultipliedColor(); + // gmem.render.drawLight(.{ + // .point = .{ + // .pos = pos, + // .radius = ent.data.point_light.radius, + // .color = color, + // }, + // }); + // } + // if (ent.data.flags.dir_light) { + // const dir4 = ent.globalMatrix(&gmem.world).mulByVec4(Vec4.forward()); + // const color = ent.data.light.premultipliedColor(); - gmem.render.drawLight(.{ - .directional = .{ - .dir = dir4.toVec3(), - .color = color, - }, - }); - } + // gmem.render.drawLight(.{ + // .directional = .{ + // .dir = dir4.toVec3(), + // .color = color, + // }, + // }); + // } } - - // TODO: get rid of this - gmem.render.flushUBOs(); } } diff --git a/tools/asset_compiler.zig b/tools/asset_compiler.zig index 4cec663..7456052 100644 --- a/tools/asset_compiler.zig +++ b/tools/asset_compiler.zig @@ -32,6 +32,10 @@ const scene_formats = [_][]const u8{ ".glb", }; +pub fn float(int: anytype) f32 { + return @floatFromInt(int); +} + pub fn resolveAssetTypeByExtension(path: []const u8) ?AssetType { for (scene_formats) |ext| { if (std.mem.endsWith(u8, path, ext)) { @@ -498,30 +502,28 @@ fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, material_o if (mesh.mTextureCoords[0] == null) return error.MissingUVs; if (mesh.mNumUVComponents[0] != 2) return error.WrongUVComponents; - var vertices = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices)); - var normals = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices)); - var tangents = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices)); - var uvs = try allocator.alloc(Vector2, @intCast(mesh.mNumVertices)); + var positions = try allocator.alloc(Vector3, @intCast(mesh.mNumVertices)); + var other_data = try allocator.alloc(formats.Mesh.VertexDataForBasePass, @intCast(mesh.mNumVertices)); var indices = try allocator.alloc(formats.Index, @intCast(mesh.mNumFaces * 3)); // triangles for (0..mesh.mNumVertices) |i| { - vertices[i] = .{ + positions[i] = .{ .x = mesh.mVertices[i].x, .y = mesh.mVertices[i].y, .z = mesh.mVertices[i].z, }; - normals[i] = .{ + other_data[i].normal = .{ .x = mesh.mNormals[i].x, .y = mesh.mNormals[i].y, .z = mesh.mNormals[i].z, }; - tangents[i] = .{ + other_data[i].tangent = .{ .x = mesh.mTangents[i].x, .y = mesh.mTangents[i].y, .z = mesh.mTangents[i].z, }; - uvs[i] = .{ + other_data[i].uv = .{ .x = mesh.mTextureCoords[0][i].x, .y = mesh.mTextureCoords[0][i].y, }; @@ -554,10 +556,8 @@ fn processMesh(allocator: std.mem.Allocator, scene: *const c.aiScene, material_o .z = mesh.mAABB.mMax.z, }, }, - .vertices = vertices, - .normals = normals, - .tangents = tangents, - .uvs = uvs, + .positions = positions, + .other_data = other_data, .indices = indices, .material = material, }; @@ -593,7 +593,7 @@ fn processShader(allocator: std.mem.Allocator, flags: []const []const u8, input: const compile_result = try std.process.Child.run(.{ .allocator = allocator, .argv = try std.mem.concat(allocator, []const u8, &.{ - &.{ "glslc", "--target-env=vulkan1.3", "-std=460core", "-g", "-o", "-" }, + &.{ "glslc", "--target-env=vulkan1.3", "-std=460core", "-g", "-O0", "-o", "-" }, if (maybe_dep_file) |dep| &.{ "-MD", "-MF", dep } else &.{}, flags, &.{input}, @@ -821,7 +821,7 @@ fn processTexture(allocator: std.mem.Allocator, texture_type: TextureType, conte const mip_levels_to_gen = 1 + @as( u32, - @intFromFloat(@log2(@as(f32, @floatFromInt(@max(width, height))))), + @intFromFloat(@log2(float(@max(width, height)))), ); var actual_mip_count: usize = 1; @@ -972,10 +972,10 @@ fn premultiplyAlpha(img: []u8) void { for (0..img.len / 4) |i| { const pixel = img[i * 4 .. i * 4 + 4]; - const r = @as(f32, @floatFromInt(pixel[0])) / 255.0; - const g = @as(f32, @floatFromInt(pixel[1])) / 255.0; - const b = @as(f32, @floatFromInt(pixel[2])) / 255.0; - const a = @as(f32, @floatFromInt(pixel[3])) / 255.0; + const r = float(pixel[0]) / 255.0; + const g = float(pixel[1]) / 255.0; + const b = float(pixel[2]) / 255.0; + const a = float(pixel[3]) / 255.0; pixel[0] = @intFromFloat(r * a * 255.0); pixel[1] = @intFromFloat(g * a * 255.0); @@ -1040,8 +1040,8 @@ inline fn loadColorVec2(pixel: []const u8) @Vector(2, f32) { std.debug.assert(pixel.len >= 2); return @Vector(2, f32){ - @as(f32, @floatFromInt(pixel[0])), - @as(f32, @floatFromInt(pixel[1])), + float(pixel[0]), + float(pixel[1]), } / @as(@Vector(2, f32), @splat(255.0)); } @@ -1060,10 +1060,10 @@ inline fn loadColorVec4(pixel: []const u8) @Vector(4, f32) { std.debug.assert(pixel.len >= 4); return @Vector(4, f32){ - @as(f32, @floatFromInt(pixel[0])), - @as(f32, @floatFromInt(pixel[1])), - @as(f32, @floatFromInt(pixel[2])), - @as(f32, @floatFromInt(pixel[3])), + float(pixel[0]), + float(pixel[1]), + float(pixel[2]), + float(pixel[3]), } / @as(@Vector(4, f32), @splat(255.0)); }