From 5d988d15b76fd4ac85b439a73b0230c97cf82d1b Mon Sep 17 00:00:00 2001 From: Kevin Trogant Date: Tue, 7 May 2024 08:12:45 +0200 Subject: [PATCH] give passes views instead of lists A view is a collection of lists. This is useful for a shadow mapping pass that generates more than one shadow map. Each view would create lists of objects visible in one shadow map. --- src/game/main.c | 10 ++- src/gfx/gfx_main.c | 21 +++++++ src/gfx/meson.build | 3 + src/gfx/render_view.c | 77 +++++++++++++++++++++++ src/gfx/render_view.h | 39 ++++++++++++ src/gfx/renderer_api.h | 33 +++++++--- src/renderer/common/common_render_graph.h | 7 +++ src/renderer/dx11/render_graph.cpp | 26 +++++++- src/renderer/null/null.c | 12 ++++ src/runtime/runtime.h | 2 +- 10 files changed, 217 insertions(+), 13 deletions(-) create mode 100644 src/gfx/render_view.c create mode 100644 src/gfx/render_view.h diff --git a/src/game/main.c b/src/game/main.c index 62fcbad..064f226 100644 --- a/src/game/main.c +++ b/src/game/main.c @@ -14,8 +14,8 @@ void RegisterCVars(void) { static rt_render_graph *_graph; static rt_result ForwardPassExecute(rt_command_buffer_handle cmdbuf, - const rt_render_list *lists, - uint32_t list_count, + const rt_render_view *views, + uint32_t view_count, void *userdata) { return RT_SUCCESS; } @@ -49,7 +49,10 @@ void Init(void) { (rt_color){.r = 1.f, .g = 0.f, .b = 1.f, .a = 1.f}); builder.SetBackbuffer(builder.obj, "backbuffer"); builder.BindRenderPass(builder.obj, "forward", ForwardPassExecute, NULL); - builder.Build(builder.obj, &_graph); + if (builder.Build(builder.obj, &_graph) != RT_SUCCESS) { + rtReportError("GAME", "Failed to build the render graph."); + return; + } g_renderer.DestroyRenderGraphBuilder(&builder); } @@ -65,5 +68,6 @@ void Update(unsigned int frame_id) { } void Render(unsigned int frame_id) { + g_renderer.ResetRenderGraph(_graph); g_renderer.ExecuteRenderGraph(_graph); } \ No newline at end of file diff --git a/src/gfx/gfx_main.c b/src/gfx/gfx_main.c index 6c5f4da..1ef0464 100644 --- a/src/gfx/gfx_main.c +++ b/src/gfx/gfx_main.c @@ -26,6 +26,9 @@ RT_CVAR_S(rt_Renderer, "Select the render backend. Available options: [vk, null], Default: vk", "dx11"); +extern rt_cvar rt_RenderViewArenaSize; +extern rt_cvar rt_RenderListPoolSize; + #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 *); @@ -54,6 +57,10 @@ extern void RT_RENDERER_API_FN(DestroyBuffers)(uint32_t, rt_buffer_handle *); extern rt_render_graph_builder RT_RENDERER_API_FN(CreateRenderGraphBuilder)(void); extern void RT_RENDERER_API_FN(DestroyRenderGraphBuilder)(rt_render_graph_builder *); extern rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *); +extern void RT_RENDERER_API_FN(SubmitRenderView)(rt_render_graph *render_graph, + uint32_t pass_id, + rt_render_view view); +extern void RT_RENDERER_API_FN(ResetRenderGraph)(rt_render_graph *graph); extern void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle, const rt_cmd_begin_pass_info *); @@ -75,6 +82,9 @@ extern void RT_RENDERER_API_FN(CmdDraw)(rt_command_buffer_handle, uint32_t, uint extern rt_result InitRenderLists(void); extern void ShutdownRenderLists(void); extern void ResetRenderLists(void); +extern rt_result InitRenderViews(void); +extern void ShutdownRenderViews(void); +extern void ResetRenderViews(void); static bool LoadRenderer(void) { @@ -109,6 +119,8 @@ static bool LoadRenderer(void) { RETRIEVE_SYMBOL(CreateRenderGrapbuilder, rt_create_render_graph_builder_fn); RETRIEVE_SYMBOL(DestroyRenderGraphBuilder, rt_destroy_render_graph_builder_fn); RETRIEVE_SYMBOL(ExecuteRenderGraph, rt_execute_render_graph_fn); + RETRIEVE_SYMBOL(SubmitRenderView, rt_submit_render_view_fn); + RETRIEVE_SYMBOL(ResetRenderGraph, rt_reset_render_graph_fn); RETRIEVE_SYMBOL(CmdBeginPass, rt_cmd_begin_pass_fn); RETRIEVE_SYMBOL(CmdEndPass, rt_cmd_end_pass_fn); RETRIEVE_SYMBOL(CmdTransitionRenderTarget, rt_cmd_transition_render_target_fn); @@ -140,6 +152,8 @@ static bool LoadRenderer(void) { g_renderer.CreateRenderGraphBuilder = &rtRenCreateRenderGraphBuilder; g_renderer.DestroyRenderGraphBuilder = &rtRenDestroyRenderGraphBuilder; g_renderer.ExecuteRenderGraph = &rtRenExecuteRenderGraph; + g_renderer.SubmitRenderView = &rtRenSubmitRenderView; + g_renderer.ResetRenderGraph = &rtRenResetRenderGraph; g_renderer.CmdBeginPass = &rtRenCmdBeginPass; g_renderer.CmdEndPass = &rtRenCmdEndPass; g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget; @@ -162,6 +176,8 @@ RT_DLLEXPORT void rtRegisterRendererCVars(void) { RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) { rtRegisterCVAR(&rt_Renderer); + rtRegisterCVAR(&rt_RenderViewArenaSize); + rtRegisterCVAR(&rt_RenderListPoolSize); if (!_renderer_loaded) { if (!LoadRenderer()) @@ -177,10 +193,14 @@ RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) { if ((result = InitRenderLists()) != RT_SUCCESS) return result; + if ((result = InitRenderViews()) != RT_SUCCESS) + return result; + return result; } RT_DLLEXPORT void rtShutdownGFX(void) { + ShutdownRenderViews(); ShutdownRenderLists(); g_renderer.Shutdown(); } @@ -192,4 +212,5 @@ RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) { RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) { g_renderer.EndFrame(frame_id); ResetRenderLists(); + ResetRenderViews(); } diff --git a/src/gfx/meson.build b/src/gfx/meson.build index ade295e..2a460da 100644 --- a/src/gfx/meson.build +++ b/src/gfx/meson.build @@ -6,11 +6,14 @@ gfx_lib = library('rtgfx', 'gfx.h', 'renderer_api.h', 'render_list.h', + 'render_view.h', 'builtin_objects.c', 'effect.c', 'gfx_main.c', 'render_list.c', + 'render_view.c', + # Contrib Sources dependencies : gfx_deps, include_directories : engine_incdir, diff --git a/src/gfx/render_view.c b/src/gfx/render_view.c new file mode 100644 index 0000000..d476aa0 --- /dev/null +++ b/src/gfx/render_view.c @@ -0,0 +1,77 @@ +#include "render_view.h" +#include "renderer_api.h" + +#include "runtime/config.h" +#include "runtime/mem_arena.h" +#include "runtime/threading.h" + +RT_CVAR_I(rt_RenderViewArenaSize, + "Size of the memory arena used for allocating render views. Default: 1 MB", + RT_MB(1)); + +static rt_arena _view_arena; +static rt_mutex *_view_lock; + +rt_result InitRenderViews(void) { + rt_create_arena_result arena_res = rtCreateArena(NULL, (size_t)rt_RenderViewArenaSize.i); + if (!arena_res.ok) + return RT_OUT_OF_MEMORY; + _view_arena = arena_res.arena; + _view_lock = rtCreateMutex(); + if (!_view_lock) { + rtReleaseArena(&_view_arena); + return RT_UNKNOWN_ERROR; + } + return RT_SUCCESS; +} + +void ShutdownRenderViews(void) { + rtDestroyMutex(_view_lock); + rtReleaseArena(&_view_arena); +} + +void ResetRenderViews(void) { + rtArenaClear(&_view_arena); +} + +RT_DLLEXPORT rt_create_render_view_result rtCreateRenderView(const rt_render_object_type *types, + uint32_t type_count) { + +#ifdef RT_DEBUG + for (uint32_t i = 0; i < type_count - 1; ++i) { + for (uint32_t j = i + 1; j < type_count; ++j) { + RT_ASSERT(types[i] != types[j], "Duplicate render list type detected."); + } + } +#endif + + size_t size = type_count * (sizeof(rt_render_list) + sizeof(rt_render_list)); + rtLockMutex(_view_lock); + void *storage = rtArenaPush(&_view_arena, size); + rtUnlockMutex(_view_lock); + if (!storage) { + return (rt_create_render_view_result){ + .ok = false, + }; + } + + rt_render_view view; + view.lists = storage; + view.list_types = (rt_render_object_type *)(view.lists + type_count); + view.list_count = type_count; + return (rt_create_render_view_result){.ok = true, .view = view}; +} + +RT_DLLEXPORT bool +rtPushRenderObjectToView(rt_render_view *view, rt_render_object_type type, const void *object) { + for (uint32_t i = 0; i < view->list_count; ++i) { + if (view->list_types[i] == type) + return rtPushRenderListEntry(&view->lists[i], object); + } + return false; +} + +RT_DLLEXPORT void +rtSubmitRenderView(rt_render_view view, rt_render_graph *render_graph, uint32_t pass_id) { + g_renderer.SubmitRenderView(render_graph, pass_id, view); +} \ No newline at end of file diff --git a/src/gfx/render_view.h b/src/gfx/render_view.h new file mode 100644 index 0000000..883a43a --- /dev/null +++ b/src/gfx/render_view.h @@ -0,0 +1,39 @@ +#ifndef RT_GFX_RENDER_VIEW_H +#define RT_GFX_RENDER_VIEW_H + +/* A render view acts as a container of one or more render lists. + * Each view is processed by exactly one pass. */ + +#include "render_list.h" + +typedef struct rt_render_graph_s rt_render_graph; + +typedef struct { + rt_render_list *lists; + rt_render_object_type *list_types; + uint32_t list_count; +} rt_render_view; + +typedef struct { + bool ok; + rt_render_view view; +} rt_create_render_view_result; + +#ifdef __cplusplus +extern "C" { +#endif + +RT_DLLEXPORT rt_create_render_view_result rtCreateRenderView(const rt_render_object_type *types, + uint32_t type_count); + +RT_DLLEXPORT bool +rtPushRenderObjectToView(rt_render_view *view, rt_render_object_type type, const void *object); + +RT_DLLEXPORT void +rtSubmitRenderView(rt_render_view view, rt_render_graph *render_graph, uint32_t pass_id); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/gfx/renderer_api.h b/src/gfx/renderer_api.h index 04896f7..4404557 100644 --- a/src/gfx/renderer_api.h +++ b/src/gfx/renderer_api.h @@ -7,6 +7,7 @@ #include "gfx.h" #include "render_list.h" +#include "render_view.h" #include "runtime/resources.h" #include "runtime/rt_math.h" @@ -18,7 +19,7 @@ extern "C" { /* Handles for backend objects */ -#define RT_RENDER_BACKEND_HANDLE_MAX_INDEX ((1u<<24)-1) +#define RT_RENDER_BACKEND_HANDLE_MAX_INDEX ((1u << 24) - 1) #define RT_RENDER_BACKEND_HANDLE_MAX_VERSION 255 #define RT_RENDER_BACKEND_HANDLE(name) \ @@ -228,8 +229,8 @@ typedef struct { enum { /* Bit 0 contains the type: 0 -> graphics, 1 -> compute */ - RT_PASS_FLAG_GRAPHICS = 0x0000, - RT_PASS_FLAG_COMPUTE = 0x0001, + RT_PASS_FLAG_GRAPHICS = 0x0000, + RT_PASS_FLAG_COMPUTE = 0x0001, RT_PASS_FLAG_TYPE_MASK = RT_PASS_FLAG_COMPUTE | RT_PASS_FLAG_GRAPHICS, /* Always excecute the pass, even if no objects will be rendered. */ @@ -242,7 +243,10 @@ typedef struct { } rt_pass_info; typedef struct rt_render_graph_s rt_render_graph; -typedef rt_result rt_execute_render_pass_fn(rt_command_buffer_handle cmdbuf, const rt_render_list *render_lists, unsigned int render_list_count, void *userdata); +typedef rt_result rt_execute_render_pass_fn(rt_command_buffer_handle cmdbuf, + const rt_render_view *views, + unsigned int view_count, + void *userdata); typedef struct { void *obj; @@ -252,7 +256,12 @@ typedef struct { void (*SetBackbuffer)(void *obj, const char *rt_name); void (*AddRenderPass)(void *obj, const rt_pass_info *info); - void (*AddColorOutput)(void *obj, const char *pass_name, const char *rt_name, rt_pass_load_mode load, rt_pass_write_mode write, rt_color clear_color); + void (*AddColorOutput)(void *obj, + const char *pass_name, + const char *rt_name, + rt_pass_load_mode load, + rt_pass_write_mode write, + rt_color clear_color); void (*AddSampledInput)(void *obj, const char *pass_name, const char *rt_name); void (*SetDepthStencilAttachment)(void *obj, const char *pass_name, @@ -260,12 +269,14 @@ typedef struct { rt_pass_load_mode load, rt_pass_write_mode write, rt_depth_stencil_value clear_value); - void (*BindRenderPass)(void *obj, const char *pass_name, rt_execute_render_pass_fn *execute_fn, void *userdata); + void (*BindRenderPass)(void *obj, + const char *pass_name, + rt_execute_render_pass_fn *execute_fn, + void *userdata); rt_result (*Build)(void *obj, rt_render_graph **p_render_graph); } rt_render_graph_builder; - 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); @@ -286,6 +297,9 @@ typedef void rt_destroy_buffers_fn(uint32_t count, rt_buffer_handle *buffers); typedef rt_render_graph_builder rt_create_render_graph_builder_fn(void); typedef void rt_destroy_render_graph_builder_fn(rt_render_graph_builder *builder); typedef rt_result rt_execute_render_graph_fn(rt_render_graph *rgraph); +typedef void +rt_submit_render_view_fn(rt_render_graph *render_graph, uint32_t pass_id, rt_render_view view); +typedef void rt_reset_render_graph_fn(rt_render_graph *graph); typedef void rt_cmd_begin_pass_fn(rt_command_buffer_handle cmdbuf, const rt_cmd_begin_pass_info *info); @@ -301,7 +315,8 @@ typedef void rt_cmd_bind_vertex_buffers_fn(rt_command_buffer_handle cmd, uint32_t count, const rt_buffer_handle *buffers, const uint64_t *offsets); -typedef void rt_cmd_draw_fn(rt_command_buffer_handle cmdbuf, uint32_t first_vertex, uint32_t vertex_count); +typedef void +rt_cmd_draw_fn(rt_command_buffer_handle cmdbuf, uint32_t first_vertex, uint32_t vertex_count); typedef struct { rt_register_renderer_cvars_fn *RegisterCVars; @@ -321,6 +336,8 @@ typedef struct { rt_create_render_graph_builder_fn *CreateRenderGraphBuilder; rt_destroy_render_graph_builder_fn *DestroyRenderGraphBuilder; rt_execute_render_graph_fn *ExecuteRenderGraph; + rt_submit_render_view_fn *SubmitRenderView; + rt_reset_render_graph_fn *ResetRenderGraph; /* Command Buffer Functions */ rt_cmd_begin_pass_fn *CmdBeginPass; diff --git a/src/renderer/common/common_render_graph.h b/src/renderer/common/common_render_graph.h index 95730b8..fe3b117 100644 --- a/src/renderer/common/common_render_graph.h +++ b/src/renderer/common/common_render_graph.h @@ -23,6 +23,8 @@ typedef struct { rt_rgb_require_explicit_synchronization_fn *RequireExplicitSynchronization; } rt_render_graph_builder_platform_callbacks; +#define RT_MAX_SUBMITTED_VIEWS_PER_PASS 32 + typedef struct { uint32_t flags; @@ -53,6 +55,11 @@ typedef struct { rt_execute_render_pass_fn *Execute; void *user_data; + /* Runtime data. */ + rt_render_view submitted_views[RT_MAX_SUBMITTED_VIEWS_PER_PASS]; + uint32_t submitted_view_count; + + /* These refer to the semaphores array */ uint32_t first_wait; uint32_t wait_count; diff --git a/src/renderer/dx11/render_graph.cpp b/src/renderer/dx11/render_graph.cpp index a77a560..cdcddb2 100644 --- a/src/renderer/dx11/render_graph.cpp +++ b/src/renderer/dx11/render_graph.cpp @@ -1,3 +1,4 @@ +#include "gfx/render_view.h" #include "gfx/renderer_api.h" #include "renderer/common/common_render_graph.h" @@ -26,6 +27,28 @@ extern "C" void RT_RENDERER_API_FN(DestroyRenderGraphBuilder)(rt_render_graph_bu rtDestroyRenderGraphBuilder(builder); } +extern "C" void RT_RENDERER_API_FN(SubmitRenderView)(rt_render_graph *render_graph, + uint32_t pass_id, + rt_render_view view) { + for (uint32_t i = 0; i < render_graph->pass_count; ++i) { + if (render_graph->passes[i].id == pass_id) { + rt_render_pass *pass = &render_graph->passes[i]; + if (!RT_VERIFY(pass->submitted_view_count < RT_MAX_SUBMITTED_VIEWS_PER_PASS)) + return; + pass->submitted_views[pass->submitted_view_count++] = view; + } + } +} + +extern "C" void RT_RENDERER_API_FN(ResetRenderGraph)(rt_render_graph *graph) { + for (uint32_t i = 0; i < graph->pass_count; ++i) { +#ifdef RT_DEBUG + memset(graph->passes[i].submitted_views, 0, sizeof(graph->passes[i].submitted_views)); +#endif + graph->passes[i].submitted_view_count = 0; + } +} + static rt_result ExecutePass(rt_render_pass *pass, rt_command_buffer_handle cmdbuf_handle) { rt_command_buffer *cmd = rtGetCommandBuffer(cmdbuf_handle); if (!RT_VERIFY(cmd)) @@ -143,7 +166,8 @@ extern "C" rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *ren } else { // NOTE(Kevin): The most flexible solution would probably be a fullscreen tri draw // that implements a blit. - // Another idea would be a compute shader that does a copy&filter but that requires more work + // Another idea would be a compute shader that does a copy&filter but that requires more + // work RT_NOT_IMPLEMENTED; } diff --git a/src/renderer/null/null.c b/src/renderer/null/null.c index 20e3747..fdc6bc6 100644 --- a/src/renderer/null/null.c +++ b/src/renderer/null/null.c @@ -129,6 +129,18 @@ rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *render_graph) return RT_SUCCESS; } +void RT_RENDERER_API_FN(SubmitRenderView)(rt_render_graph *render_graph, + uint32_t pass_id, + rt_render_view view) { + RT_UNUSED(render_graph); + RT_UNUSED(pass_id); + RT_UNUSED(view); +} + +void RT_RENDERER_API_FN(ResetRenderGraph)(rt_render_graph *graph) { + RT_UNUSED(graph); +} + void RT_RENDERER_API_FN(CmdBindPipeline)(rt_command_buffer_handle cmdhandle, rt_pipeline_handle pipeline_handle) { } diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 98765be..bf198aa 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -130,7 +130,7 @@ RT_DLLEXPORT int rtAssertHandler(const char *expr, const char *msg, const char * // Asserts if p is "false", evaluates to p // NOTE that this will evaluate p multiple times! #define RT_VERIFY(p) \ - ((!p) ? (rtAssertHandler(#p, "Verify failed", __FILE__, __LINE__), p) : p) + ((!(p)) ? (rtAssertHandler(#p, "Verify failed", __FILE__, __LINE__), p) : p) #else #define RT_ASSERT(x, msg) RT_UNUSED(x)