NYXGFX/src/rhi/vulkan/resource/swapchain.zig

170 lines
5.5 KiB
Zig
Raw Normal View History

2026-08-11 21:06:28 +01:00
//! ----------------------------------------------------
//! `🗲` Vulkan Swapchain `🗲`
//! ----------------------------------------------------
const std = @import("std");
const gtl = @import("gtl");
const vk = @import("vulkan");
const Self = @This();
const Adapter = @import("adapter.zig");
const Device = @import("device.zig");
const Surface = @import("surface.zig");
/// ----------------------------------------------------
/// ----------------------------------------------------
pub const Config = struct {
width: u32,
height: u32,
};
//
// FIELDS
//
raw: *vk.VkSwapchainKHR_T,
images: []vk.VkImage,
image_views: []vk.VkImageView,
format: vk.VkFormat,
extent: vk.VkExtent2D,
device: *const Device,
alloc: std.mem.Allocator,
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn init(
adapter: *const Adapter,
device: *const Device,
surface: *const Surface,
config: Config,
alloc: std.mem.Allocator,
) !Self {
// --- # ---
var capabilities: vk.VkSurfaceCapabilitiesKHR = .{};
_ = vk.vkGetPhysicalDeviceSurfaceCapabilitiesKHR(adapter.raw, surface.raw, &capabilities);
// --- # ---
var format_count: u32 = 0;
_ = vk.vkGetPhysicalDeviceSurfaceFormatsKHR(adapter.raw, surface.raw, &format_count, null);
const formats = try alloc.alloc(vk.VkSurfaceFormatKHR, format_count);
defer alloc.free(formats);
_ = vk.vkGetPhysicalDeviceSurfaceFormatsKHR(adapter.raw, surface.raw, &format_count, formats.ptr);
// --- # ---
var present_mode_count: u32 = 0;
_ = vk.vkGetPhysicalDeviceSurfacePresentModesKHR(adapter.raw, surface.raw, &present_mode_count, null);
const present_modes = try alloc.alloc(vk.VkPresentModeKHR, present_mode_count);
defer alloc.free(present_modes);
_ = vk.vkGetPhysicalDeviceSurfacePresentModesKHR(adapter.raw, surface.raw, &present_mode_count, present_modes.ptr);
// --- # ---
const extent: vk.VkExtent2D = blk: {
if (capabilities.currentExtent.width != std.math.maxInt(u32)) break :blk capabilities.currentExtent;
break :blk .{ .width = config.width, .height = config.height };
};
// --- # ---
const format: vk.VkSurfaceFormatKHR = blk: {
for (formats) |v| {
if (v.format == vk.VK_FORMAT_B8G8R8A8_SRGB and v.colorSpace == vk.VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
break :blk v;
}
}
break :blk formats[0];
};
// --- # ---
var image_count: u32 = capabilities.minImageCount + 1;
if (capabilities.maxImageCount > 0 and image_count > capabilities.maxImageCount) {
image_count = capabilities.maxImageCount;
}
var create_info: vk.VkSwapchainCreateInfoKHR = .{
.sType = vk.VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = surface.raw,
.minImageCount = image_count,
.imageFormat = format.format,
.imageColorSpace = format.colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = vk.VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.preTransform = capabilities.currentTransform,
.compositeAlpha = vk.VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = present_modes[0],
.clipped = 1,
.imageSharingMode = vk.VK_SHARING_MODE_EXCLUSIVE,
.queueFamilyIndexCount = 0,
.pQueueFamilyIndices = null,
};
var swapchain: vk.VkSwapchainKHR = null;
if (vk.vkCreateSwapchainKHR(device.raw, &create_info, null, &swapchain) != vk.VK_SUCCESS) {
return error.FailedToCreateSwapchainKHR;
}
// --- GET IMAGES ---
_ = vk.vkGetSwapchainImagesKHR(device.raw, swapchain, &image_count, null);
const images = try alloc.alloc(vk.VkImage, image_count);
_ = vk.vkGetSwapchainImagesKHR(device.raw, swapchain, &image_count, images.ptr);
// --- GET IMAGE VIEWS ---
const image_views = try alloc.alloc(vk.VkImageView, images.len);
for (images, 0..) |image, i| {
var image_view_create_info: vk.VkImageViewCreateInfo = .{
.sType = vk.VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = image,
.viewType = vk.VK_IMAGE_VIEW_TYPE_2D,
.format = format.format,
.components = .{
.r = vk.VK_COMPONENT_SWIZZLE_IDENTITY,
.g = vk.VK_COMPONENT_SWIZZLE_IDENTITY,
.b = vk.VK_COMPONENT_SWIZZLE_IDENTITY,
.a = vk.VK_COMPONENT_SWIZZLE_IDENTITY,
},
.subresourceRange = .{
.aspectMask = vk.VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1,
},
};
if (vk.vkCreateImageView(device.raw, &image_view_create_info, null, &image_views[i]) != vk.VK_SUCCESS) {
return error.FailedToCreateImageView;
}
}
return .{
.raw = swapchain.?,
.images = images,
.image_views = image_views,
.extent = extent,
.format = format.format,
.device = device,
.alloc = alloc,
};
}
/// ----------------------------------------------------
/// ----------------------------------------------------
pub fn deinit(self: *Self) void {
for (self.image_views) |view| {
vk.vkDestroyImageView(self.device.raw, view, null);
}
vk.vkDestroySwapchainKHR(self.device.raw, self.raw, null);
self.alloc.free(self.images);
self.alloc.free(self.image_views);
}