topaz/rendering/vk/swapchain.c

160 lines
5.4 KiB
C

/* SPDX-License-Identifier:BSD-3-Clause */
#include "swapchain.h"
#include "../../core/log.h"
#include <stdlib.h>
#include <string.h>
#define RGFW_IMPORT
#include "../../rgfw.h"
static VkSurfaceFormatKHR select_surface_format(VkPhysicalDevice device, VkSurfaceKHR surface)
{
u32 format_count = 0;
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &format_count, NULL);
VkSurfaceFormatKHR *formats = malloc(sizeof(VkSurfaceFormatKHR) * format_count);
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface, &format_count, formats);
VkSurfaceFormatKHR selected = formats[0];
for (u32 i = 0; i < format_count; i++) {
if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
selected = formats[i];
break;
}
}
free(formats);
return selected;
}
static VkPresentModeKHR select_present_mode(VkPhysicalDevice device, VkSurfaceKHR surface)
{
u32 mode_count = 0;
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &mode_count, NULL);
VkPresentModeKHR *modes = malloc(sizeof(VkPresentModeKHR) * mode_count);
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface, &mode_count, modes);
VkPresentModeKHR selected = VK_PRESENT_MODE_FIFO_KHR;
for (u32 i = 0; i < mode_count; i++) {
if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {
selected = VK_PRESENT_MODE_MAILBOX_KHR;
break;
}
}
free(modes);
return selected;
}
static VkExtent2D select_extent(VkSurfaceCapabilitiesKHR *caps, RGFW_window *window)
{
if (caps->currentExtent.width != 0xFFFFFFFF) {
return caps->currentExtent;
}
i32 w, h;
RGFW_window_getSize(window, &w, &h);
VkExtent2D extent;
extent.width = (u32)w;
extent.height = (u32)h;
if (extent.width < caps->minImageExtent.width)
extent.width = caps->minImageExtent.width;
if (extent.width > caps->maxImageExtent.width)
extent.width = caps->maxImageExtent.width;
if (extent.height < caps->minImageExtent.height)
extent.height = caps->minImageExtent.height;
if (extent.height > caps->maxImageExtent.height)
extent.height = caps->maxImageExtent.height;
return extent;
}
void vk_swapchain_init(struct renderer_context *context)
{
VkSurfaceCapabilitiesKHR caps;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(context->physical_device, context->surface, &caps);
VkSurfaceFormatKHR format = select_surface_format(context->physical_device, context->surface);
VkPresentModeKHR present_mode = select_present_mode(context->physical_device, context->surface);
VkExtent2D extent = select_extent(&caps, context->window);
u32 image_count = caps.minImageCount + 1;
if (caps.maxImageCount > 0 && image_count > caps.maxImageCount) {
image_count = caps.maxImageCount;
}
VkSwapchainCreateInfoKHR create_info = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.surface = context->surface,
.minImageCount = image_count,
.imageFormat = format.format,
.imageColorSpace = format.colorSpace,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.preTransform = caps.currentTransform,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = present_mode,
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE
};
u32 queue_indices[] = { context->queue_indices.graphics, context->queue_indices.present };
if (context->queue_indices.graphics != context->queue_indices.present) {
create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
create_info.queueFamilyIndexCount = 2;
create_info.pQueueFamilyIndices = queue_indices;
} else {
create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
}
if (vkCreateSwapchainKHR(context->device, &create_info, NULL, &context->swapchain.handle) != VK_SUCCESS) {
fatal("Can't create swapchain.\n");
}
context->swapchain.format = format.format;
context->swapchain.extent = extent;
vkGetSwapchainImagesKHR(context->device, context->swapchain.handle, &context->swapchain.image_count, NULL);
context->swapchain.images = malloc(sizeof(VkImage) * context->swapchain.image_count);
vkGetSwapchainImagesKHR(context->device, context->swapchain.handle, &context->swapchain.image_count, context->swapchain.images);
context->swapchain.image_views = malloc(sizeof(VkImageView) * context->swapchain.image_count);
for (u32 i = 0; i < context->swapchain.image_count; i++) {
VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = context->swapchain.images[i],
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = context->swapchain.format,
.components.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.components.a = VK_COMPONENT_SWIZZLE_IDENTITY,
.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.subresourceRange.baseMipLevel = 0,
.subresourceRange.levelCount = 1,
.subresourceRange.baseArrayLayer = 0,
.subresourceRange.layerCount = 1
};
if (vkCreateImageView(context->device, &view_info, NULL, &context->swapchain.image_views[i]) != VK_SUCCESS) {
fatal("Can't create image view.\n");
}
}
log_info("Swapchain created.\n");
}
void vk_swapchain_deinit(struct renderer_context *context)
{
for (u32 i = 0; i < context->swapchain.image_count; i++) {
vkDestroyImageView(context->device, context->swapchain.image_views[i], NULL);
}
free(context->swapchain.image_views);
free(context->swapchain.images);
vkDestroySwapchainKHR(context->device, context->swapchain.handle, NULL);
}