Add single-threaded framegraph execute function
This commit is contained in:
parent
abe05f3780
commit
c23f03e622
@ -1,11 +1,17 @@
|
||||
#include "runtime/app.h"
|
||||
|
||||
extern void RegisterCVars(void);
|
||||
extern void Init(void);
|
||||
extern void Shutdown(void);
|
||||
extern void Update(void);
|
||||
extern void Render(void);
|
||||
|
||||
static rt_app_callbacks _callbacks = {
|
||||
.RegisterCVars = RegisterCVars,
|
||||
.Init = Init,
|
||||
.Shutdown = Shutdown,
|
||||
.Update = Update,
|
||||
.Render = Render,
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "runtime/gfx.h"
|
||||
#include "runtime/resources.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/resources.h"
|
||||
#include "runtime/threading.h"
|
||||
|
||||
#include "asset_compiler/asset_compiler.h"
|
||||
|
||||
@ -8,15 +9,66 @@ void RegisterCVars(void) {
|
||||
rtRegisterAssetCompilerCVars();
|
||||
}
|
||||
|
||||
static rt_framegraph *_framegraph;
|
||||
|
||||
static void PassPrepare(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Prepare pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassExecute(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Execute pass %x", pass);
|
||||
}
|
||||
|
||||
static void PassFinalize(rt_render_pass_id pass,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count) {
|
||||
rtLog("GAME", "Finalize pass %x", pass);
|
||||
}
|
||||
|
||||
/* Called after the runtime has finished its initialization and before entering the main-loop*/
|
||||
void Init(void) {
|
||||
rtLog("GAME", "Init");
|
||||
|
||||
rtInitAssetCompiler();
|
||||
|
||||
rt_resource_id resid = rtGetResourceID("assets/test.framegraph");
|
||||
while (rtGetResourceSize(resid) == 0)
|
||||
rtSleep(10);
|
||||
|
||||
rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
|
||||
|
||||
size_t size = rtGetResourceSize(resid);
|
||||
rt_resource *res = rtArenaPush(temp.arena, size);
|
||||
rtGetResource(resid, res);
|
||||
|
||||
_framegraph = rtCreateFramegraph(res->data);
|
||||
|
||||
rt_render_pass_bind_fns bind = {.Execute = PassExecute,
|
||||
.Prepare = PassPrepare,
|
||||
.Finalize = PassFinalize};
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass0", sizeof("pass0")-1), &bind);
|
||||
rtBindRenderPass(_framegraph, rtCalculateRenderPassID("pass1", sizeof("pass1")-1), &bind);
|
||||
}
|
||||
|
||||
/* Called after exiting the main-loop and before the runtime starts its shutdown */
|
||||
void Shutdown(void) {
|
||||
rtLog("GAME", "Shutdown");
|
||||
rtShutdownAssetCompiler();
|
||||
rtDestroyFramegraph(_framegraph);
|
||||
}
|
||||
|
||||
void Update(void) {
|
||||
}
|
||||
|
||||
void Render(void) {
|
||||
rtExecuteFramegraph(_framegraph);
|
||||
}
|
@ -98,7 +98,7 @@ rtWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
|
||||
|
||||
app_callbacks.Init();
|
||||
|
||||
if (rtInitMainLoop() != RT_SUCCESS) {
|
||||
if (rtInitMainLoop(app_callbacks.Update, app_callbacks.Render) != RT_SUCCESS) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
/* Platform specific application entry point */
|
||||
|
||||
#include "runtime.h"
|
||||
#include "main_loop.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -23,6 +24,12 @@ typedef struct {
|
||||
|
||||
/* Called after the main-loop and before the runtime starts its shutdown. */
|
||||
rt_app_shutdown_fn *Shutdown;
|
||||
|
||||
/* Called by the update thread for each frame */
|
||||
rt_main_loop_update_fn *Update;
|
||||
|
||||
/* Called by the render thread for each frame */
|
||||
rt_main_loop_render_fn *Render;
|
||||
} rt_app_callbacks;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -131,9 +131,21 @@ typedef struct {
|
||||
uint32_t render_pass_count;
|
||||
} rt_framegraph_info;
|
||||
|
||||
typedef void rt_render_pass_prepare_fn(rt_render_pass_id id);
|
||||
typedef void rt_render_pass_execute_fn(rt_render_pass_id id);
|
||||
typedef void rt_render_pass_finalize_fn(rt_render_pass_id id);
|
||||
typedef void rt_render_pass_prepare_fn(rt_render_pass_id id,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count);
|
||||
typedef void rt_render_pass_execute_fn(rt_render_pass_id id,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count);
|
||||
typedef void rt_render_pass_finalize_fn(rt_render_pass_id id,
|
||||
const rt_render_target_write *writes,
|
||||
uint32_t write_count,
|
||||
const rt_render_target_read *reads,
|
||||
uint32_t read_count);
|
||||
|
||||
typedef struct {
|
||||
rt_render_pass_prepare_fn *Prepare;
|
||||
@ -141,14 +153,17 @@ typedef struct {
|
||||
rt_render_pass_finalize_fn *Finalize;
|
||||
} rt_render_pass_bind_fns;
|
||||
|
||||
|
||||
typedef struct rt_framegraph_s rt_framegraph;
|
||||
|
||||
RT_DLLEXPORT rt_framegraph *rtCreateFramegraph(const rt_framegraph_info *info);
|
||||
|
||||
RT_DLLEXPORT void rtDestroyFramegraph(rt_framegraph *framegraph);
|
||||
|
||||
RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph, rt_render_pass_id pass, const rt_render_pass_bind_fns *bind_fns);
|
||||
RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph,
|
||||
rt_render_pass_id pass,
|
||||
const rt_render_pass_bind_fns *bind_fns);
|
||||
|
||||
RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph);
|
||||
|
||||
/* Utility to turn a string into a usable render target id. */
|
||||
RT_DLLEXPORT rt_render_target_id rtCalculateRenderTargetID(const char *name, size_t len);
|
||||
|
@ -18,6 +18,7 @@ RT_CVAR_I(rt_MaxFramegraphs, "Maximum number of framegraphs. Default 16", 16);
|
||||
#define RT_RENDERPASS_MAX_WRITES 8
|
||||
|
||||
typedef struct {
|
||||
rt_render_target_id id;
|
||||
rt_pixel_format format;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
@ -26,6 +27,7 @@ typedef struct {
|
||||
} rt_render_target;
|
||||
|
||||
typedef struct {
|
||||
rt_render_pass_id id;
|
||||
int execution_level;
|
||||
unsigned int read_count;
|
||||
unsigned int write_count;
|
||||
@ -40,10 +42,8 @@ struct rt_framegraph_s {
|
||||
|
||||
rt_framegraph *next_free;
|
||||
|
||||
rt_render_pass_id pass_ids[RT_FRAMEGRAPH_MAX_PASSES];
|
||||
rt_render_pass passes[RT_FRAMEGRAPH_MAX_PASSES];
|
||||
|
||||
rt_render_target_id render_target_ids[RT_FRAMEGRAPH_MAX_RENDER_TARGETS];
|
||||
rt_render_target render_targets[RT_FRAMEGRAPH_MAX_RENDER_TARGETS];
|
||||
};
|
||||
|
||||
@ -224,6 +224,7 @@ CreateRenderPasses(rt_framegraph *graph, const rt_framegraph_info *info, rt_aren
|
||||
pass_info[i].read_render_target_count * sizeof(rt_render_target_read));
|
||||
graph->passes[i].write_count = pass_info[i].write_render_target_count;
|
||||
graph->passes[i].read_count = pass_info[i].read_render_target_count;
|
||||
graph->passes[i].id = pass_info[i].id;
|
||||
}
|
||||
|
||||
/* Sort by execution level */
|
||||
@ -244,7 +245,7 @@ CreateRenderTargets(rt_framegraph *graph, const rt_framegraph_info *info, rt_are
|
||||
/* TODO(Kevin): determine aliasing opportunities */
|
||||
const rt_render_target_info *render_targets = rtResolveConstRelptr(&info->render_targets);
|
||||
for (uint32_t i = 0; i < info->render_target_count; ++i) {
|
||||
graph->render_target_ids[i] = render_targets[i].id;
|
||||
graph->render_targets[i].id = render_targets[i].id;
|
||||
graph->render_targets[i].format = render_targets[i].format;
|
||||
graph->render_targets[i].width = render_targets[i].width;
|
||||
graph->render_targets[i].height = render_targets[i].height;
|
||||
@ -375,7 +376,7 @@ RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph,
|
||||
rt_render_pass_id id,
|
||||
const rt_render_pass_bind_fns *bind_fns) {
|
||||
for (uint32_t i = 0; i < framegraph->pass_count; ++i) {
|
||||
if (framegraph->pass_ids[i] == id) {
|
||||
if (framegraph->passes[i].id == id) {
|
||||
if (framegraph->passes[i].bound_fns.Execute)
|
||||
rtLog("GFX", "Rebound pass %x to new functions", id);
|
||||
framegraph->passes[i].bound_fns = *bind_fns;
|
||||
@ -385,6 +386,58 @@ RT_DLLEXPORT void rtBindRenderPass(rt_framegraph *framegraph,
|
||||
rtLog("GFX", "Tried to bind functions to unknown render pass %x", id);
|
||||
}
|
||||
|
||||
RT_DLLEXPORT void rtExecuteFramegraph(rt_framegraph *framegraph) {
|
||||
int execution_level = framegraph->passes[0].execution_level;
|
||||
uint32_t level_start = 0;
|
||||
|
||||
for (uint32_t i = 0; i <= framegraph->pass_count && level_start < framegraph->pass_count; ++i) {
|
||||
if ((i == framegraph->pass_count) ||
|
||||
(framegraph->passes[i].execution_level > execution_level)) {
|
||||
/* Dispatch all passes in the current execution level */
|
||||
for (uint32_t pass_idx = level_start; pass_idx < i; ++pass_idx) {
|
||||
bool pass_bound = framegraph->passes[pass_idx].bound_fns.Prepare != NULL &&
|
||||
framegraph->passes[pass_idx].bound_fns.Execute != NULL &&
|
||||
framegraph->passes[pass_idx].bound_fns.Finalize != NULL;
|
||||
if (!pass_bound) {
|
||||
rtLog("GFX",
|
||||
"Framegraph pass %u (%x) is not bound to any function.",
|
||||
pass_idx,
|
||||
framegraph->passes[pass_idx].id);
|
||||
continue;
|
||||
}
|
||||
rt_render_pass_id id = framegraph->passes[pass_idx].id;
|
||||
const rt_render_target_write *writes = framegraph->passes[pass_idx].writes;
|
||||
const rt_render_target_read *reads = framegraph->passes[pass_idx].reads;
|
||||
uint32_t write_count = framegraph->passes[pass_idx].write_count;
|
||||
uint32_t read_count = framegraph->passes[pass_idx].read_count;
|
||||
|
||||
/* TODO(Kevin): Every one of these should be a job-dispatch*/
|
||||
|
||||
framegraph->passes[pass_idx].bound_fns.Prepare(id,
|
||||
writes,
|
||||
write_count,
|
||||
reads,
|
||||
read_count);
|
||||
framegraph->passes[pass_idx].bound_fns.Execute(id,
|
||||
writes,
|
||||
write_count,
|
||||
reads,
|
||||
read_count);
|
||||
framegraph->passes[pass_idx].bound_fns.Finalize(id,
|
||||
writes,
|
||||
write_count,
|
||||
reads,
|
||||
read_count);
|
||||
}
|
||||
|
||||
/* Start next level */
|
||||
level_start = i;
|
||||
if (i < framegraph->pass_count)
|
||||
execution_level = framegraph->passes[i].execution_level;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_render_target_id rtCalculateRenderTargetID(const char *name, size_t len) {
|
||||
rt_render_target_id id = rtHashBytes32(name, len);
|
||||
if (id == 0)
|
||||
|
@ -17,7 +17,7 @@ void UpdateThreadEntry(void *param) {
|
||||
rtWaitOnSemaphore(&g_main_loop.update_proceed);
|
||||
rtLog("UT", "Processing %d", g_main_loop.u_frame_id);
|
||||
|
||||
rtSleep(250);
|
||||
(g_main_loop.GameUpdate)();
|
||||
|
||||
rtLog("UT", "Finished %d", g_main_loop.u_frame_id);
|
||||
g_main_loop.u_frame_id += 1;
|
||||
@ -36,7 +36,7 @@ void RenderThreadEntry(void *param) {
|
||||
rtWaitOnSemaphore(&g_main_loop.render_proceed);
|
||||
rtLog("RT", "Processing %d", g_main_loop.r_frame_id);
|
||||
|
||||
rtSleep(500);
|
||||
(g_main_loop.GameRender)();
|
||||
|
||||
rtLog("RT", "Finished %d", g_main_loop.r_frame_id);
|
||||
g_main_loop.r_frame_id += 1;
|
||||
@ -45,12 +45,18 @@ void RenderThreadEntry(void *param) {
|
||||
}
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_result rtInitMainLoop(void) {
|
||||
RT_DLLEXPORT rt_result rtInitMainLoop(rt_main_loop_update_fn *update_cb,
|
||||
rt_main_loop_render_fn *render_cb) {
|
||||
RT_ASSERT(g_main_loop.render_thread == NULL && g_main_loop.update_thread == NULL,
|
||||
"InitMainLoop called multiple times.");
|
||||
RT_ASSERT(update_cb != NULL && render_cb != NULL,
|
||||
"Valid update and render functions must be provided.");
|
||||
|
||||
g_main_loop.r_frame_id = 0;
|
||||
g_main_loop.u_frame_id = 0;
|
||||
g_main_loop.shutdown = 0;
|
||||
g_main_loop.GameUpdate = update_cb;
|
||||
g_main_loop.GameRender = render_cb;
|
||||
|
||||
int frame_latency = rt_MaxFrameLatency.i;
|
||||
if (frame_latency < 2) {
|
||||
|
@ -4,6 +4,9 @@
|
||||
#include "runtime.h"
|
||||
#include "threading.h"
|
||||
|
||||
typedef void rt_main_loop_update_fn(void);
|
||||
typedef void rt_main_loop_render_fn(void);
|
||||
|
||||
typedef struct {
|
||||
int u_frame_id;
|
||||
int r_frame_id;
|
||||
@ -14,13 +17,17 @@ typedef struct {
|
||||
rt_thread *update_thread;
|
||||
rt_thread *render_thread;
|
||||
|
||||
rt_main_loop_update_fn *GameUpdate;
|
||||
rt_main_loop_render_fn *GameRender;
|
||||
|
||||
volatile int shutdown;
|
||||
} rt_main_loop;
|
||||
|
||||
/* The applications main-loop */
|
||||
extern RT_DLLIMPORT rt_main_loop g_main_loop;
|
||||
|
||||
RT_DLLEXPORT rt_result rtInitMainLoop(void);
|
||||
RT_DLLEXPORT rt_result rtInitMainLoop(rt_main_loop_update_fn *update_cb,
|
||||
rt_main_loop_render_fn *render_cb);
|
||||
|
||||
RT_DLLEXPORT void rtShutdownMainLoop(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user