feat: Create the swapchain
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m50s

This commit is contained in:
Kevin Trogant 2024-07-31 10:07:49 +02:00
parent e0904e84c4
commit 3a7bca385c
9 changed files with 242 additions and 14 deletions

View File

@ -1,12 +1,12 @@
#ifndef RT_RENCOM_RENDERER_API_H
#define RT_RENCOM_RENDERER_API_H
#include "runtime/runtime.h"
#include <runtime/runtime.h>
#include "renderer.h"
typedef struct rt_physical_resource_manager_i rt_physical_resource_manager_i;
typedef rt_physical_resource_manager_i *rt_render_device_get_physical_resource_manager_fn(void *o);
typedef rt_physical_resource_manager_i rt_render_device_get_physical_resource_manager_fn(void *o);
/* Interface for the render device.
* The device is responsible for executing command lists. */

View File

@ -5,6 +5,7 @@
#include <runtime/runtime.h>
#include <runtime/config.h>
#include <runtime/timing.h>
#include "device.h"
@ -439,6 +440,7 @@ static rt_result CreateDevice(rt_vk_device *dev) {
queue_info[0].queueCount = 1;
queue_info[0].queueFamilyIndex = queue_indices.graphics;
queue_info[0].pQueuePriorities = &priority;
dev->unique_families[0] = queue_indices.graphics;
if (queue_indices.compute != queue_indices.graphics) {
queue_info[1].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[1].pNext = NULL;
@ -446,6 +448,7 @@ static rt_result CreateDevice(rt_vk_device *dev) {
queue_info[1].queueCount = 1;
queue_info[1].queueFamilyIndex = queue_indices.compute;
queue_info[1].pQueuePriorities = &priority;
dev->unique_families[distinct_queue_count] = queue_indices.compute;
++distinct_queue_count;
}
if (queue_indices.present != queue_indices.graphics &&
@ -456,18 +459,23 @@ static rt_result CreateDevice(rt_vk_device *dev) {
queue_info[distinct_queue_count].queueCount = 1;
queue_info[distinct_queue_count].queueFamilyIndex = queue_indices.present;
queue_info[distinct_queue_count].pQueuePriorities = &priority;
dev->unique_families[distinct_queue_count] = queue_indices.present;
++distinct_queue_count;
}
if (queue_indices.transfer != queue_indices.graphics &&
queue_indices.transfer != queue_indices.compute) {
queue_indices.transfer != queue_indices.compute &&
queue_indices.transfer != queue_indices.present) {
queue_info[distinct_queue_count].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
queue_info[distinct_queue_count].pNext = NULL;
queue_info[distinct_queue_count].flags = 0;
queue_info[distinct_queue_count].queueCount = 1;
queue_info[distinct_queue_count].queueFamilyIndex = queue_indices.transfer;
queue_info[distinct_queue_count].pQueuePriorities = &priority;
dev->unique_families[distinct_queue_count] = queue_indices.transfer;
++distinct_queue_count;
}
dev->unique_family_count = distinct_queue_count;
VkPhysicalDeviceTimelineSemaphoreFeatures timeline_semaphore_features = {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TIMELINE_SEMAPHORE_FEATURES,
};
@ -619,9 +627,15 @@ void DestroyPerFrameObjects(rt_vk_device *dev) {
}
}
rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info) {
rtLog("vk", "Init");
extern rt_result CreateSwapchain(rt_vk_device *dev);
extern rt_result RecreateSwapchain(rt_vk_device *dev);
extern void DestroySwapchain(rt_vk_device *dev);
rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info) {
rtLog("VK", "Init");
rt_timestamp initBegin = rtTimeNow();
rt_vk_device dev;
_tracking_alloc_cbs.pUserData = NULL;
@ -635,6 +649,13 @@ rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info)
dev.alloc_cb = NULL;
}
dev.max_frames_in_flight = RT_RESTRICT_VALUE_TO_BOUNDS(r_VkMaxFramesInFlight.i, 2, 3);
rtLog("VK", "Max frames in flight: %u", dev.max_frames_in_flight);
if ((int)dev.max_frames_in_flight != r_VkMaxFramesInFlight.i) {
r_VkMaxFramesInFlight.i = (int)dev.max_frames_in_flight;
rtNotifyCVARChange(&r_VkMaxFramesInFlight);
}
rt_result res;
if ((res = CreateInstance(&dev)) != RT_SUCCESS)
goto out;
@ -646,6 +667,11 @@ rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info)
goto out;
if ((res = CreatePerFrameObjects(&dev)) != RT_SUCCESS)
goto out;
if ((res = CreateSwapchain(&dev)) != RT_SUCCESS)
goto out;
rt_time_delta initTime = rtTimeBetween(initBegin, rtTimeNow());
rtLog("VK", "Init complete. Took %lf seconds.", initTime);
out:
return (rt_create_vk_device_result) {.result = res, .device = dev};
@ -654,6 +680,7 @@ out:
void rtDestroyVkDevice(rt_vk_device *dev) {
rtLog("VK", "Shutdown");
vkDeviceWaitIdle(dev->device);
DestroySwapchain(dev);
DestroyPerFrameObjects(dev);
// DestroyAllocator();
vkDestroyDevice(dev->device, dev->alloc_cb);
@ -663,3 +690,9 @@ void rtDestroyVkDevice(rt_vk_device *dev) {
#endif
vkDestroyInstance(dev->instance, dev->alloc_cb);
}
/* rt_render_device_i functions */
rt_physical_resource_manager_i rtVkDevGetPhysicalResourceManager(void *o) {
rt_physical_resource_manager_i iface = {};
return iface;
}

View File

@ -4,6 +4,7 @@
#include <volk/volk.h>
#include <runtime/runtime.h>
#include <renderer/renderer.h>
#include <renderer/backend_api.h>
#ifdef _WIN32
struct HINSTANCE__;
@ -29,7 +30,7 @@ typedef struct {
VkSemaphore swapchain_transitioned;
} rt_vk_frame_data;
typedef struct {
typedef struct rt_vk_device {
/* *** Vulkan objects *** */
VkInstance instance;
VkDevice device;
@ -42,11 +43,14 @@ typedef struct {
uint32_t compute_family;
uint32_t transfer_family;
uint32_t present_family;
uint32_t unique_families[4];
uint32_t unique_family_count;
VkQueue graphics_queue;
VkQueue compute_queue;
VkQueue transfer_queue;
VkQueue present_queue;
/* *** Properties and features *** */
VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props;
VkPhysicalDeviceDescriptorIndexingFeatures descriptor_indexing_features;
@ -59,6 +63,10 @@ typedef struct {
/* *** Windowing system *** */
rt_vk_native_window native_window;
VkSwapchainKHR swapchain;
VkImage swapchain_images[4];
VkImageView swapchain_image_views[4];
uint32_t swapchain_image_count;
/* *** Debug utils *** */
#ifdef RT_DEBUG
@ -75,5 +83,7 @@ rt_create_vk_device_result rtCreateVkDevice(const rt_renderer_window_info *info)
void rtDestroyVkDevice(rt_vk_device *dev);
#endif
/* rt_render_device_i functions */
rt_physical_resource_manager_i rtVkDevGetPhysicalResourceManager(void *o);
#endif

View File

@ -7,11 +7,7 @@
extern rt_cvar r_VkEnableAPIAllocTracking;
extern rt_cvar r_VkPhysDeviceName;
extern rt_cvar r_VkMaxFramesInFlight;
#if 0
extern rt_cvar r_VkPreferredSwapchainImages;
extern rt_cvar r_VkPreferMailboxMode;
#endif
void VkRegisterCVARs(void) {
rtRegisterCVAR(&r_VkEnableAPIAllocTracking);
@ -37,7 +33,7 @@ rt_render_backend_init_result VkInit(const rt_renderer_window_info *info) {
_device = device_result.device;
rt_render_device_i device_i = {
.o = &_device,
.GetPhysicalResourceManager = NULL
.GetPhysicalResourceManager = rtVkDevGetPhysicalResourceManager,
};
res.device = device_i;

View File

@ -14,10 +14,12 @@ if get_option('build_vk')
vk_renderer_lib = library('rtvk',
'device.h',
'physical_resource_manager.h',
'device.c',
'init.c',
'physical_resource_manager.c',
'swapchain.c',
'../../../contrib/volk/volk.c',
'../../../contrib/volk/volk.h',

View File

@ -0,0 +1 @@
#include "physical_resource_manager.h"

View File

@ -0,0 +1,10 @@
#ifndef RT_VK_PHYSICAL_RESOURCE_MANAGER_H
#define RT_VK_PHYSICAL_RESOURCE_MANAGER_H
struct rt_vk_device;
typedef struct {
struct rt_vk_device *dev;
} rt_vk_physical_resource_manager;
#endif

176
src/renderer/vk/swapchain.c Normal file
View File

@ -0,0 +1,176 @@
#include <runtime/mem_arena.h>
#include <runtime/config.h>
#include "device.h"
RT_CVAR_I(r_VkPreferMailboxMode, "Prefer the mailbox present mode. [0/1] (Default: 1)", 1);
RT_CVAR_I(r_VkPreferRelaxedMode, "Prefer the relaxed FIFO present mode. [0/1] (Default: 0)", 0);
RT_CVAR_I(r_VkEnableVSync, "Enable VSync. [0/1] (Default: 0)", 0);
rt_result CreateSwapchain(rt_vk_device *dev) {
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
uint32_t format_count = 0;
if (vkGetPhysicalDeviceSurfaceFormatsKHR(dev->phys_device, dev->surface, &format_count, NULL) != VK_SUCCESS) {
rtReturnTemporaryArena(temp);
return RT_UNKNOWN_ERROR;
}
VkSurfaceFormatKHR *formats = RT_ARENA_PUSH_ARRAY(temp.arena, VkSurfaceFormatKHR, format_count);
if (vkGetPhysicalDeviceSurfaceFormatsKHR(dev->phys_device, dev->surface, &format_count, formats) != VK_SUCCESS) {
rtReturnTemporaryArena(temp);
return RT_UNKNOWN_ERROR;
}
/* Pick a format */
VkFormat surface_format = formats[0].format;
VkColorSpaceKHR color_space = formats[0].colorSpace;
for (uint32_t i = 0; i < format_count; ++i) {
if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB && formats[i].colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {
surface_format = formats[i].format;
color_space = formats[i].colorSpace;
break;
}
}
/* Determine the number of images to create */
uint32_t num_images = dev->max_frames_in_flight + 1;
VkSurfaceCapabilitiesKHR surface_capabilities;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(dev->phys_device, dev->surface, &surface_capabilities);
if (surface_capabilities.maxImageCount > 0 && surface_capabilities.maxImageCount < dev->max_frames_in_flight) {
dev->max_frames_in_flight = surface_capabilities.maxImageCount;
num_images = dev->max_frames_in_flight;
rtLog("VK", "Limiting number of frames in flight to maximum number of swapchain images %u.", dev->max_frames_in_flight);
}
if (surface_capabilities.maxImageCount > 0 && num_images > surface_capabilities.maxImageCount) {
num_images = surface_capabilities.maxImageCount;
}
/* Determine the extent */
VkExtent2D extent = surface_capabilities.currentExtent;
if (surface_capabilities.currentExtent.width == UINT32_MAX && surface_capabilities.currentExtent.height == UINT32_MAX) {
extent = surface_capabilities.maxImageExtent;
}
/* Determine the present mode */
uint32_t present_mode_count = 0;
if (vkGetPhysicalDeviceSurfacePresentModesKHR(dev->phys_device, dev->surface, &present_mode_count, NULL) != VK_SUCCESS) {
rtReturnTemporaryArena(temp);
return RT_UNKNOWN_ERROR;
}
VkPresentModeKHR *present_modes = RT_ARENA_PUSH_ARRAY(temp.arena, VkPresentModeKHR, present_mode_count);
if (vkGetPhysicalDeviceSurfacePresentModesKHR(dev->phys_device, dev->surface, &present_mode_count, present_modes) != VK_SUCCESS) {
rtReturnTemporaryArena(temp);
return RT_UNKNOWN_ERROR;
}
VkPresentModeKHR present_mode = present_modes[0];
if (!r_VkEnableVSync.i) {
if (r_VkPreferMailboxMode.i) {
rtLog("VK", "r_VkPreferMailboxMode has no effect, if VSync is disabled.");
r_VkPreferMailboxMode.i = 0;
rtNotifyCVARChange(&r_VkPreferMailboxMode);
}
if (r_VkPreferRelaxedMode.i) {
rtLog("VK", "r_VkPreferRelaxedMode has no effect, if VSync is disabled.");
r_VkPreferRelaxedMode.i = 0;
rtNotifyCVARChange(&r_VkPreferRelaxedMode);
}
for (uint32_t i = 0; i < present_mode_count; ++i) {
if (present_modes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR) {
present_mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
break;
}
}
if (present_mode != VK_PRESENT_MODE_IMMEDIATE_KHR) {
rtLog("VK", "VSync was disabled, but the physical device/surface combination does not support VK_PRESENT_MODE_IMMEDIATE_KHR");
r_VkEnableVSync.i = 1;
rtNotifyCVARChange(&r_VkEnableVSync);
}
}
/* NOT an else if, because we fall back to this if disabled vsync is not supported. */
if (r_VkEnableVSync.i) {
/* Required to be supported */
present_mode = VK_PRESENT_MODE_FIFO_KHR;
if (r_VkPreferMailboxMode.i || r_VkPreferRelaxedMode.i) {
for (uint32_t i = 0; i < present_mode_count; ++i) {
if (present_modes[i] == VK_PRESENT_MODE_FIFO_RELAXED_KHR && r_VkPreferRelaxedMode.i) {
present_mode = present_modes[i];
break;
}
if (present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR && r_VkPreferMailboxMode.i) {
present_mode = present_modes[i];
break;
}
}
}
}
VkSwapchainCreateInfoKHR swapchain_info = {
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
.pNext = NULL,
.flags = 0,
.surface = dev->surface,
.minImageCount = num_images,
.imageFormat = surface_format,
.imageColorSpace = color_space,
.imageExtent = extent,
.imageArrayLayers = 1,
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
.pQueueFamilyIndices = NULL,
.queueFamilyIndexCount = 0,
.preTransform = surface_capabilities.currentTransform,
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
.presentMode = present_mode,
.clipped = VK_TRUE,
.oldSwapchain = VK_NULL_HANDLE,
};
if (dev->graphics_family != dev->present_family) {
uint32_t queue_families[2];
queue_families[0] = dev->graphics_family;
queue_families[1] = dev->present_family;
swapchain_info.pQueueFamilyIndices = &queue_families[0];
swapchain_info.queueFamilyIndexCount = 2;
}
if (vkCreateSwapchainKHR(dev->device, &swapchain_info, dev->alloc_cb, &dev->swapchain) != VK_SUCCESS) {
rtReturnTemporaryArena(temp);
return RT_UNKNOWN_ERROR;
}
vkGetSwapchainImagesKHR(dev->device, dev->swapchain, &dev->swapchain_image_count, NULL);
RT_ASSERT(dev->swapchain_image_count <= RT_ARRAY_COUNT(dev->swapchain_images), "Unexpectedly high number of swapchain images.");
vkGetSwapchainImagesKHR(dev->device, dev->swapchain, &dev->swapchain_image_count, &dev->swapchain_images[0]);
for (uint32_t i = 0; i < dev->swapchain_image_count; ++i) {
VkImageViewCreateInfo view_info = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = dev->swapchain_images[i],
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = surface_format,
.components = { VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY },
.subresourceRange = { .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseArrayLayer = 0,.baseMipLevel = 0,
.layerCount = 1, .levelCount = 1},
};
vkCreateImageView(dev->device, &view_info, dev->alloc_cb, &dev->swapchain_image_views[i]);
}
return RT_SUCCESS;
}
void DestroySwapchain(rt_vk_device *dev) {
vkDestroySwapchainKHR(dev->device, dev->swapchain, dev->alloc_cb);
for (uint32_t i = 0; i < dev->swapchain_image_count; ++i) {
vkDestroyImageView(dev->device, dev->swapchain_image_views[i], dev->alloc_cb);
}
}
rt_result RecreateSwapchain(rt_vk_device *dev) {
/* TODO(Kevin): Do this in a more perfomant way involving oldSwapchain */
vkDeviceWaitIdle(dev->device);
DestroySwapchain(dev);
return CreateSwapchain(dev);
}

View File

@ -16,7 +16,7 @@ khronos_validation.validate_sync = true
khronos_validation.thread_safety = true
# Specifies what action is to be taken when a layer reports information
khronos_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG
#khronos_validation.debug_action = VK_DBG_LAYER_ACTION_LOG_MSG
# Comma-delineated list of options specifying the types of messages to be reported
khronos_validation.report_flags = debug,error,perf,info,warn