Present the first (black) image

This commit is contained in:
Kevin Trogant 2024-02-19 10:27:53 +01:00
parent e989c2b406
commit 1e49b14879
10 changed files with 142 additions and 4 deletions

View File

@ -260,7 +260,7 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = rtGetSemaphore(info->wait_semaphores[i]),
.value = info->wait_values[i],
.stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
.deviceIndex = 0,
};
wait_semaphores[i] = semaphore_info;
@ -270,7 +270,7 @@ rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_SUBMIT_INFO,
.semaphore = rtGetSemaphore(info->signal_semaphores[i]),
.value = info->signal_values[i],
.stageMask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
.stageMask = VK_PIPELINE_STAGE_2_ALL_COMMANDS_BIT,
.deviceIndex = 0,
};
wait_semaphores[i] = semaphore_info;

View File

@ -1,9 +1,59 @@
#include "gpu.h"
#include "command_buffers.h"
#include "gpu.h"
#include "swapchain.h"
#include "runtime/renderer_api.h"
#define ONE_SECOND_NS 1000000000u
void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) {
g_gpu.current_frame_id = frame_id;
rt_frame_data *frame = rtGetFrameData(frame_id);
/* Wait until the previous frame is done */
VkFence fence = g_swapchain.image_fences[frame_id % g_swapchain.image_count];
RT_VK_CHECK(vkWaitForFences(g_gpu.device, 1, &fence, VK_TRUE, ONE_SECOND_NS));
RT_VK_CHECK(vkResetFences(g_gpu.device, 1, &fence));
rtResetCommandPools(frame_id);
VkResult acquire_res = vkAcquireNextImageKHR(g_gpu.device,
g_swapchain.swapchain,
ONE_SECOND_NS,
frame->image_available,
fence,
&frame->swapchain_image_index);
if (acquire_res == VK_SUBOPTIMAL_KHR || acquire_res == VK_ERROR_OUT_OF_DATE_KHR) {
/* We need to recreate the swapchain and try again */
rtLog("vk", "Swapchain has become suboptimal and needs to be re-created.");
vkDeviceWaitIdle(g_gpu.device);
if (rtRecreateSwapchain() != RT_SUCCESS) {
rtReportError("vk", "Failed to recreate the swapchain.");
return;
}
rtRenBeginFrame(frame_id);
} else if (acquire_res != VK_SUCCESS) {
rtReportError("vk", "vkAcquireNextImageKHR failed: %u", acquire_res);
}
}
void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
rt_frame_data *frame = rtGetFrameData(frame_id);
uint32_t image_index = frame->swapchain_image_index;
VkPresentInfoKHR present_info = {
.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.pImageIndices = &image_index,
.pSwapchains = &g_swapchain.swapchain,
.swapchainCount = 1,
.pWaitSemaphores = &frame->image_available,
.waitSemaphoreCount = 1,
};
VkResult res = vkQueuePresentKHR(g_gpu.present_queue, &present_info);
if (res != VK_SUCCESS) {
rtReportError("vk", "vkQueuePresentKHR failed: %u", res);
}
}

View File

