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
 | 
			
		||||
@ -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);
 | 
			
		||||
}
 | 
			
		||||
@ -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