//! ---------------------------------------------------- //! `🗲` Vulkan Device `🗲` //! ---------------------------------------------------- const std = @import("std"); const vk = @import("vulkan"); const Adapter = @import("adapter.zig"); const Surface = @import("surface.zig"); const Self = @This(); /// ---------------------------------------------------- /// ---------------------------------------------------- pub const QueueFamilies = struct { graphics: ?u32 = null, present: ?u32 = null, }; // // FIELDS // raw: *vk.VkDevice_T, graphics_queue: *vk.VkQueue_T, present_queue: *vk.VkQueue_T, graphics_command_pool: *vk.VkCommandPool_T, /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn init( adapter: *Adapter, surface: *Surface, alloc: std.mem.Allocator, ) !Self { // --- # --- const extensions: []const [*:0]const u8 = &.{ "VK_KHR_swapchain", }; // --- # --- var features13: vk.VkPhysicalDeviceVulkan13Features = .{ .sType = vk.VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES, .dynamicRendering = vk.VK_TRUE, }; // --- FIND QUEUE FAMILIES --- const queue_families = try findQueueFamilies(adapter.raw, surface.raw, alloc); if (queue_families.graphics == null or queue_families.present == null) { return error.FailedToFindSuitableQueueFamily; } // --- CREATE QUEUE INFOS --- const queue_priority: f32 = 1.0; var queue_create_infos: [2]vk.VkDeviceQueueCreateInfo = undefined; var queue_create_info_count: u32 = 0; queue_create_infos[0] = .{ .sType = vk.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = queue_families.graphics.?, .queueCount = 1, .pQueuePriorities = &queue_priority, }; queue_create_info_count += 1; if (queue_families.present.? != queue_families.graphics.?) { queue_create_infos[1] = .{ .sType = vk.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, .queueFamilyIndex = queue_families.present.?, .queueCount = 1, .pQueuePriorities = &queue_priority, }; queue_create_info_count += 1; } // --- DEVICE CREATE INFO --- var features: vk.VkPhysicalDeviceFeatures = .{}; var create_info: vk.VkDeviceCreateInfo = .{ .sType = vk.VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, .pQueueCreateInfos = &queue_create_infos, .queueCreateInfoCount = queue_create_info_count, .pEnabledFeatures = &features, .enabledExtensionCount = extensions.len, .ppEnabledExtensionNames = extensions.ptr, .pNext = &features13, }; // --- # --- var device: vk.VkDevice = null; if (vk.vkCreateDevice(adapter.raw, &create_info, null, &device) != vk.VK_SUCCESS) { return error.FailedToCreateVulkanDevice; } // --- # --- var pool_info: vk.VkCommandPoolCreateInfo = .{ .sType = vk.VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, .flags = vk.VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, .queueFamilyIndex = queue_families.graphics.?, }; var graphics_command_pool: vk.VkCommandPool = null; if (vk.vkCreateCommandPool(device, &pool_info, null, &graphics_command_pool) != vk.VK_SUCCESS) { return error.FailedToCreateCommandPool; } // --- GET QUEUES --- var graphics_queue: vk.VkQueue = null; vk.vkGetDeviceQueue(device, queue_families.graphics.?, 0, &graphics_queue); var present_queue: vk.VkQueue = null; vk.vkGetDeviceQueue(device, queue_families.present.?, 0, &present_queue); return .{ .raw = device.?, .graphics_queue = graphics_queue.?, .present_queue = present_queue.?, .graphics_command_pool = graphics_command_pool.?, }; } /// ---------------------------------------------------- /// ---------------------------------------------------- pub fn deinit(self: *Self) void { vk.vkDestroyCommandPool(self.raw, self.graphics_command_pool, null); vk.vkDestroyDevice(self.raw, null); } /// ---------------------------------------------------- /// ---------------------------------------------------- fn findQueueFamilies( adapter: vk.VkPhysicalDevice, surface: *vk.VkSurfaceKHR_T, alloc: std.mem.Allocator, ) !QueueFamilies { var indices: QueueFamilies = .{}; // --- GET FAMILY COUNT --- var queue_family_count: u32 = 0; vk.vkGetPhysicalDeviceQueueFamilyProperties(adapter, &queue_family_count, null); // --- CREATE BUFFER --- const queue_families = try alloc.alloc(vk.VkQueueFamilyProperties, queue_family_count); defer alloc.free(queue_families); vk.vkGetPhysicalDeviceQueueFamilyProperties(adapter, &queue_family_count, queue_families.ptr); // --- FIND SUPPORTED FAMILIES --- for (queue_families, 0..) |family, i| { var supported: vk.VkBool32 = vk.VK_FALSE; if (family.queueFlags & @as(vk.VkQueueFlags, @intCast(vk.VK_QUEUE_GRAPHICS_BIT)) != 0) { indices.graphics = @intCast(i); } _ = vk.vkGetPhysicalDeviceSurfaceSupportKHR( adapter, @intCast(i), surface, &supported, ); if (supported == vk.VK_TRUE) { indices.present = @intCast(i); } if (indices.graphics != null and indices.present != null) { break; } } return indices; }