@ -33,6 +33,12 @@ typedef struct {
#endif
} rt_native_window;
typedef struct {
uint32_t swapchain_image_index;
VkSemaphore image_available;
VkSemaphore render_finished;
} rt_frame_data;
typedef struct {
VkInstance instance;
VkDebugUtilsMessengerEXT messenger;
@ -60,14 +66,30 @@ typedef struct {
unsigned int max_frames_in_flight;
unsigned int current_frame_id;
rt_frame_data frames[RT_VK_MAX_SUPPORTED_FRAMES_IN_FLIGHT];
} rt_vk_gpu;
#ifndef RT_VK_DONT_DEFINE_GPU_GLOBAL
extern rt_vk_gpu g_gpu;
RT_INLINE rt_frame_data *rtGetFrameData(unsigned int frame_id) {
return &g_gpu.frames[frame_id % g_gpu.max_frames_in_flight];
}
#endif
/* Helper functions */
#define RT_VK_CHECK(expr) \
do { \
VkResult res = expr; \
if (res != VK_SUCCESS) { \
rtReportError("vk", "Vulkan command failed with error %u.\nCommand: %s", res, #expr); \
} \
} while (0)
VkFormat rtPixelFormatToVkFormat(rt_pixel_format format);
VkSampleCountFlagBits rtSampleCountToFlags(unsigned int count);

View File

@ -543,6 +543,34 @@ static void DestroyAllocator(void) {
vmaDestroyAllocator(g_gpu.allocator);
}
static rt_result CreatePerFrameObjects(void) {
for (unsigned int i = 0; i < g_gpu.max_frames_in_flight; ++i) {
VkSemaphoreCreateInfo semaphore_info = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
};
if (vkCreateSemaphore(g_gpu.device,
&semaphore_info,
g_gpu.alloc_cb,
&g_gpu.frames[i].render_finished) != VK_SUCCESS) {
return RT_UNKNOWN_ERROR;
}
if (vkCreateSemaphore(g_gpu.device,
&semaphore_info,
g_gpu.alloc_cb,
&g_gpu.frames[i].image_available) != VK_SUCCESS) {
return RT_UNKNOWN_ERROR;
}
}
return RT_SUCCESS;
}
void DestroyPerFrameObjects(void) {
for (unsigned int i = 0; i < g_gpu.max_frames_in_flight; ++i) {
vkDestroySemaphore(g_gpu.device, g_gpu.frames[i].image_available, g_gpu.alloc_cb);
vkDestroySemaphore(g_gpu.device, g_gpu.frames[i].render_finished, g_gpu.alloc_cb);
}
}
extern rt_result InitPipelineManagement(void);
extern void ShutdownPipelineManagement(void);
extern rt_result InitRenderTargetManagement(void);
@ -582,6 +610,9 @@ rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
if (res != RT_SUCCESS)
return res;
res = CreateAllocator();
if (res != RT_SUCCESS)
return res;
res = CreatePerFrameObjects();
if (res != RT_SUCCESS)
return res;
res = InitPipelineManagement();
@ -611,8 +642,12 @@ void RT_RENDERER_API_FN(Shutdown)(void) {
ShutdownSemaphoreManagement();
ShutdownRenderTargetManagement();
ShutdownPipelineManagement();
DestroyPerFrameObjects();
DestroyAllocator();
vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb);
vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb);
#ifdef RT_DEBUG
vkDestroyDebugUtilsMessengerEXT(g_gpu.instance, g_gpu.messenger, g_gpu.alloc_cb);
#endif
vkDestroyInstance(g_gpu.instance, g_gpu.alloc_cb);
}

View File

@ -167,6 +167,23 @@ rt_result rtCreateSwapchain(void) {
}
}
/* Create fences */
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
VkFenceCreateInfo fence_info = {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
/* Create as signalled so that we can wait on it the first time we render to that
swapchain image. */
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
};
if (vkCreateFence(g_gpu.device,
&fence_info,
g_gpu.alloc_cb,
&g_swapchain.image_fences[i]) != VK_SUCCESS) {
rtReportError("vk", "Failed to create a fence for the swapchain");
return 53;
}
}
return RT_SUCCESS;
}
@ -178,6 +195,7 @@ rt_result rtRecreateSwapchain(void) {
void rtDestroySwapchain(void) {
for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
vkDestroyFence(g_gpu.device, g_swapchain.image_fences[i], g_gpu.alloc_cb);
vkDestroyImageView(g_gpu.device, g_swapchain.image_views[i], g_gpu.alloc_cb);
}
vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);

View File

