I decided to make queues explicit, to simplify handling queue ownership transfers in the renderer code. The framegraph + pass code has explicit knowledge about resource ownership, so it makes sense to handle it there. - Manage pools - Allocate command buffers - Submit command buffers
129 lines
5.0 KiB
C
129 lines
5.0 KiB
C
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
#define RT_DONT_DEFINE_RENDERER_GLOBAL
|
|
|
|
#include "config.h"
|
|
#include "dynamic_libs.h"
|
|
#include "gfx.h"
|
|
#include "renderer_api.h"
|
|
|
|
/* Attributes are used to bind buffers (or textures) to symbolic values.
|
|
* For example, an attribute might be bound to "CELL_GRID", which would be
|
|
* replaced with the (at the time of the invoke) grid buffer of the current
|
|
* world cell.
|
|
*/
|
|
|
|
rt_renderer_api g_renderer;
|
|
static rt_dynlib _renderer_lib;
|
|
static bool _renderer_loaded = false;
|
|
|
|
RT_DLLEXPORT
|
|
RT_CVAR_S(rt_Renderer, "Select the render backend. Available options: [vk], Default: vk", "vk");
|
|
|
|
#ifdef RT_STATIC_LIB
|
|
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 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
|
|
RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *);
|
|
extern void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle);
|
|
extern rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t,
|
|
const rt_alloc_command_buffer_info *,
|
|
rt_command_buffer_handle *);
|
|
extern rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue,
|
|
const rt_submit_command_buffers_info *);
|
|
#endif
|
|
|
|
extern rt_result InitFramegraphManager(void);
|
|
extern void ShutdownFramegraphManager(void);
|
|
|
|
static bool LoadRenderer(void) {
|
|
|
|
#if !defined(RT_STATIC_LIB)
|
|
#define RETRIEVE_SYMBOL(name, type) \
|
|
g_renderer.name = (type *)rtGetSymbol(_renderer_lib, "rtRen" #name); \
|
|
if (!g_renderer.name) { \
|
|
rtReportError("GFX", \
|
|
"Unable to retrieve renderer function %s from backend %s", \
|
|
#name, \
|
|
rt_Renderer.s); \
|
|
}
|
|
|
|
if (strcmp(rt_Renderer.s, "vk") == 0) {
|
|
_renderer_lib = rtOpenLib(RT_DLLNAME("rtvk"));
|
|
if (!_renderer_lib) {
|
|
rtReportError("GFX", "Unable to load renderer backend: %s", RT_DLLNAME("rtvk"));
|
|
return false;
|
|
}
|
|
RETRIEVE_SYMBOL(RegisterCVars, rt_register_renderer_cvars_fn);
|
|
RETRIEVE_SYMBOL(Init, rt_init_renderer_fn);
|
|
RETRIEVE_SYMBOL(Shutdown, rt_shutdown_renderer_fn);
|
|
RETRIEVE_SYMBOL(BeginFrame, rt_begin_frame_fn);
|
|
RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
|
|
RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
|
|
RETRIEVE_SYMBOL(CreateRenderTarget, rt_create_render_target_fn);
|
|
RETRIEVE_SYMBOL(DestroyRenderTarget, rt_destroy_render_target_fn);
|
|
RETRIEVE_SYMBOL(AllocCommandBuffers, rt_alloc_command_buffers_fn);
|
|
RETRIEVE_SYMBOL(SubmitCommandBuffers, rt_submit_command_buffers_fn);
|
|
} else {
|
|
rtReportError("GFX",
|
|
"Unsupported renderer backend: (%s) %s",
|
|
rt_Renderer.name,
|
|
rt_Renderer.s);
|
|
return false;
|
|
}
|
|
#undef RETRIEVE_SYMBOL
|
|
#else
|
|
g_renderer.RegisterCVars = &rtRenRegisterCVars;
|
|
g_renderer.Init = &rtRenInit;
|
|
g_renderer.Shutdown = &rtRenShutdown;
|
|
g_renderer.BeginFrame = &rtRenBeginFrame;
|
|
g_renderer.CompilePipeline = &rtRenCompilePipeline;
|
|
g_renderer.DestroyPipeline = &rtRenDestroyPipeline;
|
|
g_renderer.CreateRenderTarget = &rtRenCreateRenderTarget;
|
|
g_renderer.DestroyRenderTarget = &rtRenDestroyRenderTarget;
|
|
g_renderer.AllocCommandBuffers = &rtRenAllocCommandBuffers;
|
|
g_renderer.SubmitCommandBuffers = &rtRenSubmitCommandBuffers;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
RT_DLLEXPORT void rtRegisterRendererCVars(void) {
|
|
if (!_renderer_loaded) {
|
|
if (!LoadRenderer())
|
|
return;
|
|
_renderer_loaded = true;
|
|
}
|
|
g_renderer.RegisterCVars();
|
|
}
|
|
|
|
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
|
|
if (!_renderer_loaded) {
|
|
if (!LoadRenderer())
|
|
return RT_UNKNOWN_ERROR;
|
|
g_renderer.RegisterCVars();
|
|
}
|
|
|
|
rt_result result;
|
|
|
|
if ((result = g_renderer.Init(renderer_info)) != RT_SUCCESS)
|
|
return result;
|
|
|
|
if ((result = InitFramegraphManager()) != RT_SUCCESS)
|
|
return result;
|
|
|
|
return result;
|
|
}
|
|
|
|
RT_DLLEXPORT void rtShutdownGFX(void) {
|
|
ShutdownFramegraphManager();
|
|
g_renderer.Shutdown();
|
|
}
|
|
|
|
RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) {
|
|
g_renderer.BeginFrame(frame_id);
|
|
} |