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.
This commit is contained in:
Kevin Trogant 2024-05-07 08:12:45 +02:00
parent 6052f35485
commit 5d988d15b7
10 changed files with 217 additions and 13 deletions

View File

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

View File

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

View File

@ -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,

77
src/gfx/render_view.c Normal file
View File

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

39
src/gfx/render_view.h Normal file
View File

@ -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

View File

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

View File

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

View File

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

View File

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

View File

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