diff --git a/src/gfx.zig b/src/gfx.zig index 260368c..e0d132d 100644 --- a/src/gfx.zig +++ b/src/gfx.zig @@ -1,5 +1,12 @@ +const std = @import("std"); +const builtin = @import("builtin"); const vk = @import("vk"); +pub const use_debug_messenger = switch (builtin.mode) { + .Debug, .ReleaseSafe => true, + .ReleaseSmall, .ReleaseFast => false, +}; + pub const BaseDispatch = vk.BaseWrapper(.{ .createInstance = true, .getInstanceProcAddr = true, @@ -19,6 +26,8 @@ pub const InstanceDispatch = vk.InstanceWrapper(.{ .getPhysicalDeviceSurfaceSupportKHR = true, .getPhysicalDeviceMemoryProperties = true, .getDeviceProcAddr = true, + .createDebugUtilsMessengerEXT = use_debug_messenger, + .destroyDebugUtilsMessengerEXT = use_debug_messenger, }); pub const DeviceDispatch = vk.DeviceWrapper(.{ @@ -72,4 +81,52 @@ pub const DeviceDispatch = vk.DeviceWrapper(.{ .cmdCopyBuffer = true, .cmdBeginRenderingKHR = true, .cmdEndRenderingKHR = true, + .cmdPipelineBarrier = true, }); + +pub fn debug_callback( + msg_severity: vk.DebugUtilsMessageSeverityFlagsEXT, + msg_type: vk.DebugUtilsMessageTypeFlagsEXT, + p_data: ?*const vk.DebugUtilsMessengerCallbackDataEXT, + _: ?*anyopaque, +) callconv(vk.vulkan_call_conv) vk.Bool32 { + // ripped from std.log.defaultLog + + const data = p_data orelse return vk.FALSE; + const message = data.p_message orelse return vk.FALSE; + + const severity_prefix = if (msg_severity.verbose_bit_ext) + "verbose:" + else if (msg_severity.info_bit_ext) + "info:" + else if (msg_severity.warning_bit_ext) + "warning:" + else if (msg_severity.error_bit_ext) + "error:" + else + "?:"; + + const type_prefix = if (msg_type.general_bit_ext) + "" + else if (msg_type.validation_bit_ext) + "validation:" + else if (msg_type.performance_bit_ext) + "performance:" + else if (msg_type.device_address_binding_bit_ext) + "device_address_binding:" + else + "?:"; + + const stderr = std.io.getStdErr().writer(); + var bw = std.io.bufferedWriter(stderr); + const writer = bw.writer(); + + std.debug.getStderrMutex().lock(); + defer std.debug.getStderrMutex().unlock(); + nosuspend { + writer.print("vk-{s}{s} {s}\n", .{ severity_prefix, type_prefix, message }) catch return vk.FALSE; + bw.flush() catch return vk.FALSE; + } + + return vk.FALSE; +} diff --git a/src/main.zig b/src/main.zig index 2e20a4b..303939e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -2,7 +2,6 @@ const std = @import("std"); const vk = @import("vk"); const c = @import("c.zig"); const shaders = @import("shaders"); -// const GraphicsContext = @import("graphics_context.zig").GraphicsContext; const Swapchain = @import("swapchain.zig").Swapchain; const Context = @import("swapchain.zig").Context; const Allocator = std.mem.Allocator; @@ -53,12 +52,44 @@ const vertices = [_]Vertex{ const indices = [_]Index{ 4, 5, 6, 6, 5, 7 }; -const InstancePair = std.meta.Tuple(&.{ vk.Instance, gfx.InstanceDispatch }); +const InstancePair = std.meta.Tuple(&.{ vk.Instance, gfx.InstanceDispatch, vk.DebugUtilsMessengerEXT }); /// note: destroy with vki.destroyInstance(instance, null) fn create_instance(vkb: gfx.BaseDispatch) !InstancePair { + var exts = std.BoundedArray([*:0]const u8, 32){}; + var layers = std.BoundedArray([*:0]const u8, 32){}; + + if (gfx.use_debug_messenger) { + try exts.appendSlice(&.{ + vk.extension_info.ext_debug_utils.name, + }); + + try layers.appendSlice(&.{ + "VK_LAYER_KHRONOS_validation", + }); + } + var glfw_exts_count: u32 = 0; - const glfw_exts = c.glfwGetRequiredInstanceExtensions(&glfw_exts_count); + const glfw_exts: [*]const [*:0]const u8 = + @ptrCast(c.glfwGetRequiredInstanceExtensions(&glfw_exts_count)); + try exts.appendSlice(glfw_exts[0..glfw_exts_count]); + + const dumci: vk.DebugUtilsMessengerCreateInfoEXT = .{ + .message_severity = .{ + .error_bit_ext = true, + .info_bit_ext = true, + .verbose_bit_ext = true, + .warning_bit_ext = true, + }, + .message_type = .{ + .device_address_binding_bit_ext = true, + .general_bit_ext = false, + .performance_bit_ext = true, + .validation_bit_ext = true, + }, + .pfn_user_callback = &gfx.debug_callback, + .p_user_data = null, + }; const instance = try vkb.createInstance(&vk.InstanceCreateInfo{ .p_application_info = &vk.ApplicationInfo{ @@ -68,13 +99,23 @@ fn create_instance(vkb: gfx.BaseDispatch) !InstancePair { .engine_version = vk.makeApiVersion(0, 0, 0, 0), .api_version = vk.API_VERSION_1_3, }, - .enabled_extension_count = glfw_exts_count, - .pp_enabled_extension_names = @ptrCast(glfw_exts), + .enabled_extension_count = @intCast(exts.len), + .pp_enabled_extension_names = &exts.buffer, + .enabled_layer_count = @intCast(layers.len), + .pp_enabled_layer_names = &layers.buffer, + .p_next = if (gfx.use_debug_messenger) &dumci else null, }, null); - const vki = try gfx.InstanceDispatch.load(instance, vkb.dispatch.vkGetInstanceProcAddr); + errdefer vki.destroyInstance(instance, null); - return .{ instance, vki }; + const messenger: vk.DebugUtilsMessengerEXT = if (gfx.use_debug_messenger) + try vki.createDebugUtilsMessengerEXT(instance, &dumci, null) + else + .null_handle; + errdefer if (gfx.use_debug_messenger) + vki.destroyDebugUtilsMessengerEXT(instance, messenger, null); + + return .{ instance, vki, messenger }; } /// note: destroy with vki.destroySurfaceKHR(instance, surface, null) @@ -123,7 +164,7 @@ fn create_device( pdev_search: for (pdevs) |pdev| { const props = vki.getPhysicalDeviceProperties(pdev); - if (props.device_type != .discrete_gpu) continue :pdev_search; + // if (props.device_type != .discrete_gpu) continue :pdev_search; var format_count: u32 = undefined; _ = try vki.getPhysicalDeviceSurfaceFormatsKHR(pdev, surface, &format_count, null); @@ -192,6 +233,9 @@ fn create_device( .p_queue_create_infos = qci.ptr, .enabled_extension_count = @intCast(required_device_extensions.len), .pp_enabled_extension_names = required_device_extensions.ptr, + .p_next = &vk.PhysicalDeviceDynamicRenderingFeaturesKHR{ + .dynamic_rendering = vk.TRUE, + }, }, null); const vkd = try gfx.DeviceDispatch.load(dev, vki.dispatch.vkGetDeviceProcAddr); errdefer vkd.destroyDevice(dev, null); @@ -222,8 +266,10 @@ pub fn main() !void { const vkb = try gfx.BaseDispatch.load(c.glfwGetInstanceProcAddress); - const instance, const vki = try create_instance(vkb); + const instance, const vki, const messenger = try create_instance(vkb); defer vki.destroyInstance(instance, null); + defer if (gfx.use_debug_messenger) + vki.destroyDebugUtilsMessengerEXT(instance, messenger, null); const surface = try create_surface(instance, window); defer vki.destroySurfaceKHR(instance, surface, null); @@ -234,38 +280,6 @@ pub fn main() !void { const queue = vkd.getDeviceQueue(dev, family, 0); - // var swapchain: vk.SwapchainKHR = .null_handle; - // defer vkd.destroySwapchainKHR(dev, swapchain, null); - // - // swapchain = try vkd.createSwapchainKHR(dev, &.{ - // .surface = surface, - // .min_image_count = 3, // should compute - // .image_format = .r8g8b8a8_sint, // should compute - // // .image_format = .r8g8b8a8_sint, // should compute - // .image_color_space = .srgb_nonlinear_khr, // should compute - // .image_extent = extent, // should compute - // .image_array_layers = 1, - // .image_usage = .{ .color_attachment_bit = true, .transfer_dst_bit = true }, - // .image_sharing_mode = .exclusive, // since we only choose one queue family - // .pre_transform = .{ .identity_bit_khr = true }, // should compute - // .composite_alpha = .{ .opaque_bit_khr = true }, - // .present_mode = .mailbox_khr, // should compute - // .clipped = vk.TRUE, - // .old_swapchain = swapchain, - // }, null); - // - // _ = try vkd.queuePresentKHR(queue, &.{ - // .wait_semaphore_count = 0, - // .swapchain_count = 1, - // .p_swapchains = &[_]vk.SwapchainKHR{swapchain}, - // .p_image_indices = &[_]u32{0}, - // }); - // - // try vkd.deviceWaitIdle(dev); - // - // _ = pdev; - // extent = undefined; - const gc: Context = .{ .vki = vki, .vkd = vkd, @@ -485,13 +499,44 @@ fn createCommandBuffers( for (cmdbufs, swapchain.swap_images) |cmdbuf, image| { try gc.vkd.beginCommandBuffer(cmdbuf, &.{}); + const pre_render_barriers: []const vk.ImageMemoryBarrier = &.{ + vk.ImageMemoryBarrier{ + .src_access_mask = .{}, + .dst_access_mask = .{ .color_attachment_write_bit = true }, + .old_layout = .undefined, + .new_layout = .color_attachment_optimal, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = image.image, + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }, + }; + gc.vkd.cmdPipelineBarrier( + cmdbuf, + .{ .top_of_pipe_bit = true }, + .{ .color_attachment_output_bit = true }, + .{}, + 0, + null, + 0, + null, + @intCast(pre_render_barriers.len), + pre_render_barriers.ptr, + ); + gc.vkd.cmdSetViewport(cmdbuf, 0, 1, @ptrCast(&viewport)); gc.vkd.cmdSetScissor(cmdbuf, 0, 1, @ptrCast(&scissor)); const color_attachments = [_]vk.RenderingAttachmentInfoKHR{ .{ .image_view = image.view, - .image_layout = .present_src_khr, + .image_layout = .color_attachment_optimal, .resolve_mode = .{}, .resolve_image_view = .null_handle, .resolve_image_layout = .undefined, @@ -519,6 +564,37 @@ fn createCommandBuffers( gc.vkd.cmdEndRenderingKHR(cmdbuf); + const post_render_barriers: []const vk.ImageMemoryBarrier = &.{ + vk.ImageMemoryBarrier{ + .src_access_mask = .{ .color_attachment_write_bit = true }, + .dst_access_mask = .{}, + .old_layout = .color_attachment_optimal, + .new_layout = .present_src_khr, + .src_queue_family_index = 0, + .dst_queue_family_index = 0, + .image = image.image, + .subresource_range = .{ + .aspect_mask = .{ .color_bit = true }, + .base_mip_level = 0, + .level_count = 1, + .base_array_layer = 0, + .layer_count = 1, + }, + }, + }; + gc.vkd.cmdPipelineBarrier( + cmdbuf, + .{ .color_attachment_output_bit = true }, + .{ .bottom_of_pipe_bit = true }, + .{}, + 0, + null, + 0, + null, + @intCast(post_render_barriers.len), + post_render_barriers.ptr, + ); + try gc.vkd.endCommandBuffer(cmdbuf); }