Present the first (black) image
This commit is contained in:
parent
e989c2b406
commit
1e49b14879
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -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
|
||||
@ -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;
|
||||
@ -138,3 +141,7 @@ 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user