feat: Create the swapchain
Some checks failed
Ubuntu Cross to Win64 / Cross Compile with ming64 (1.4.0, ubuntu-latest) (push) Failing after 1m50s
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:
parent
e0904e84c4
commit
3a7bca385c
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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',
|
||||
|
1
src/renderer/vk/physical_resource_manager.c
Normal file
1
src/renderer/vk/physical_resource_manager.c
Normal file
@ -0,0 +1 @@
|
||||
#include "physical_resource_manager.h"
|
10
src/renderer/vk/physical_resource_manager.h
Normal file
10
src/renderer/vk/physical_resource_manager.h
Normal 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
176
src/renderer/vk/swapchain.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user