const std = @import("std");

const vk = @import("vulkan");

const Context = @import("Context.zig");
const Instance = Context.Instance;
const Device = Context.Device;

pub const QueueFamilyIndices = struct {
    graphics_family: ?u32 = null,
    presentation_family: ?u32 = null,

    pub fn isValid(self: QueueFamilyIndices) bool {
        return self.graphics_family != null and self.presentation_family != null;
    }
};

pub fn getQueueFamilies(ctx: Context, pdev: vk.PhysicalDevice) !QueueFamilyIndices {
    var indices: QueueFamilyIndices = .{ .graphics_family = null };

    var queue_family_count: u32 = 0;
    ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, null);

    const queue_family_list = try ctx.allocator.alloc(vk.QueueFamilyProperties, queue_family_count);
    defer ctx.allocator.free(queue_family_list);

    ctx.instance.getPhysicalDeviceQueueFamilyProperties(pdev, &queue_family_count, queue_family_list.ptr);

    for (queue_family_list, 0..) |queue_family, i| {
        if (queue_family.queue_count > 0 and queue_family.queue_flags.graphics_bit) {
            indices.graphics_family = @intCast(i);
        }

        const presentation_support = try ctx.instance.getPhysicalDeviceSurfaceSupportKHR(pdev, @intCast(i), ctx.surface);
        if (queue_family.queue_count > 0 and presentation_support == vk.TRUE) {
            indices.presentation_family = @intCast(i);
        }

        if (indices.isValid()) {
            return indices;
        }
    }

    unreachable;
}

pub fn getDeviceQueues(ctx: Context) ![2]vk.Queue {
    const indices = try getQueueFamilies(ctx, ctx.physical_device);

    const graphics_queue = ctx.device.getDeviceQueue(indices.graphics_family.?, 0);
    const presentation_queue = ctx.device.getDeviceQueue(indices.presentation_family.?, 0);
    return .{ graphics_queue, presentation_queue };
}