@ -11,6 +11,7 @@ typedef struct {
VkSwapchainKHR swapchain;
VkImage images[RT_VK_MAX_SWAPCHAIN_IMAGES];
VkImageView image_views[RT_VK_MAX_SWAPCHAIN_IMAGES];
VkFence image_fences[RT_VK_MAX_SWAPCHAIN_IMAGES];
uint32_t image_count;
VkFormat format;
VkExtent2D extent;

View File

@ -63,6 +63,8 @@ RT_DLLEXPORT void rtShutdownGFX(void);
RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id);
RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id);
/* *********************************************************************
* Framegraph API
*

View File

@ -26,6 +26,7 @@ extern void RT_RENDERER_API_FN(RegisterCVars)(void);
extern rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *);
extern void RT_RENDERER_API_FN(Shutdown)(void);
extern void RT_RENDERER_API_FN(BeginFrame)(unsigned int);
extern void RT_RENDERER_API_FN(EndFrame)(unsigned int);
extern rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *);
extern void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle);
extern rt_render_target_handle
@ -43,7 +44,7 @@ extern void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semapho
extern uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle);
#endif
extern rt_result InitFramegraphManager(void);
extern rt_result InitFramegraphManager(void);
extern void ShutdownFramegraphManager(void);
static bool LoadRenderer(void) {
@ -68,6 +69,7 @@ static bool LoadRenderer(void) {
RETRIEVE_SYMBOL(Init, rt_init_renderer_fn);
RETRIEVE_SYMBOL(Shutdown, rt_shutdown_renderer_fn);
RETRIEVE_SYMBOL(BeginFrame, rt_begin_frame_fn);
RETRIEVE_SYMBOL(EndFrame, rt_end_frame_fn);
RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
RETRIEVE_SYMBOL(CreateRenderTarget, rt_create_render_target_fn);
@ -90,6 +92,7 @@ static bool LoadRenderer(void) {
g_renderer.Init = &rtRenInit;
g_renderer.Shutdown = &rtRenShutdown;
g_renderer.BeginFrame = &rtRenBeginFrame;
g_renderer.EndFrame = &rtRenEndFrame;
g_renderer.CompilePipeline = &rtRenCompilePipeline;
g_renderer.DestroyPipeline = &rtRenDestroyPipeline;
g_renderer.CreateRenderTarget = &rtRenCreateRenderTarget;
@ -137,4 +140,8 @@ RT_DLLEXPORT void rtShutdownGFX(void) {
RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) {
g_renderer.BeginFrame(frame_id);
}
RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) {
g_renderer.EndFrame(frame_id);
}

View File

@ -40,6 +40,7 @@ void RenderThreadEntry(void *param) {
rtBeginGFXFrame(g_main_loop.r_frame_id);
(g_main_loop.GameRender)();
rtEndGFXFrame(g_main_loop.r_frame_id);
rtLog("RT", "Finished %u", g_main_loop.r_frame_id);
g_main_loop.r_frame_id += 1;

View File

@ -140,6 +140,7 @@ typedef void rt_register_renderer_cvars_fn(void);
typedef rt_result rt_init_renderer_fn(const rt_renderer_init_info *info);
typedef void rt_shutdown_renderer_fn(void);
typedef void rt_begin_frame_fn(unsigned int frame_id);
typedef void rt_end_frame_fn(unsigned int frame_id);
typedef rt_pipeline_handle rt_compile_pipeline_fn(const rt_pipeline_info *info);
typedef void rt_destroy_pipeline_fn(rt_pipeline_handle handle);
typedef rt_render_target_handle rt_create_render_target_fn(const rt_render_target_info *info);
@ -160,6 +161,7 @@ typedef struct {
rt_init_renderer_fn *Init;
rt_shutdown_renderer_fn *Shutdown;
rt_begin_frame_fn *BeginFrame;
rt_end_frame_fn *EndFrame;
rt_compile_pipeline_fn *CompilePipeline;
rt_destroy_pipeline_fn *DestroyPipeline;
rt_create_render_target_fn *CreateRenderTarget;