From c1c81ee7614e76c56b05b016a19735a5fb65161d Mon Sep 17 00:00:00 2001 From: sergeypdev Date: Wed, 1 Jan 2025 22:04:44 +0400 Subject: [PATCH] Name vulkan objects for debugging, got first meshes to draw, spirv debug output for Aftermath --- build.zig | 17 +- build.zig.zon | 4 - libs/vma/vma.cpp | 4 - post_process.glsl.spirv | Bin 0 -> 5872 bytes src/AssetManager.zig | 30 ++- src/DescriptorManager.zig | 5 + src/GraphicsContext.zig | 58 +++--- src/Render2.zig | 321 +++++++++++++++++++------------- src/gen/asset_manifest.zig | 5 +- src/globals.zig | 2 +- src/render_common.zig | 14 +- tools/GenerateAssetManifest.zig | 2 +- tools/asset_compiler.zig | 32 ++-- 13 files changed, 275 insertions(+), 219 deletions(-) delete mode 100644 libs/vma/vma.cpp create mode 100644 post_process.glsl.spirv diff --git a/build.zig b/build.zig index f409019..535fc6e 100644 --- a/build.zig +++ b/build.zig @@ -41,24 +41,10 @@ pub fn build(b: *Build) void { const vk = buildVulkanWrapper(b, target, optimize); - const vma_dep = b.dependency("vma", .{}); - const vma = b.addStaticLibrary(.{ - .name = "vma", - .target = target, - .optimize = optimize, - }); - vma.linkLibC(); - vma.linkLibCpp(); - vma.addIncludePath(b.dependency("vulkan_headers", .{}).path("include")); - vma.addIncludePath(vma_dep.path("include")); - vma.installHeadersDirectory(vma_dep.path("include"), "", .{}); - vma.addCSourceFile(.{ - .file = b.path("libs/vma/vma.cpp"), - }); - const tracy = b.dependency("zig-tracy", .{ .target = target, .optimize = optimize, + .tracy_enable = false, }); const zalgebra_dep = b.dependency("zalgebra", .{}); @@ -102,7 +88,6 @@ pub fn build(b: *Build) void { l.root_module.addImport("tracy", tracy.module("tracy")); l.root_module.addImport("vk", vk); l.linkLibrary(tracy.artifact("tracy")); - l.linkLibrary(vma); } const install_lib = b.addInstallArtifact(lib, .{ .dest_dir = .{ .override = .prefix } }); diff --git a/build.zig.zon b/build.zig.zon index 1e73f1b..19628bd 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -43,10 +43,6 @@ .url = "https://github.com/sinnwrig/mach-dxcompiler/tarball/c3dfe92f3f04d4a3262dbc1a71f0016b9af92eb4", .hash = "12202f48e7cf06b1f2ecfd84f16effbd5bb9d644ea17e8a6144b4301a4dea198cf9c", }, - .vma = .{ - .url = "https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator/tarball/1c35ba99ce775f8342d87a83a3f0f696f99c2a39", - .hash = "1220521e256ea64cb942c37cfe08065073f2c71bfaa91d5c929fd382314c73ac0369", - }, .@"spirv-cross" = .{ .url = "https://github.com/hexops/spirv-cross/tarball/872bd405fece4bf6388abdea916356e26cb8fed9", .hash = "12207bebf82eef06f4f80a7e54c91e4402c0055d04167fdbcf1f350846a350266976", diff --git a/libs/vma/vma.cpp b/libs/vma/vma.cpp deleted file mode 100644 index c485935..0000000 --- a/libs/vma/vma.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#define VMA_IMPLEMENTATION -#define VMA_STATIC_VULKAN_FUNCTIONS 0 -#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1 -#include "vk_mem_alloc.h" diff --git a/post_process.glsl.spirv b/post_process.glsl.spirv new file mode 100644 index 0000000000000000000000000000000000000000..c8dc1b2926c3899a591176fd6eeb850ba0cad428 GIT binary patch literal 5872 zcmbVQ&2t<_6(3ucY_F3z;KXqfV%ipjU0a%+o&A*MueBtv9c0UvWyOgtCbPSCVFTR5w6h&LUeN1%qOoi(JzBGZmhIZU z)pYx+d_7>?#M-;X6L!*E`@z5lSjn2};+u16=qZ+mTL zdt*izTznpDM{Mj+AC6%6QWJf9M_dqwUKSVm7s){py*9FsbnhtuYjSh7-ng@LckTbH zO3(Y>i?Zh1Uf|lH(-s}Sza=)qa1dO|=exadbJ)~d{jL1krnBnU?wybBgKA2ITS!Qsucre0AkikhHRBsrC2VNYn03x zwPH!C6v~xKTE!^U%pxU)VzDNXTCrNKM!kW^R~BVhW5F9T_%eCi*xr!Q12`-P#4HMW z#VA$F=xD5Gm#aT^gS$>7frT24}Vl(1cr`_Vr%u?zMsqR?hrx} zSZu5dE<|jcTdJTw^})d1;WmZswOOq(+p+CO-ec3W_uYc+bHCu)TLTgH#bX}yjWOpf z%CgcC8YsF4q(Zz|DUq9vFU-L(*tBGS+a4}ee40u{+??@sjh&(MAqnI)H0*hy2wINk zzyxWraI+$Z4ok6579bMW@p;qU!y*gH6E-Uo?e;v!_SgCk(5~rJt82O_wvp*5Cl^G) z)aOiDIBC2CQ9(D#WmbC7f0o_9@tNpQLJQZJF!fR=7q<|sWX7eZmg}o!xDAkc!T@$z z_FS=0G-@4jO>Bd8N$lv@R;1fi#(H!l#`n)=AeFWTLuhM`S5}5;1RTPqrPnMDVLcB1ARQk%LJi6 zY~kh6bDqh210RW!c-HsbwiWiRmfIUJBFP;=XCE_Br4*53ckyY(0}s*TTsM38JbP?D z5YeHX5q|%fwPk-7*Hv{vwNSNbpPI*UuWulO7DuZYjwwU3+6 zTvQ%n2Ad8(Qsqde7;oZZcsI+3=Rpt2wETdFsRnt5_KlU5#`2QY8Vsx;+;JU?7m(G) zi?tQ@Mh^AlIb)pVTJtV%M~!&wx+jh0QnnzEdS-llVQLX~~@mdq6bdFm=Vp0UJ^N}#!qTbRfCSlUcV zK2Yh8GwZ|OMv*RlCmov7953{DW(R$KxYTbd@(~t9Vl;H0+Frqszs1N8ZNKY;vyL|s z!Jy}l@H&E@qiKF@qZhg6%hqTh7WTn80QaTn^T0V8xLsIx%5EWY)dSNMVkjQ-MIL__ z(g$lwpX4h#?US`t>#>Gs0UXq2{SuBXJHD5BJ5IpOf5ZpQO*n^eI?!y>sw0iJACm;Kwiv zz&qd^$4q(xAV6m@GbZxi#oyO3Q_lUQhoV1#@#6O~a6*$)>pZ28rKLGM*kAEjfd#-;mrr!q6!SzpLrmph$E(I8j?>*$>YnU1H z2bhV|M)d`GT$40=jYF*=fOAditNhdcefatiGyOB4Sra=G^&f(MkvX3DT?c(; zd;OY<=VQ>cp&n)AbDxg@jFsz9NBRE*c(D2BB(6_Eub%wN@0I*9=pWo!f1&(80Zkj~ zQKs}ZfdBp9NB^Mc?|?4-?PrN!3-nvp{+Rgr3^Z-1N13v-fiM5#7s>if(B{O?6S@U@ z>cx+f{kB2VhI*8#{o?7NG1kuj)H#NFv+ua(2|xw?!#C!adg zn7;ww-9bKect?B_K>j*(KE(Vj0DY5BJD&Slz(s(HF$-Le`5!}v=g9!jmi!g$mS>^> zAfLd&+#Lp7#c5$)C|7x5{WusGZA}1mUPJasmjM$1?wK;)Ey@pN%8w14L;0xzryuU+ z66Se86~H^@K6pHzmjTq{piki}hQ12}C| j4yZ$(ioFS(L-|+&P9KW^u0eVMp!8e7IsStvYJmR&7IaoB literal 0 HcmV?d00001 diff --git a/src/AssetManager.zig b/src/AssetManager.zig index e5629cc..1e32335 100644 --- a/src/AssetManager.zig +++ b/src/AssetManager.zig @@ -100,7 +100,7 @@ const AssetWatcher = struct { } pub fn startWatching(self: *AssetWatcher) void { - self.thread = sdl.SDL_CreateThread(watcherThread, "AssetManager Watcher", @ptrCast(self)) orelse { + self.thread = sdl.SDL_CreateThread(watcherThread, "AssetManager Watcher", @ptrCast(self), null, null) orelse { std.log.err("SDL Error: {s}\n", .{sdl.SDL_GetError()}); @panic("SDL_CreateThread"); }; @@ -190,6 +190,9 @@ pub fn init(allocator: std.mem.Allocator, frame_arena: std.mem.Allocator, gc: *G .command_pool = try queue.createCommandPool(.{ .transient_bit = true }), }; + NullMesh.positions = result.vertex_heap.heap_address; + NullMesh.other_data = result.vertex_heap.heap_address; + result.texture_heap_memory = try gc.device.allocateMemory(&.{ .allocation_size = result.texture_heap.getSize(), .memory_type_index = gc.memory_config.gpu.type_index, @@ -564,7 +567,7 @@ const NullShaderProgram = LoadedShaderProgram{ .pipeline = .null_handle, }; -const NullMesh = LoadedMesh{ +var NullMesh = LoadedMesh{ .aabb = .{}, .allocation = .{}, .positions = 0, @@ -643,7 +646,8 @@ fn loadMeshErr(self: *AssetManager, id: AssetId) !LoadedMesh { self.gc.device.unmapMemory(staging_mem); - const cmds = try self.command_pool.allocateCommandBuffer(); + const cmd_buf_name = try std.fmt.allocPrintZ(self.frame_arena, "MeshLoadCMDBuf ({s})", .{path}); + const cmds = try self.command_pool.allocateCommandBuffer(cmd_buf_name); try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); @@ -830,6 +834,11 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture { .initial_layout = .undefined, }, null); errdefer self.gc.device.destroyImage(image, null); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image, + .object_handle = @intFromEnum(image), + .p_object_name = @ptrCast(path.ptr), + }); const mem_reqs = self.gc.getImageMemoryRequirements(image); const allocation = try self.texture_heap.alloc(mem_reqs.size); @@ -853,6 +862,11 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture { .level_count = texture.header.mip_count, }, }, null); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image_view, + .object_handle = @intFromEnum(view), + .p_object_name = @ptrCast(path.ptr), + }); errdefer self.gc.device.destroyImageView(view, null); var data_size: u64 = 0; @@ -889,7 +903,8 @@ fn loadTextureErr(self: *AssetManager, id: AssetId) !LoadedTexture { self.gc.device.unmapMemory(staging_mem); - const cmds = try self.command_pool.allocateCommandBuffer(); + const cmd_buf_name = try std.fmt.allocPrintZ(self.frame_arena, "TextureLoadCMDBuf ({s})", .{path}); + const cmds = try self.command_pool.allocateCommandBuffer(cmd_buf_name); try cmds.beginCommandBuffer(&.{ .flags = .{ .one_time_submit_bit = true } }); @@ -1087,7 +1102,7 @@ fn finishLoadingAsset(self: *AssetManager, id: AssetId) void { .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, + .indices_offset = loading_mesh.allocation.indices.offset / @sizeOf(formats.Index), }, }) catch @panic("OOM"); } @@ -1885,6 +1900,11 @@ const VertexBufferHeap = struct { .sharing_mode = .exclusive, .usage = .{ .shader_device_address_bit = true, .storage_buffer_bit = true, .transfer_dst_bit = true, .index_buffer_bit = true }, }, null); + try device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .buffer, + .object_handle = @intFromEnum(heap_buffer), + .p_object_name = "VertexBufferHeap", + }); errdefer device.destroyBuffer(heap_buffer, null); const mem_reqs = device.getBufferMemoryRequirements(heap_buffer); diff --git a/src/DescriptorManager.zig b/src/DescriptorManager.zig index 5aa89e9..809557a 100644 --- a/src/DescriptorManager.zig +++ b/src/DescriptorManager.zig @@ -329,6 +329,11 @@ pub fn init(gc: *GraphicsContext, frame_allocator: std.mem.Allocator) !Descripto .p_set_layouts = &.{self.descriptor_set_layouts.global}, }, &descriptor_set_buf); self.global_descriptor_set = descriptor_set_buf[0]; + try gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .descriptor_set, + .object_handle = @intFromEnum(self.global_descriptor_set), + .p_object_name = "GlobalDescriptorSet", + }); return self; } diff --git a/src/GraphicsContext.zig b/src/GraphicsContext.zig index 9c501e8..f8edf7b 100644 --- a/src/GraphicsContext.zig +++ b/src/GraphicsContext.zig @@ -1,7 +1,6 @@ const std = @import("std"); const vk = @import("vk"); const c = @import("sdl.zig"); -const vma = @import("vma.zig"); pub const GraphicsContext = @This(); @@ -12,6 +11,7 @@ const apis: []const vk.ApiInfo = &.{ vk.features.version_1_3, vk.extensions.khr_surface, vk.extensions.khr_swapchain, + vk.extensions.ext_debug_utils, }; pub const Instance = vk.InstanceProxy(apis); @@ -22,13 +22,17 @@ const BaseDispatch = vk.BaseWrapper(apis); const InstanceDispatch = vk.InstanceWrapper(apis); const DeviceDispatch = Device.Wrapper; +const instance_extensions = [_][*:0]const u8{ + vk.extensions.ext_debug_utils.name, +}; const device_extensions = [_][:0]const u8{ vk.extensions.khr_swapchain.name, }; -const vk_layers = [_][:0]const u8{"VK_LAYER_KHRONOS_validation"}; +const vk_layers = [_][:0]const u8{ + // "VK_LAYER_KHRONOS_validation", +}; allocator: std.mem.Allocator = undefined, -vma_allocator: vma.Allocator = null, window: *c.SDL_Window = undefined, vkb: BaseDispatch = undefined, vki: InstanceDispatch = undefined, @@ -49,13 +53,20 @@ pub const CommandPool = struct { device: Device, handle: vk.CommandPool, - pub fn allocateCommandBuffer(self: *const CommandPool) !CommandBuffer { + pub fn allocateCommandBuffer(self: *const CommandPool, maybe_debug_name: ?[:0]const u8) !CommandBuffer { var cmd_bufs = [_]vk.CommandBuffer{.null_handle}; try self.device.allocateCommandBuffers(&.{ .command_pool = self.handle, .level = .primary, .command_buffer_count = cmd_bufs.len, }, &cmd_bufs); + if (maybe_debug_name) |debug_name| { + try self.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .command_buffer, + .object_handle = @intFromEnum(cmd_bufs[0]), + .p_object_name = debug_name, + }); + } return CommandBuffer.init(cmd_bufs[0], self.device.wrapper); } @@ -312,13 +323,14 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL return error.GetSDLExtensions; } - const sdl_instance_ext_names = try fba.allocator().alloc([*:0]const u8, sdl_instance_ext_count); - if (c.SDL_Vulkan_GetInstanceExtensions(window, &sdl_instance_ext_count, @ptrCast(sdl_instance_ext_names.ptr)) == c.SDL_FALSE) { + const instance_ext_names = try fba.allocator().alloc([*:0]const u8, sdl_instance_ext_count + instance_extensions.len); + if (c.SDL_Vulkan_GetInstanceExtensions(window, &sdl_instance_ext_count, @ptrCast(instance_ext_names.ptr)) == c.SDL_FALSE) { std.debug.print("SDL_Vulkan_GetInstanceExtensions: get names {s}\n", .{c.SDL_GetError()}); return error.GetSDLExtensions; } + @memcpy(instance_ext_names[sdl_instance_ext_count..], &instance_extensions); - std.debug.print("SDL Extensions: {s}\n", .{sdl_instance_ext_names}); + std.debug.print("Instance Extensions: {s}\n", .{instance_ext_names}); self.vkb = try BaseDispatch.load(vkGetInstanceProcAddr); @@ -330,8 +342,8 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL }, .pp_enabled_layer_names = @ptrCast((&vk_layers).ptr), .enabled_layer_count = @intCast(vk_layers.len), - .enabled_extension_count = @intCast(sdl_instance_ext_names.len), - .pp_enabled_extension_names = sdl_instance_ext_names.ptr, + .enabled_extension_count = @intCast(instance_ext_names.len), + .pp_enabled_extension_names = instance_ext_names.ptr, }, null); self.vki = try InstanceDispatch.load(instance_handle, vkGetInstanceProcAddr); @@ -415,21 +427,6 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL errdefer self.vkd.destroyDevice(device_handle, null); self.device = Device.init(device_handle, &self.vkd); - self.vma_allocator = vma.createAllocator(&.{ - .flags = .{ - .buffer_device_address_bit = true, - }, - .instance = instance_handle, - .physical_device = self.device_info.physical_device, - .device = device_handle, - .vulkanApiVersion = vk.API_VERSION_1_3, - .pVulkanFunctions = &vma.VulkanFunctions{ - .vkGetInstanceProcAddr = @ptrCast(vkGetInstanceProcAddr), - .vkGetDeviceProcAddr = @ptrCast(self.instance.wrapper.dispatch.vkGetDeviceProcAddr), - }, - }); - std.debug.assert(self.vma_allocator != null); - try self.maybeResizeSwapchain(); errdefer self.device.destroySwapchainKHR(self.swapchain, null); @@ -454,22 +451,14 @@ pub fn init(self: *GraphicsContext, allocator: std.mem.Allocator, window: *c.SDL self.pipeline_cache = try self.device.createPipelineCache(&.{}, null); } -pub fn createBuffer(self: *GraphicsContext, create_info: *const vk.BufferCreateInfo, allocation_create_info: *const vma.AllocationCreateInfo) !Buffer { - var result: Buffer = undefined; - result.gc = self; - result.handle = try vma.createBuffer(self.vma_allocator, create_info, allocation_create_info, &result.allocation, &result.allocation_info); - result.sync_state = .{}; - return result; -} - -pub fn acquireSwapchainImage(self: *GraphicsContext, acuire_semaphore: vk.Semaphore) !u32 { +pub fn acquireSwapchainImage(self: *GraphicsContext, acuire_semaphore: vk.Semaphore, acquire_fence: vk.Fence) !u32 { var found = false; var swapchain_img: u32 = 0; try self.maybeResizeSwapchain(); while (!found) { - const acquire_result = try self.device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), acuire_semaphore, .null_handle); + const acquire_result = try self.device.acquireNextImageKHR(self.swapchain, std.math.maxInt(u64), acuire_semaphore, acquire_fence); switch (acquire_result.result) { .success, .suboptimal_khr => { @@ -537,6 +526,7 @@ fn maybeResizeSwapchain(self: *GraphicsContext) !void { self.allocator.free(self.swapchain_images); self.swapchain_images = &.{}; } + self.swapchain_extent = new_extent; const surface_caps = self.device_info.surface_capabilities; self.swapchain = try self.device.createSwapchainKHR(&.{ diff --git a/src/Render2.zig b/src/Render2.zig index cb5a11a..2d81e56 100644 --- a/src/Render2.zig +++ b/src/Render2.zig @@ -6,6 +6,7 @@ const vk = @import("vk"); const a = @import("asset_manifest"); const za = @import("zalgebra"); const Vec3 = za.Vec3; +const Vec4 = za.Vec4; const Mat4 = za.Mat4; const common = @import("common.zig"); const formats = @import("formats.zig"); @@ -313,6 +314,11 @@ fn allocateRenderTarget(self: *Render2) !MainRenderTarget { .samples = .{ .@"1_bit" = true }, .initial_layout = .undefined, }, &color_img_address); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image, + .object_handle = @intFromEnum(color_image), + .p_object_name = "Main RT (Color)", + }); const color_image_view = try self.createPerFrameImageView(&vk.ImageViewCreateInfo{ .image = color_image, @@ -327,6 +333,11 @@ fn allocateRenderTarget(self: *Render2) !MainRenderTarget { .level_count = 1, }, }); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image_view, + .object_handle = @intFromEnum(color_image_view), + .p_object_name = "Main RT View (Color)", + }); const depth_image = try self.createPerFrameImage(&.{ .image_type = .@"2d", @@ -340,6 +351,11 @@ fn allocateRenderTarget(self: *Render2) !MainRenderTarget { .samples = .{ .@"1_bit" = true }, .initial_layout = .undefined, }, &depth_img_address); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image, + .object_handle = @intFromEnum(depth_image), + .p_object_name = "Main RT (Depth)", + }); const depth_image_view = try self.createPerFrameImageView(&vk.ImageViewCreateInfo{ .image = depth_image, .view_type = .@"2d", @@ -353,6 +369,11 @@ fn allocateRenderTarget(self: *Render2) !MainRenderTarget { .level_count = 1, }, }); + try self.gc.device.setDebugUtilsObjectNameEXT(&vk.DebugUtilsObjectNameInfoEXT{ + .object_type = .image_view, + .object_handle = @intFromEnum(depth_image_view), + .p_object_name = "Main RT View (Depth)", + }); return MainRenderTarget{ .color = GraphicsContext.Image{ @@ -439,6 +460,8 @@ pub fn draw(self: *Render2, cmd: DrawCommand) void { self.draw_command_count += 1; } +const debug_label_color: [4]f32 = .{ 0.15, 0.6, 0.15, 1 }; + pub fn finish(self: *Render2) !void { const gc = self.gc; const device = gc.device; @@ -446,7 +469,7 @@ pub fn finish(self: *Render2) !void { try frame.waitForDrawAndReset(self.gc.device, self.descriptorman); - const swapchain_image_index: u32 = try gc.acquireSwapchainImage(frame.acquire_swapchain_image); + const swapchain_image_index: u32 = try gc.acquireSwapchainImage(frame.acquire_swapchain_image, .null_handle); self.vulkan_frame_arena.startFrame(self.frame_state.frame); @@ -461,7 +484,7 @@ pub fn finish(self: *Render2) !void { const projection = self.camera.projection().mul(Mat4{ .data = .{ .{ 1, 0, 0, 0 }, - .{ 0, 1, 0, 0 }, + .{ 0, -1, 0, 0 }, .{ 0, 0, 1, 0 }, .{ 0, 0, 0, 1 }, }, @@ -483,144 +506,59 @@ pub fn finish(self: *Render2) !void { const depth_image: *GraphicsContext.Image = &main_render_target.depth; var swapchain_image = GraphicsContext.Image{ .handle = gc.swapchain_images[swapchain_image_index], .mip_count = 1, .layer_count = 1, .format = .r8g8b8a8_unorm }; + // NOTE: I don't think this is actually needed, but validation is screaming at me + swapchain_image.sync_state.sync_state.last_writer.stage_mask = .{ .color_attachment_output_bit = true }; const swapchain_image_view = try swapchain_image.createView(gc.device, .{ .color_bit = true }); defer gc.device.destroyImageView(swapchain_image_view, null); - const cmds = frame.command_buffer; + const global_descriptor_set = self.descriptorman.global_descriptor_set; - try cmds.beginCommandBuffer(&.{}); { - try global_uniform_buffer.sync(cmds, .{ .stage_mask = .{ .copy_bit = true }, .access_mask = .{ .transfer_write_bit = true } }); - cmds.updateBuffer(global_uniform_buffer.handle, 0, @sizeOf(GlobalUniform), &global_uniform); - try global_uniform_buffer.sync(cmds, .{ .stage_mask = .{ .vertex_shader_bit = true }, .access_mask = .{ .shader_read_bit = true } }); + const cmds = frame.draw_cmdbuf; + try cmds.beginCommandBuffer(&.{}); + defer cmds.endCommandBuffer() catch @panic("endCommandBuffer"); - const global_descriptor_set = self.descriptorman.global_descriptor_set; - - // TODO: move this into descriptorman - device.updateDescriptorSets(1, &.{ - vk.WriteDescriptorSet{ - .dst_set = global_descriptor_set, - .dst_binding = 0, - .dst_array_element = 0, - .descriptor_type = .uniform_buffer, - .descriptor_count = 1, - .p_buffer_info = &.{ - vk.DescriptorBufferInfo{ - .buffer = global_uniform_buffer.handle, - .offset = 0, - .range = @sizeOf(GlobalUniform), - }, - }, - .p_image_info = &[_]vk.DescriptorImageInfo{}, - .p_texel_buffer_view = &[_]vk.BufferView{}, - }, - }, 0, null); - - try self.descriptorman.commitDescriptorArrayUpdates(); - - try color_image.sync( - cmds, - .{ - .stage_mask = .{ .color_attachment_output_bit = true }, - .access_mask = .{ .color_attachment_write_bit = true }, - }, - .color_attachment_optimal, - .{ .color_bit = true }, - ); - try depth_image.sync( - cmds, - .{ - .stage_mask = .{ .early_fragment_tests_bit = true, .late_fragment_tests_bit = true }, - .access_mask = .{ - .depth_stencil_attachment_write_bit = true, - .depth_stencil_attachment_read_bit = true, - }, - }, - .depth_stencil_attachment_optimal, - .{ .depth_bit = true, .stencil_bit = true }, - ); - - // Actual draws + // Main Pass { - cmds.beginRendering(&vk.RenderingInfo{ - .render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = gc.swapchain_extent }, - .layer_count = 1, - .view_mask = 0, - .color_attachment_count = 1, - .p_color_attachments = &.{ - vk.RenderingAttachmentInfo{ - .clear_value = .{ .color = .{ .float_32 = .{ 0.9, 0.8, 0.7, 1.0 } } }, - .load_op = .clear, - .store_op = .store, - .image_layout = .color_attachment_optimal, - .image_view = color_image.view, - .resolve_image_layout = .color_attachment_optimal, - .resolve_mode = .{}, - }, - }, - .p_depth_attachment = &vk.RenderingAttachmentInfo{ - .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, - .load_op = .clear, - .store_op = .store, - .image_layout = .depth_stencil_attachment_optimal, - .image_view = depth_image.view, - .resolve_image_layout = .depth_stencil_attachment_optimal, - .resolve_mode = .{}, - }, - .p_stencil_attachment = &vk.RenderingAttachmentInfo{ - .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, - .load_op = .clear, - .store_op = .none, - .image_layout = .depth_stencil_attachment_optimal, - .image_view = depth_image.view, - .resolve_image_layout = .depth_stencil_attachment_optimal, - .resolve_mode = .{}, - }, + cmds.beginDebugUtilsLabelEXT(&vk.DebugUtilsLabelEXT{ + .color = debug_label_color, + .p_label_name = "Draw", }); - defer cmds.endRendering(); - - cmds.setDepthTestEnable(vk.TRUE); - cmds.setDepthWriteEnable(vk.TRUE); - cmds.setDepthCompareOp(.greater); - - const unlit = self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.unlit); - - cmds.bindPipeline(.graphics, unlit.pipeline); - cmds.bindDescriptorSets(.graphics, self.descriptorman.pipeline_layout, 0, 1, &.{global_descriptor_set}, 0, null); - - cmds.setViewportWithCount(1, &.{vk.Viewport{ - .x = 0, - .y = 0, - .width = @floatFromInt(gc.swapchain_extent.width), - .height = @floatFromInt(gc.swapchain_extent.height), - .min_depth = 0, - .max_depth = 1, - }}); - cmds.setScissorWithCount(1, &.{vk.Rect2D{ - .offset = .{ .x = 0, .y = 0 }, - .extent = gc.swapchain_extent, - }}); - - 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, + defer cmds.endDebugUtilsLabelEXT(); + { + cmds.beginDebugUtilsLabelEXT(&vk.DebugUtilsLabelEXT{ + .color = debug_label_color, + .p_label_name = "UpdateGlobalUniformBuffer", }); - - cmds.drawIndexed(mesh.index_count, 1, mesh.indices_offset, 0, 0); + defer cmds.endDebugUtilsLabelEXT(); + try global_uniform_buffer.sync(cmds, .{ .stage_mask = .{ .clear_bit = true, .copy_bit = true }, .access_mask = .{ .transfer_write_bit = true } }); + cmds.updateBuffer(global_uniform_buffer.handle, 0, @sizeOf(GlobalUniform), &global_uniform); + try global_uniform_buffer.sync(cmds, .{ .stage_mask = .{ .vertex_shader_bit = true, .fragment_shader_bit = true }, .access_mask = .{ .uniform_read_bit = true } }); } - } - // Post process and convert from f16 to rgba8_unorm - { - try swapchain_image.sync( + // TODO: move this into descriptorman + device.updateDescriptorSets(1, &.{ + vk.WriteDescriptorSet{ + .dst_set = global_descriptor_set, + .dst_binding = 0, + .dst_array_element = 0, + .descriptor_type = .uniform_buffer, + .descriptor_count = 1, + .p_buffer_info = &.{ + vk.DescriptorBufferInfo{ + .buffer = global_uniform_buffer.handle, + .offset = 0, + .range = @sizeOf(GlobalUniform), + }, + }, + .p_image_info = &[_]vk.DescriptorImageInfo{}, + .p_texel_buffer_view = &[_]vk.BufferView{}, + }, + }, 0, null); + + try self.descriptorman.commitDescriptorArrayUpdates(); + + try color_image.sync( cmds, .{ .stage_mask = .{ .color_attachment_output_bit = true }, @@ -629,6 +567,106 @@ pub fn finish(self: *Render2) !void { .color_attachment_optimal, .{ .color_bit = true }, ); + try depth_image.sync( + cmds, + .{ + .stage_mask = .{ .early_fragment_tests_bit = true, .late_fragment_tests_bit = true }, + .access_mask = .{ + .depth_stencil_attachment_write_bit = true, + .depth_stencil_attachment_read_bit = true, + }, + }, + .depth_stencil_attachment_optimal, + .{ .depth_bit = true, .stencil_bit = true }, + ); + + // Actual draws + { + cmds.beginDebugUtilsLabelEXT(&vk.DebugUtilsLabelEXT{ + .color = debug_label_color, + .p_label_name = "MainPass", + }); + defer cmds.endDebugUtilsLabelEXT(); + + cmds.beginRendering(&vk.RenderingInfo{ + .render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = gc.swapchain_extent }, + .layer_count = 1, + .view_mask = 0, + .color_attachment_count = 1, + .p_color_attachments = &.{ + vk.RenderingAttachmentInfo{ + .clear_value = .{ .color = .{ .float_32 = .{ 0.9, 0.8, 0.7, 1.0 } } }, + .load_op = .clear, + .store_op = .store, + .image_layout = .color_attachment_optimal, + .image_view = color_image.view, + .resolve_image_layout = .color_attachment_optimal, + .resolve_mode = .{}, + }, + }, + .p_depth_attachment = &vk.RenderingAttachmentInfo{ + .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, + .load_op = .clear, + .store_op = .store, + .image_layout = .depth_stencil_attachment_optimal, + .image_view = depth_image.view, + .resolve_image_layout = .depth_stencil_attachment_optimal, + .resolve_mode = .{}, + }, + .p_stencil_attachment = &vk.RenderingAttachmentInfo{ + .clear_value = .{ .depth_stencil = .{ .depth = 0.0, .stencil = 0 } }, + .load_op = .clear, + .store_op = .none, + .image_layout = .depth_stencil_attachment_optimal, + .image_view = depth_image.view, + .resolve_image_layout = .depth_stencil_attachment_optimal, + .resolve_mode = .{}, + }, + }); + defer cmds.endRendering(); + + cmds.setDepthTestEnable(vk.TRUE); + cmds.setDepthWriteEnable(vk.TRUE); + cmds.setDepthCompareOp(.greater); + + const unlit = self.assetman.resolveShaderProgram(a.ShaderPrograms.shaders.unlit); + + cmds.bindPipeline(.graphics, unlit.pipeline); + cmds.bindDescriptorSets(.graphics, self.descriptorman.pipeline_layout, 0, 1, &.{global_descriptor_set}, 0, null); + + cmds.setViewportWithCount(1, &.{vk.Viewport{ + .x = 0, + .y = 0, + .width = @floatFromInt(gc.swapchain_extent.width), + .height = @floatFromInt(gc.swapchain_extent.height), + .min_depth = 0, + .max_depth = 1, + }}); + cmds.setScissorWithCount(1, &.{vk.Rect2D{ + .offset = .{ .x = 0, .y = 0 }, + .extent = gc.swapchain_extent, + }}); + + 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 + { try color_image.sync( cmds, .{ @@ -638,6 +676,21 @@ pub fn finish(self: *Render2) !void { .shader_read_only_optimal, .{ .color_bit = true }, ); + cmds.beginDebugUtilsLabelEXT(&vk.DebugUtilsLabelEXT{ + .color = debug_label_color, + .p_label_name = "PostProcess", + }); + defer cmds.endDebugUtilsLabelEXT(); + + try swapchain_image.sync( + cmds, + .{ + .stage_mask = .{ .color_attachment_output_bit = true }, + .access_mask = .{ .color_attachment_write_bit = true }, + }, + .color_attachment_optimal, + .{ .color_bit = true }, + ); cmds.beginRendering(&.{ .render_area = vk.Rect2D{ .offset = .{ .x = 0, .y = 0 }, .extent = gc.swapchain_extent }, .layer_count = 1, @@ -690,19 +743,21 @@ pub fn finish(self: *Render2) !void { try swapchain_image.sync(cmds, .{ .stage_mask = .{}, .access_mask = .{} }, .present_src_khr, .{ .color_bit = true }); } - try cmds.endCommandBuffer(); self.draw_command_count = 0; try gc.queues.graphics.submit( &GraphicsContext.SubmitInfo{ .wait_semaphores = &.{frame.acquire_swapchain_image}, - .wait_dst_stage_mask = &.{vk.PipelineStageFlags{}}, - .command_buffers = &.{cmds.handle}, + .wait_dst_stage_mask = &.{ + vk.PipelineStageFlags{ .color_attachment_output_bit = true }, // Wait for swapchain acquire before rendering into it + }, + .command_buffers = &.{frame.draw_cmdbuf.handle}, .signal_semaphores = &.{frame.draw_sema}, }, - frame.draw_fence, + frame.end_draw_fence, ); + frame.draw_submitted = true; _ = try gc.device.queuePresentKHR(gc.queues.graphics.handle, &.{ diff --git a/src/gen/asset_manifest.zig b/src/gen/asset_manifest.zig index d847f32..6ee4dab 100644 --- a/src/gen/asset_manifest.zig +++ b/src/gen/asset_manifest.zig @@ -7,11 +7,12 @@ pub const ShaderPrograms = manifest.ShaderPrograms; pub const Textures = manifest.Textures; pub const Materials = manifest.Materials; +const empty: [:0]const u8 = ""; pub fn getPath(asset_id: u64) []const u8 { manifest.init(); - if (asset_id == 0) return ""; + if (asset_id == 0) return empty; - return manifest.asset_paths.get(asset_id) orelse ""; + return manifest.asset_paths.get(asset_id) orelse empty; } pub fn getAssetByPath(path: []const u8) u32 { diff --git a/src/globals.zig b/src/globals.zig index aedbdc5..0996ef9 100644 --- a/src/globals.zig +++ b/src/globals.zig @@ -71,7 +71,7 @@ pub const FreeLookCamera = struct { pub fn update(self: *FreeLookCamera, dt: f32, move: Vec3, look: Vec2) void { self.yaw += look.x(); - self.pitch -= look.y(); + self.pitch += look.y(); // First rotate pitch, then yaw const rot = Mat4.fromRotation(self.pitch, Vec3.right()).mul(Mat4.fromRotation(self.yaw, Vec3.up())); diff --git a/src/render_common.zig b/src/render_common.zig index 7bdef02..38305e0 100644 --- a/src/render_common.zig +++ b/src/render_common.zig @@ -104,11 +104,11 @@ pub const FrameData = struct { // Sync acquire_swapchain_image: vk.Semaphore, draw_sema: vk.Semaphore, - draw_fence: vk.Fence, + end_draw_fence: vk.Fence, draw_submitted: bool = true, destroy_queue: DeferredDestroyQueue, - command_buffer: GraphicsContext.CommandBuffer, + draw_cmdbuf: GraphicsContext.CommandBuffer, pub fn init(gc: *GraphicsContext, command_pool: GraphicsContext.CommandPool) !FrameData { const fence = try gc.device.createFence(&.{ .flags = .{ .signaled_bit = true } }, null); @@ -116,9 +116,9 @@ pub const FrameData = struct { return FrameData{ .acquire_swapchain_image = try gc.device.createSemaphore(&.{}, null), .draw_sema = try gc.device.createSemaphore(&.{}, null), - .draw_fence = fence, + .end_draw_fence = fence, - .command_buffer = try command_pool.allocateCommandBuffer(), + .draw_cmdbuf = try command_pool.allocateCommandBuffer("MainPass"), .destroy_queue = DeferredDestroyQueue.init(fence), }; } @@ -127,13 +127,13 @@ pub const FrameData = struct { if (!self.draw_submitted) return; self.draw_submitted = false; - _ = try device.waitForFences(1, &.{self.draw_fence}, vk.TRUE, std.math.maxInt(u64)); + _ = try device.waitForFences(1, &.{self.end_draw_fence}, vk.TRUE, std.math.maxInt(u64)); try self.destroy_queue.destroy(device, descriptorman); - try device.resetFences(1, &.{self.draw_fence}); + try device.resetFences(1, &.{self.end_draw_fence}); - try self.command_buffer.resetCommandBuffer(.{ .release_resources_bit = true }); + try self.draw_cmdbuf.resetCommandBuffer(.{ .release_resources_bit = true }); } }; diff --git a/tools/GenerateAssetManifest.zig b/tools/GenerateAssetManifest.zig index 22981e3..b378033 100644 --- a/tools/GenerateAssetManifest.zig +++ b/tools/GenerateAssetManifest.zig @@ -154,7 +154,7 @@ fn writeAssetManifest(arena: std.mem.Allocator, writer: anytype, assets: []Asset try writer.writeAll( \\var buf: [1024 * 1024]u8 = undefined; \\var fba = std.heap.FixedBufferAllocator.init(&buf); - \\pub var asset_paths = std.AutoHashMapUnmanaged(u64, []const u8){}; + \\pub var asset_paths = std.AutoHashMapUnmanaged(u64, [:0]const u8){}; \\var initialized = false; \\ \\// Fill map with data diff --git a/tools/asset_compiler.zig b/tools/asset_compiler.zig index 7456052..0d997df 100644 --- a/tools/asset_compiler.zig +++ b/tools/asset_compiler.zig @@ -59,7 +59,6 @@ const Args = struct { fn parseArgs(allocator: std.mem.Allocator) !Args { var args = try std.process.argsWithAllocator(allocator); - defer args.deinit(); var result: Args = .{}; @@ -138,7 +137,7 @@ pub fn main() !void { switch (asset_type) { .Scene => try processScene(allocator, rel_input, output_dir, asset_list_writer), - .ShaderProgram => try processShaderProgram(allocator, rel_input, output_dir, args.dep_file, asset_list_writer), + .ShaderProgram => try processShaderProgram(allocator, rel_input, rel_output, output_dir, args.dep_file, asset_list_writer), .Texture => try processTextureFromFile(allocator, rel_input, output_dir, asset_list_writer), else => unreachable, } @@ -585,22 +584,29 @@ fn readFileContents(allocator: std.mem.Allocator, path: []const u8) ![]u8 { // Returns spirv binary source // Caller owns memory -fn processShader(allocator: std.mem.Allocator, flags: []const []const u8, input: []const u8, maybe_dep_file: ?[]const u8) ![]u8 { - // const old_depfile_contents = if (maybe_dep_file) |dep| try readFileContents(allocator, dep) else try allocator.alloc(u8, 0); - // defer allocator.free(old_depfile_contents); +fn processShader(allocator: std.mem.Allocator, rel_output: []const u8, flags: []const []const u8, input: []const u8, stage: []const u8, maybe_dep_file: ?[]const u8) ![]u8 { + // const input_dir = std.fs.path.dirname(input).?; + const basename = std.fs.path.basename(input); + const basename_spirv = try std.mem.concat(allocator, u8, &.{ basename, ".", stage, ".spirv" }); + defer allocator.free(basename_spirv); + const out_spirv_path = try std.fs.path.join(allocator, &.{ rel_output, "assets", "shader_debug", basename_spirv }); + defer allocator.free(out_spirv_path); + + const dirpath = std.fs.path.dirname(out_spirv_path).?; + try std.fs.cwd().makePath(dirpath); // TODO: make sure output is stdout 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", "-O0", "-o", "-" }, + &.{ "glslc", "--target-env=vulkan1.3", "-std=460core", "-g", "-o", out_spirv_path }, if (maybe_dep_file) |dep| &.{ "-MD", "-MF", dep } else &.{}, flags, &.{input}, }), }); defer allocator.free(compile_result.stderr); - errdefer allocator.free(compile_result.stdout); + defer allocator.free(compile_result.stdout); switch (compile_result.term) { .Exited => |status| { @@ -614,10 +620,12 @@ fn processShader(allocator: std.mem.Allocator, flags: []const []const u8, input: }, } - return compile_result.stdout; + const spirv = try std.fs.cwd().readFileAlloc(allocator, out_spirv_path, 9999999999999); + + return spirv; } -fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_dir: std.fs.Dir, dep_file: ?[]const u8, asset_list_writer: anytype) !void { +fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, rel_output: []const u8, output_dir: std.fs.Dir, dep_file: ?[]const u8, asset_list_writer: anytype) !void { const input_dir = std.fs.path.dirname(input).?; // Recreate file in case it's not empty @@ -671,7 +679,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_ const shader_source_path = try std.fs.path.resolve(allocator, &.{ input_dir, stage }); const relative_path = try std.fs.path.relative(allocator, try std.fs.cwd().realpathAlloc(allocator, "."), shader_source_path); - const shader = try processShader(allocator, &.{ "-DVERTEX_SHADER=1", "-fshader-stage=vert", "-fpreserve-bindings" }, relative_path, dep_file); + const shader = try processShader(allocator, rel_output, &.{ "-DVERTEX_SHADER=1", "-fshader-stage=vert", "-fpreserve-bindings" }, relative_path, "vert", dep_file); result.graphics.vertex.source = @alignCast(shader); } { @@ -679,7 +687,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_ const shader_source_path = try std.fs.path.resolve(allocator, &.{ input_dir, stage }); const relative_path = try std.fs.path.relative(allocator, try std.fs.cwd().realpathAlloc(allocator, "."), shader_source_path); - const shader = try processShader(allocator, &.{ "-DFRAGMENT_SHADER=1", "-fshader-stage=frag", "-fpreserve-bindings" }, relative_path, dep_file); + const shader = try processShader(allocator, rel_output, &.{ "-DFRAGMENT_SHADER=1", "-fshader-stage=frag", "-fpreserve-bindings" }, relative_path, "frag", dep_file); result.graphics.fragment.source = @alignCast(shader); } } else if (program.value.compute != null) { @@ -689,7 +697,7 @@ fn processShaderProgram(allocator: std.mem.Allocator, input: []const u8, output_ const shader_source_path = try std.fs.path.resolve(allocator, &.{ input_dir, stage }); const relative_path = try std.fs.path.relative(allocator, try std.fs.cwd().realpathAlloc(allocator, "."), shader_source_path); - const shader = try processShader(allocator, &.{ "-DCOMPUTE_SHADER=1", "-fshader-stage=compute" }, relative_path, dep_file); + const shader = try processShader(allocator, rel_output, &.{ "-DCOMPUTE_SHADER=1", "-fshader-stage=compute" }, relative_path, "comp", dep_file); result.compute.compute.source = @alignCast(shader); } else { std.log.err("Provide vertex and fragment shaders for a graphics pipeline or a compute shader for a compute pipeline\n", .{});