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_render_graph *_graph;
static rt_result ForwardPassExecute(rt_command_buffer_handle cmdbuf, static rt_result ForwardPassExecute(rt_command_buffer_handle cmdbuf,
const rt_render_list *lists, const rt_render_view *views,
uint32_t list_count, uint32_t view_count,
void *userdata) { void *userdata) {
return RT_SUCCESS; return RT_SUCCESS;
} }
@ -49,7 +49,10 @@ void Init(void) {
(rt_color){.r = 1.f, .g = 0.f, .b = 1.f, .a = 1.f}); (rt_color){.r = 1.f, .g = 0.f, .b = 1.f, .a = 1.f});
builder.SetBackbuffer(builder.obj, "backbuffer"); builder.SetBackbuffer(builder.obj, "backbuffer");
builder.BindRenderPass(builder.obj, "forward", ForwardPassExecute, NULL); 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); g_renderer.DestroyRenderGraphBuilder(&builder);
} }
@ -65,5 +68,6 @@ void Update(unsigned int frame_id) {
} }
void Render(unsigned int frame_id) { void Render(unsigned int frame_id) {
g_renderer.ResetRenderGraph(_graph);
g_renderer.ExecuteRenderGraph(_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", "Select the render backend. Available options: [vk, null], Default: vk",
"dx11"); "dx11");
extern rt_cvar rt_RenderViewArenaSize;
extern rt_cvar rt_RenderListPoolSize;
#ifdef RT_STATIC_LIB #ifdef RT_STATIC_LIB
extern void RT_RENDERER_API_FN(RegisterCVars)(void); extern void RT_RENDERER_API_FN(RegisterCVars)(void);
extern rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *); 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 rt_render_graph_builder RT_RENDERER_API_FN(CreateRenderGraphBuilder)(void);
extern void RT_RENDERER_API_FN(DestroyRenderGraphBuilder)(rt_render_graph_builder *); extern void RT_RENDERER_API_FN(DestroyRenderGraphBuilder)(rt_render_graph_builder *);
extern rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *); 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, extern void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle,
const rt_cmd_begin_pass_info *); 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 rt_result InitRenderLists(void);
extern void ShutdownRenderLists(void); extern void ShutdownRenderLists(void);
extern void ResetRenderLists(void); extern void ResetRenderLists(void);
extern rt_result InitRenderViews(void);
extern void ShutdownRenderViews(void);
extern void ResetRenderViews(void);
static bool LoadRenderer(void) { static bool LoadRenderer(void) {
@ -109,6 +119,8 @@ static bool LoadRenderer(void) {
RETRIEVE_SYMBOL(CreateRenderGrapbuilder, rt_create_render_graph_builder_fn); RETRIEVE_SYMBOL(CreateRenderGrapbuilder, rt_create_render_graph_builder_fn);
RETRIEVE_SYMBOL(DestroyRenderGraphBuilder, rt_destroy_render_graph_builder_fn); RETRIEVE_SYMBOL(DestroyRenderGraphBuilder, rt_destroy_render_graph_builder_fn);
RETRIEVE_SYMBOL(ExecuteRenderGraph, rt_execute_render_graph_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(CmdBeginPass, rt_cmd_begin_pass_fn);
RETRIEVE_SYMBOL(CmdEndPass, rt_cmd_end_pass_fn); RETRIEVE_SYMBOL(CmdEndPass, rt_cmd_end_pass_fn);
RETRIEVE_SYMBOL(CmdTransitionRenderTarget, rt_cmd_transition_render_target_fn); RETRIEVE_SYMBOL(CmdTransitionRenderTarget, rt_cmd_transition_render_target_fn);
@ -140,6 +152,8 @@ static bool LoadRenderer(void) {
g_renderer.CreateRenderGraphBuilder = &rtRenCreateRenderGraphBuilder; g_renderer.CreateRenderGraphBuilder = &rtRenCreateRenderGraphBuilder;
g_renderer.DestroyRenderGraphBuilder = &rtRenDestroyRenderGraphBuilder; g_renderer.DestroyRenderGraphBuilder = &rtRenDestroyRenderGraphBuilder;
g_renderer.ExecuteRenderGraph = &rtRenExecuteRenderGraph; g_renderer.ExecuteRenderGraph = &rtRenExecuteRenderGraph;
g_renderer.SubmitRenderView = &rtRenSubmitRenderView;
g_renderer.ResetRenderGraph = &rtRenResetRenderGraph;
g_renderer.CmdBeginPass = &rtRenCmdBeginPass; g_renderer.CmdBeginPass = &rtRenCmdBeginPass;
g_renderer.CmdEndPass = &rtRenCmdEndPass; g_renderer.CmdEndPass = &rtRenCmdEndPass;
g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget; g_renderer.CmdTransitionRenderTarget = &rtRenCmdTransitionRenderTarget;
@ -162,6 +176,8 @@ RT_DLLEXPORT void rtRegisterRendererCVars(void) {
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) { RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
rtRegisterCVAR(&rt_Renderer); rtRegisterCVAR(&rt_Renderer);
rtRegisterCVAR(&rt_RenderViewArenaSize);
rtRegisterCVAR(&rt_RenderListPoolSize);
if (!_renderer_loaded) { if (!_renderer_loaded) {
if (!LoadRenderer()) if (!LoadRenderer())
@ -177,10 +193,14 @@ RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
if ((result = InitRenderLists()) != RT_SUCCESS) if ((result = InitRenderLists()) != RT_SUCCESS)
return result; return result;
if ((result = InitRenderViews()) != RT_SUCCESS)
return result;
return result; return result;
} }
RT_DLLEXPORT void rtShutdownGFX(void) { RT_DLLEXPORT void rtShutdownGFX(void) {
ShutdownRenderViews();
ShutdownRenderLists(); ShutdownRenderLists();
g_renderer.Shutdown(); g_renderer.Shutdown();
} }
@ -192,4 +212,5 @@ RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) {
RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) { RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) {
g_renderer.EndFrame(frame_id); g_renderer.EndFrame(frame_id);
ResetRenderLists(); ResetRenderLists();
ResetRenderViews();
} }

View File

@ -6,11 +6,14 @@ gfx_lib = library('rtgfx',
'gfx.h', 'gfx.h',
'renderer_api.h', 'renderer_api.h',
'render_list.h', 'render_list.h',
'render_view.h',
'builtin_objects.c', 'builtin_objects.c',
'effect.c', 'effect.c',
'gfx_main.c', 'gfx_main.c',
'render_list.c', 'render_list.c',
'render_view.c',
# Contrib Sources # Contrib Sources
dependencies : gfx_deps, dependencies : gfx_deps,
include_directories : engine_incdir, 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 "gfx.h"
#include "render_list.h" #include "render_list.h"
#include "render_view.h"
#include "runtime/resources.h" #include "runtime/resources.h"
#include "runtime/rt_math.h" #include "runtime/rt_math.h"
@ -18,7 +19,7 @@ extern "C" {
/* Handles for backend objects */ /* 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_MAX_VERSION 255
#define RT_RENDER_BACKEND_HANDLE(name) \ #define RT_RENDER_BACKEND_HANDLE(name) \
@ -228,8 +229,8 @@ typedef struct {
enum { enum {
/* Bit 0 contains the type: 0 -> graphics, 1 -> compute */ /* Bit 0 contains the type: 0 -> graphics, 1 -> compute */
RT_PASS_FLAG_GRAPHICS = 0x0000, RT_PASS_FLAG_GRAPHICS = 0x0000,
RT_PASS_FLAG_COMPUTE = 0x0001, RT_PASS_FLAG_COMPUTE = 0x0001,
RT_PASS_FLAG_TYPE_MASK = RT_PASS_FLAG_COMPUTE | RT_PASS_FLAG_GRAPHICS, RT_PASS_FLAG_TYPE_MASK = RT_PASS_FLAG_COMPUTE | RT_PASS_FLAG_GRAPHICS,
/* Always excecute the pass, even if no objects will be rendered. */ /* Always excecute the pass, even if no objects will be rendered. */
@ -242,7 +243,10 @@ typedef struct {
} rt_pass_info; } rt_pass_info;
typedef struct rt_render_graph_s rt_render_graph; 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 { typedef struct {
void *obj; void *obj;
@ -252,7 +256,12 @@ typedef struct {
void (*SetBackbuffer)(void *obj, const char *rt_name); void (*SetBackbuffer)(void *obj, const char *rt_name);
void (*AddRenderPass)(void *obj, const rt_pass_info *info); 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 (*AddSampledInput)(void *obj, const char *pass_name, const char *rt_name);
void (*SetDepthStencilAttachment)(void *obj, void (*SetDepthStencilAttachment)(void *obj,
const char *pass_name, const char *pass_name,
@ -260,12 +269,14 @@ typedef struct {
rt_pass_load_mode load, rt_pass_load_mode load,
rt_pass_write_mode write, rt_pass_write_mode write,
rt_depth_stencil_value clear_value); 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_result (*Build)(void *obj, rt_render_graph **p_render_graph);
} rt_render_graph_builder; } rt_render_graph_builder;
typedef void rt_register_renderer_cvars_fn(void); typedef void rt_register_renderer_cvars_fn(void);
typedef rt_result rt_init_renderer_fn(const rt_renderer_init_info *info); typedef rt_result rt_init_renderer_fn(const rt_renderer_init_info *info);
typedef void rt_shutdown_renderer_fn(void); 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 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 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 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, typedef void rt_cmd_begin_pass_fn(rt_command_buffer_handle cmdbuf,
const rt_cmd_begin_pass_info *info); 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, uint32_t count,
const rt_buffer_handle *buffers, const rt_buffer_handle *buffers,
const uint64_t *offsets); 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 { typedef struct {
rt_register_renderer_cvars_fn *RegisterCVars; rt_register_renderer_cvars_fn *RegisterCVars;
@ -321,6 +336,8 @@ typedef struct {
rt_create_render_graph_builder_fn *CreateRenderGraphBuilder; rt_create_render_graph_builder_fn *CreateRenderGraphBuilder;
rt_destroy_render_graph_builder_fn *DestroyRenderGraphBuilder; rt_destroy_render_graph_builder_fn *DestroyRenderGraphBuilder;
rt_execute_render_graph_fn *ExecuteRenderGraph; rt_execute_render_graph_fn *ExecuteRenderGraph;
rt_submit_render_view_fn *SubmitRenderView;
rt_reset_render_graph_fn *ResetRenderGraph;
/* Command Buffer Functions */ /* Command Buffer Functions */
rt_cmd_begin_pass_fn *CmdBeginPass; rt_cmd_begin_pass_fn *CmdBeginPass;

View File

@ -23,6 +23,8 @@ typedef struct {
rt_rgb_require_explicit_synchronization_fn *RequireExplicitSynchronization; rt_rgb_require_explicit_synchronization_fn *RequireExplicitSynchronization;
} rt_render_graph_builder_platform_callbacks; } rt_render_graph_builder_platform_callbacks;
#define RT_MAX_SUBMITTED_VIEWS_PER_PASS 32
typedef struct { typedef struct {
uint32_t flags; uint32_t flags;
@ -53,6 +55,11 @@ typedef struct {
rt_execute_render_pass_fn *Execute; rt_execute_render_pass_fn *Execute;
void *user_data; 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 */ /* These refer to the semaphores array */
uint32_t first_wait; uint32_t first_wait;
uint32_t wait_count; uint32_t wait_count;

View File

@ -1,3 +1,4 @@
#include "gfx/render_view.h"
#include "gfx/renderer_api.h" #include "gfx/renderer_api.h"
#include "renderer/common/common_render_graph.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); 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) { static rt_result ExecutePass(rt_render_pass *pass, rt_command_buffer_handle cmdbuf_handle) {
rt_command_buffer *cmd = rtGetCommandBuffer(cmdbuf_handle); rt_command_buffer *cmd = rtGetCommandBuffer(cmdbuf_handle);
if (!RT_VERIFY(cmd)) if (!RT_VERIFY(cmd))
@ -143,7 +166,8 @@ extern "C" rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *ren
} else { } else {
// NOTE(Kevin): The most flexible solution would probably be a fullscreen tri draw // NOTE(Kevin): The most flexible solution would probably be a fullscreen tri draw
// that implements a blit. // 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; RT_NOT_IMPLEMENTED;
} }

View File

@ -129,6 +129,18 @@ rt_result RT_RENDERER_API_FN(ExecuteRenderGraph)(rt_render_graph *render_graph)
return RT_SUCCESS; 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, void RT_RENDERER_API_FN(CmdBindPipeline)(rt_command_buffer_handle cmdhandle,
rt_pipeline_handle pipeline_handle) { 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 // Asserts if p is "false", evaluates to p
// NOTE that this will evaluate p multiple times! // NOTE that this will evaluate p multiple times!
#define RT_VERIFY(p) \ #define RT_VERIFY(p) \
((!p) ? (rtAssertHandler(#p, "Verify failed", __FILE__, __LINE__), p) : p) ((!(p)) ? (rtAssertHandler(#p, "Verify failed", __FILE__, __LINE__), p) : p)
#else #else
#define RT_ASSERT(x, msg) RT_UNUSED(x) #define RT_ASSERT(x, msg) RT_UNUSED(x)