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 = {
 | 
			
		||||
    .Init     = Init,
 | 
			
		||||
    .Shutdown = Shutdown,
 | 
			
		||||
    .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
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,7 @@ typedef union {
 | 
			
		||||
} rt_color;
 | 
			
		||||
 | 
			
		||||
/* NOTE(kevin): When you add a value here, you need to handle them in
 | 
			
		||||
 * framegraph_processor.c : ParseFramegraph 
 | 
			
		||||
 * framegraph_processor.c : ParseFramegraph
 | 
			
		||||
 * and in the render target and texture functions of all renderers. */
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
@ -62,8 +62,8 @@ RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info);
 | 
			
		||||
RT_DLLEXPORT void rtShutdownGFX(void);
 | 
			
		||||
 | 
			
		||||
/* *********************************************************************
 | 
			
		||||
 * Framegraph API 
 | 
			
		||||
 * 
 | 
			
		||||
 * Framegraph API
 | 
			
		||||
 *
 | 
			
		||||
 * The framegraph is used to organize and schedule the work for a frame.
 | 
			
		||||
 * *********************************************************************/
 | 
			
		||||
 | 
			
		||||
@ -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