Progress towards rendering with effects
- Added a null renderer to simplify testing
This commit is contained in:
parent
efd1f5f983
commit
3d0d4169f1
@ -1,5 +1,4 @@
|
||||
optimization speed;
|
||||
|
||||
passes {
|
||||
pass0 {
|
||||
vertex {
|
@ -1,5 +0,0 @@
|
||||
passes {
|
||||
pass0 {
|
||||
pipeline test/shader/static_object.pipeline;
|
||||
}
|
||||
}
|
@ -83,6 +83,8 @@ engine_link_libs = []
|
||||
if get_option('default_library') == 'static'
|
||||
if get_option('static_renderer') == 'vk'
|
||||
engine_link_libs = [runtime_lib, gfx_lib, app_lib, vk_renderer_lib]
|
||||
elif get_option('static_renderer') == 'null'
|
||||
engine_link_libs = [runtime_lib, gfx_lib, app_lib, null_renderer_lib]
|
||||
else
|
||||
error('Invalid static_renderer option ', get_option('static_renderer'))
|
||||
endif
|
||||
|
@ -36,6 +36,10 @@ RT_DLLEXPORT int rtWin32Entry(HINSTANCE hInstance,
|
||||
if (rtInitRuntime() != RT_SUCCESS)
|
||||
return 1;
|
||||
|
||||
rtRegisterCVAR(&rt_Fullscreen);
|
||||
rtRegisterCVAR(&rt_WindowWidth);
|
||||
rtRegisterCVAR(&rt_WindowHeight);
|
||||
|
||||
rtRegisterRendererCVars();
|
||||
|
||||
if (app_callbacks.RegisterCVars)
|
||||
|
@ -4,6 +4,10 @@
|
||||
#include "runtime/runtime.h"
|
||||
#include "runtime/threading.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void rt_main_loop_update_fn(unsigned int frame_id);
|
||||
typedef void rt_main_loop_render_fn(unsigned int frame_id);
|
||||
|
||||
@ -33,4 +37,8 @@ RT_DLLEXPORT rt_result rtInitMainLoop(rt_main_loop_update_fn *update_cb,
|
||||
|
||||
RT_DLLEXPORT void rtShutdownMainLoop(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -63,11 +63,11 @@ static rt_asset_db _asset_db;
|
||||
|
||||
static rt_processing_queue _processing_queue;
|
||||
|
||||
extern RT_ASSET_PROCESSOR_FN(PipelineProcessor);
|
||||
extern RT_ASSET_PROCESSOR_FN(EffectProcessor);
|
||||
extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
|
||||
|
||||
static rt_asset_processor _processors[] = {
|
||||
{ .file_ext = ".pipeline", .proc = PipelineProcessor},
|
||||
{ .file_ext = ".effect", .proc = EffectProcessor},
|
||||
{.file_ext = ".framegraph", .proc = FramegraphProcessor},
|
||||
};
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#include "gfx/effect.h"
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
#include <assert.h>
|
||||
@ -35,6 +36,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
unsigned int pass_count;
|
||||
rt_parsed_pipeline_data pipelines[RT_MAX_SUBRESOURCES];
|
||||
rt_render_pass_id pass_ids[RT_MAX_SUBRESOURCES];
|
||||
} rt_parsed_effect_data;
|
||||
|
||||
enum {
|
||||
@ -336,6 +338,7 @@ static rt_result ParseEffect(rt_file_id fid,
|
||||
file_path);
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
effect->pass_count = passes_list->count;
|
||||
const rt_parsed_stmt *pass_stmt = &state.statements[passes_list->first];
|
||||
for (unsigned int i = 0; i < passes_list->count;
|
||||
++i, pass_stmt = &state.statements[pass_stmt->next]) {
|
||||
@ -347,6 +350,9 @@ static rt_result ParseEffect(rt_file_id fid,
|
||||
file_path);
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
effect->pass_ids[i] =
|
||||
rtCalculateRenderPassID(pass_stmt->attribute.start, pass_stmt->attribute.length);
|
||||
|
||||
result = ParsePipeline(&state,
|
||||
pass_stmt->list_index,
|
||||
file_path,
|
||||
@ -360,7 +366,7 @@ static rt_result ParseEffect(rt_file_id fid,
|
||||
return result;
|
||||
}
|
||||
|
||||
RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
|
||||
RT_ASSET_PROCESSOR_FN(EffectProcessor) {
|
||||
rt_loaded_asset asset = LoadAsset(file);
|
||||
if (!asset.buffer)
|
||||
return RT_UNKNOWN_ERROR;
|
||||
@ -371,7 +377,21 @@ RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
|
||||
if (result != RT_SUCCESS)
|
||||
goto out;
|
||||
|
||||
rt_effect_info effect_info;
|
||||
effect_info.pass_count = effect.pass_count;
|
||||
|
||||
rt_resource effect_resource = {0};
|
||||
effect_resource.data = &effect_info;
|
||||
effect_resource.type = RT_RESOURCE_EFFECT;
|
||||
effect_resource.subresource_count = effect.pass_count;
|
||||
|
||||
*new_resource_count = 0;
|
||||
|
||||
const char *name = rtGetFilePath(file);
|
||||
for (unsigned int i = 0; i < effect.pass_count; ++i) {
|
||||
effect_info.passes[i].pass_id = effect.pass_ids[i];
|
||||
effect_info.passes[i].pipeline = RT_INVALID_RESOURCE_ID;
|
||||
|
||||
rt_parsed_pipeline_data pipeline;
|
||||
memcpy(&pipeline, &effect.pipelines[i], sizeof(pipeline));
|
||||
|
||||
@ -407,14 +427,27 @@ RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
|
||||
? shader_resources[pipeline.compute_shader]
|
||||
: RT_INVALID_RESOURCE_ID;
|
||||
rt_resource_id pipeline_id;
|
||||
const char *name = rtGetFilePath(file);
|
||||
result = rtCreateResources(1, &name, &pipeline_resource, &pipeline_id);
|
||||
char pipeline_name[260];
|
||||
rtSPrint(pipeline_name, sizeof(pipeline_name), "%s:%u", name, i);
|
||||
|
||||
char *ppln = &pipeline_name[0];
|
||||
|
||||
result = rtCreateResources(1, &ppln, &pipeline_resource, &pipeline_id);
|
||||
if (result == RT_SUCCESS) {
|
||||
new_resources[0] = pipeline_id;
|
||||
memcpy(&new_resources[1], shader_resources, sizeof(shader_resources));
|
||||
*new_resource_count = 1 + pipeline.shader_count;
|
||||
new_resources[i] = pipeline_id;
|
||||
memcpy(&new_resources[i + 1], shader_resources, sizeof(shader_resources));
|
||||
*new_resource_count += 1 + pipeline.shader_count;
|
||||
effect_resource.subresources[i] = pipeline_id;
|
||||
effect_info.passes[i].pipeline = pipeline_id;
|
||||
}
|
||||
}
|
||||
|
||||
rt_resource_id effect_id = 0;
|
||||
result = rtCreateResources(1, &name, &effect_resource, &effect_id);
|
||||
if (result == RT_SUCCESS) {
|
||||
new_resources[*new_resource_count] = effect_id;
|
||||
*new_resource_count += 1;
|
||||
}
|
||||
out:
|
||||
rtLog("AC", "Released %p", asset.buffer);
|
||||
rtReleaseBuffer(asset.buffer, asset.size);
|
||||
|
@ -9,17 +9,23 @@
|
||||
#include "gfx.h"
|
||||
#include "runtime/resources.h"
|
||||
|
||||
typedef struct {
|
||||
/* Id of the render pass during which this effect pass is run. */
|
||||
rt_render_pass_id pass_id;
|
||||
|
||||
typedef struct rt_pipeline_info_s {
|
||||
rt_resource_id vertex_shader;
|
||||
rt_resource_id fragment_shader;
|
||||
rt_resource_id compute_shader;
|
||||
|
||||
/* TODO(Kevin): Fixed function settings */
|
||||
} rt_pipeline_info;
|
||||
|
||||
typedef struct {
|
||||
/* Id of the render pass during which this effect pass is run. */
|
||||
rt_render_pass_id pass_id;
|
||||
rt_resource_id pipeline;
|
||||
} rt_effect_pass_info;
|
||||
|
||||
typedef struct {
|
||||
|
||||
uint32_t pass_count;
|
||||
rt_effect_pass_info passes[RT_MAX_SUBRESOURCES];
|
||||
} rt_effect_info;
|
||||
|
||||
#endif
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
rt_renderer_api g_renderer;
|
||||
extern rt_cvar rt_MaxFramegraphs;
|
||||
|
||||
#ifndef RT_STATIC_LIB
|
||||
static rt_dynlib _renderer_lib;
|
||||
@ -22,7 +23,7 @@ static rt_dynlib _renderer_lib;
|
||||
static bool _renderer_loaded = false;
|
||||
|
||||
RT_DLLEXPORT
|
||||
RT_CVAR_S(rt_Renderer, "Select the render backend. Available options: [vk], Default: vk", "vk");
|
||||
RT_CVAR_S(rt_Renderer, "Select the render backend. Available options: [vk, null], Default: vk", "vk");
|
||||
|
||||
#ifdef RT_STATIC_LIB
|
||||
extern void RT_RENDERER_API_FN(RegisterCVars)(void);
|
||||
@ -58,6 +59,9 @@ extern void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_hand
|
||||
|
||||
extern rt_result InitFramegraphManager(void);
|
||||
extern void ShutdownFramegraphManager(void);
|
||||
extern rt_result InitRenderLists(void);
|
||||
extern void ShutdownRenderLists(void);
|
||||
extern void ResetRenderLists(void);
|
||||
|
||||
static bool LoadRenderer(void) {
|
||||
|
||||
@ -140,6 +144,9 @@ RT_DLLEXPORT void rtRegisterRendererCVars(void) {
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
|
||||
rtRegisterCVAR(&rt_Renderer);
|
||||
rtRegisterCVAR(&rt_MaxFramegraphs);
|
||||
|
||||
if (!_renderer_loaded) {
|
||||
if (!LoadRenderer())
|
||||
return RT_UNKNOWN_ERROR;
|
||||
@ -154,10 +161,14 @@ RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
|
||||
if ((result = InitFramegraphManager()) != RT_SUCCESS)
|
||||
return result;
|
||||
|
||||
if ((result = InitRenderLists()) != RT_SUCCESS)
|
||||
return result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
RT_DLLEXPORT void rtShutdownGFX(void) {
|
||||
ShutdownRenderLists();
|
||||
ShutdownFramegraphManager();
|
||||
g_renderer.Shutdown();
|
||||
}
|
||||
@ -168,4 +179,5 @@ RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) {
|
||||
|
||||
RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) {
|
||||
g_renderer.EndFrame(frame_id);
|
||||
ResetRenderLists();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ gfx_lib = library('rtgfx',
|
||||
|
||||
'gfx_framegraph.c',
|
||||
'gfx_main.c',
|
||||
'render_list.c',
|
||||
# Contrib Sources
|
||||
dependencies : gfx_deps,
|
||||
include_directories : engine_incdir,
|
||||
|
@ -1,4 +1,11 @@
|
||||
/* Stdlib */
|
||||
#include <stdint.h>
|
||||
|
||||
/* Project */
|
||||
#include "gfx.h"
|
||||
|
||||
/* Commonly used runtime headers */
|
||||
#include "runtime/runtime.h"
|
||||
#include "runtime/threading.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/config.h"
|
||||
|
171
src/gfx/render_list.c
Normal file
171
src/gfx/render_list.c
Normal file
@ -0,0 +1,171 @@
|
||||
#include "render_list.h"
|
||||
|
||||
#include "runtime/threading.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
RT_CVAR_I(rt_RenderListPoolSize,
|
||||
"Size of the pool allocated for render lists in bytes. Default: 8 MiB",
|
||||
RT_MB(8));
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
const char *name;
|
||||
} rt_render_object_type_data;
|
||||
|
||||
typedef struct rt_list_pool_s {
|
||||
size_t capacity;
|
||||
struct rt_list_pool_s *next;
|
||||
} rt_list_pool;
|
||||
|
||||
#define DEFAULT_LIST_CAPACITY RT_KB(1)
|
||||
|
||||
static rt_render_object_type_data _types[RT_MAX_RENDER_OBJECT_TYPE + 1];
|
||||
static unsigned int _type_count = 0;
|
||||
static rt_rwlock _type_lock;
|
||||
|
||||
static rt_arena _list_arena;
|
||||
static rt_list_pool *_first_free_list;
|
||||
static rt_mutex *_list_lock;
|
||||
|
||||
rt_result InitRenderLists(void) {
|
||||
rt_create_rwlock_result lock_res = rtCreateRWLock();
|
||||
if (!lock_res.ok)
|
||||
return RT_UNKNOWN_ERROR;
|
||||
_type_lock = lock_res.lock;
|
||||
|
||||
rt_create_arena_result arena_res = rtCreateArena(NULL, (size_t)rt_RenderListPoolSize.i);
|
||||
if (!arena_res.ok) {
|
||||
rtDestroyRWLock(&_type_lock);
|
||||
return RT_OUT_OF_MEMORY;
|
||||
}
|
||||
_list_arena = arena_res.arena;
|
||||
|
||||
_list_lock = rtCreateMutex();
|
||||
if (!_list_lock) {
|
||||
rtReleaseArena(&_list_arena);
|
||||
rtDestroyRWLock(&_type_lock);
|
||||
}
|
||||
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void ShutdownRenderLists(void) {
|
||||
rtDestroyRWLock(&_type_lock);
|
||||
rtDestroyMutex(_list_lock);
|
||||
rtReleaseArena(&_list_arena);
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_render_object_type rtRegisterRenderObjectType(size_t object_size,
|
||||
const char *debug_name) {
|
||||
if (_type_count == RT_MAX_RENDER_OBJECT_TYPE) {
|
||||
rtReportError("GFX", "Too many render object types (max is %u)", RT_MAX_RENDER_OBJECT_TYPE);
|
||||
return RT_INVALID_RENDER_OBJECT_TYPE;
|
||||
}
|
||||
rtLockWrite(&_type_lock);
|
||||
rt_render_object_type type = (rt_render_object_type)++_type_count;
|
||||
_types[_type_count].size = object_size;
|
||||
_types[_type_count].name = debug_name;
|
||||
if (debug_name)
|
||||
rtLog("GFX",
|
||||
"Registered render object type %s; object size: %zu. Type: %u",
|
||||
debug_name,
|
||||
object_size,
|
||||
_type_count);
|
||||
else
|
||||
rtLog("GFX",
|
||||
"Registered unnamed render object type; object size: %zu. Type: %u",
|
||||
object_size,
|
||||
_type_count);
|
||||
rtUnlockWrite(&_type_lock);
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
RT_DLLEXPORT size_t rtGetRenderObjectSize(rt_render_object_type type) {
|
||||
size_t size = 0;
|
||||
rtLockRead(&_type_lock);
|
||||
if (type > RT_INVALID_RENDER_OBJECT_TYPE && type <= _type_count)
|
||||
size = _types[type].size;
|
||||
rtUnlockRead(&_type_lock);
|
||||
return size;
|
||||
}
|
||||
|
||||
RT_DLLEXPORT const char *rtGetRenderObjectTypeDebugName(rt_render_object_type type) {
|
||||
const char *name = NULL;
|
||||
rtLockRead(&_type_lock);
|
||||
if (type > RT_INVALID_RENDER_OBJECT_TYPE && type <= _type_count)
|
||||
name = _types[type].name;
|
||||
rtUnlockRead(&_type_lock);
|
||||
return name;
|
||||
}
|
||||
|
||||
static rt_create_render_list_result CreateNewList(rt_render_object_type type, size_t capacity) {
|
||||
rt_create_render_list_result res = {.ok = false};
|
||||
rtLockMutex(_list_lock);
|
||||
|
||||
if (!_first_free_list || _first_free_list->capacity < capacity) { /* Allocate a new list */
|
||||
rt_list_pool *pool =
|
||||
rtArenaPush(&_list_arena, sizeof(rt_list_pool) + capacity);
|
||||
if (!pool) {
|
||||
rtReportError("GFX",
|
||||
"Out of render list pool space! Configured space: %d kiB",
|
||||
rt_RenderListPoolSize.i / 1024);
|
||||
goto out;
|
||||
}
|
||||
pool->capacity = capacity;
|
||||
pool->next = _first_free_list;
|
||||
_first_free_list = pool;
|
||||
}
|
||||
rt_render_list list;
|
||||
list.data = (char *)_first_free_list + sizeof(rt_list_pool);
|
||||
list.type = type;
|
||||
list.length = 0;
|
||||
res.ok = true;
|
||||
res.list = list;
|
||||
_first_free_list = _first_free_list->next;
|
||||
out:
|
||||
rtUnlockMutex(_list_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
RT_DLLEXPORT rt_create_render_list_result rtCreateRenderList(rt_render_object_type type) {
|
||||
return CreateNewList(type, DEFAULT_LIST_CAPACITY);
|
||||
}
|
||||
|
||||
void ResetRenderLists(void) {
|
||||
rtLockMutex(_list_lock);
|
||||
_first_free_list = NULL;
|
||||
rtArenaClear(&_list_arena);
|
||||
rtUnlockMutex(_list_lock);
|
||||
}
|
||||
|
||||
RT_DLLEXPORT bool rtPushRenderListEntry(rt_render_list *list, const void *object) {
|
||||
size_t object_size = rtGetRenderObjectSize(list->type);
|
||||
rt_list_pool *pool = (rt_list_pool *)((char *)list->data - sizeof(rt_list_pool));
|
||||
size_t list_capacity = pool->capacity / object_size;
|
||||
|
||||
if (list->length == list_capacity) {
|
||||
/* "Grow" the list */
|
||||
rt_create_render_list_result list_res = CreateNewList(list->type, pool->capacity * 2);
|
||||
if (!list_res.ok)
|
||||
return false;
|
||||
|
||||
memcpy(list_res.list.data, list->data, list->length * object_size);
|
||||
|
||||
rtLockMutex(_list_lock);
|
||||
pool->next = _first_free_list;
|
||||
_first_free_list = pool;
|
||||
rtUnlockMutex(_list_lock);
|
||||
|
||||
list_res.list.length = list->length;
|
||||
*list = list_res.list;
|
||||
}
|
||||
|
||||
char *dst = (char *)list->data + list->length * object_size;
|
||||
memcpy(dst, object, object_size);
|
||||
++list->length;
|
||||
return true;
|
||||
}
|
@ -1,4 +1,70 @@
|
||||
#ifndef RT_RENDER_LIST_H
|
||||
#define RT_RENDER_LIST_H
|
||||
|
||||
/* a render list collects render objects. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Identifies a type of render objects. */
|
||||
typedef uint32_t rt_render_object_type;
|
||||
typedef uint32_t rt_render_object_type_mask;
|
||||
|
||||
enum {
|
||||
RT_INVALID_RENDER_OBJECT_TYPE = 0,
|
||||
RT_MAX_RENDER_OBJECT_TYPE = 32,
|
||||
};
|
||||
|
||||
#define RT_RENDER_OBJECT_TYPE_BIT(type) (1u << ((type)-1))
|
||||
|
||||
/* Registers a new render object type.
|
||||
* debug_name is optional and may be NULL.
|
||||
*/
|
||||
RT_DLLEXPORT rt_render_object_type rtRegisterRenderObjectType(size_t object_size,
|
||||
const char *debug_name);
|
||||
|
||||
RT_DLLEXPORT size_t rtGetRenderObjectSize(rt_render_object_type type);
|
||||
|
||||
RT_DLLEXPORT const char *rtGetRenderObjectTypeDebugName(rt_render_object_type type);
|
||||
|
||||
typedef struct {
|
||||
rt_render_object_type type;
|
||||
size_t length;
|
||||
void *data;
|
||||
} rt_render_list;
|
||||
|
||||
/* Returns a pointer to the i-th render list element.
|
||||
* Works for every valid type, because the size is determined at runtime. */
|
||||
RT_INLINE void *rtGetRenderListElement(const rt_render_list *list, size_t index) {
|
||||
size_t size = rtGetRenderObjectSize(list->type);
|
||||
return (char *)list->data + size * index;
|
||||
}
|
||||
|
||||
/* Returns the i-th render list element, cast to type T.
|
||||
* Saves a rtGetRenderObjectSize call, if the type is known beforehand. */
|
||||
#define RT_GET_RENDER_LIST_ELEMENT(list, T, index) *(((T *)(list).data) + (index))
|
||||
|
||||
typedef struct {
|
||||
bool ok;
|
||||
rt_render_list list;
|
||||
} rt_create_render_list_result;
|
||||
|
||||
/* Create a render list for a particular object type.
|
||||
*
|
||||
* Render Lists have a lifetime of one frame. */
|
||||
RT_DLLEXPORT rt_create_render_list_result rtCreateRenderList(rt_render_object_type type);
|
||||
|
||||
/* Append a render object to a list. The object must be of the correct type. */
|
||||
RT_DLLEXPORT bool rtPushRenderListEntry(rt_render_list *list, const void *object);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -17,6 +17,7 @@ extern "C" {
|
||||
|
||||
/* Handles for backend objects */
|
||||
|
||||
#define RT_RENDERER_BACKEND_HANDLE_MAX_INDEX ((1u<<24)-1)
|
||||
#define RT_RENDER_BACKEND_HANDLE_MAX_VERSION 255
|
||||
|
||||
#define RT_RENDER_BACKEND_HANDLE(name) \
|
||||
@ -59,13 +60,6 @@ typedef enum {
|
||||
RT_TRANSFER_QUEUE,
|
||||
} rt_gpu_queue;
|
||||
|
||||
|
||||
typedef struct {
|
||||
rt_resource_id vertex_shader;
|
||||
rt_resource_id fragment_shader;
|
||||
rt_resource_id compute_shader;
|
||||
} rt_pipeline_info;
|
||||
|
||||
#if 0
|
||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
|
||||
* For example, an attribute might be bound to "CELL_GRID", which would be
|
||||
@ -182,6 +176,8 @@ typedef enum {
|
||||
|
||||
/* Renderer API */
|
||||
|
||||
typedef struct rt_pipeline_info_s rt_pipeline_info;
|
||||
|
||||
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);
|
||||
|
@ -5,3 +5,4 @@ subdir('app_framework')
|
||||
|
||||
# Renderer libs
|
||||
subdir('renderer/vk')
|
||||
subdir('renderer/null')
|
||||
|
10
src/renderer/null/meson.build
Normal file
10
src/renderer/null/meson.build
Normal file
@ -0,0 +1,10 @@
|
||||
null_renderer_lib = library('rtnull',
|
||||
'null.c',
|
||||
# Project Sources
|
||||
include_directories : engine_incdir,
|
||||
link_with : runtime_lib,
|
||||
install : true)
|
||||
|
||||
engine_libs += null_renderer_lib
|
||||
engine_lib_paths += null_renderer_lib.full_path()
|
||||
|
122
src/renderer/null/null.c
Normal file
122
src/renderer/null/null.c
Normal file
@ -0,0 +1,122 @@
|
||||
/* "Null" renderer implementation.
|
||||
* Useful for headless testing */
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#define RETURN_HANDLE_STUB2(type, initial) \
|
||||
static unsigned int s_next = (initial); \
|
||||
return (type) { .index = (s_next++) % RT_RENDERER_BACKEND_HANDLE_MAX_INDEX, .version = 1 }
|
||||
|
||||
#define RETURN_HANDLE_STUB(type) RETURN_HANDLE_STUB2(type, 1)
|
||||
|
||||
#define RETURN_HANDLE_ARRAY_STUB2(out, count, initial) \
|
||||
static unsigned int s_next = (initial); \
|
||||
for (uint32_t i = 0; i < (count); ++i) { \
|
||||
(out)[i].index = (s_next++) % RT_RENDERER_BACKEND_HANDLE_MAX_INDEX; \
|
||||
(out)[i].version = 1; \
|
||||
}
|
||||
|
||||
#define RETURN_HANDLE_ARRAY_STUB(out, count) RETURN_HANDLE_ARRAY_STUB2(out, count, 1)
|
||||
|
||||
void RT_RENDERER_API_FN(RegisterCVars)(void) {
|
||||
}
|
||||
|
||||
rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
|
||||
RT_UNUSED(info);
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(Shutdown)(void) {
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(BeginFrame)(unsigned int frame_id) {
|
||||
RT_UNUSED(frame_id);
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(EndFrame)(unsigned int frame_id) {
|
||||
RT_UNUSED(frame_id);
|
||||
}
|
||||
|
||||
rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
|
||||
RT_UNUSED(info);
|
||||
RETURN_HANDLE_STUB(rt_pipeline_handle);
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
|
||||
RT_UNUSED(handle);
|
||||
}
|
||||
|
||||
rt_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_target_info *info) {
|
||||
RT_UNUSED(info);
|
||||
RETURN_HANDLE_STUB2(rt_render_target_handle, 2);
|
||||
}
|
||||
|
||||
rt_render_target_handle RT_RENDERER_API_FN(GetSwapchainRenderTarget)(void) {
|
||||
return (rt_render_target_handle){.index = 1, .version = 1};
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(DestroyRenderTarget)(rt_render_target_handle handle) {
|
||||
RT_UNUSED(handle);
|
||||
}
|
||||
|
||||
rt_result RT_RENDERER_API_FN(AllocCommandBuffers)(uint32_t count,
|
||||
const rt_alloc_command_buffer_info *info,
|
||||
rt_command_buffer_handle *p_command_buffers) {
|
||||
RT_UNUSED(info);
|
||||
RETURN_HANDLE_ARRAY_STUB(p_command_buffers, count)
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
rt_result RT_RENDERER_API_FN(SubmitCommandBuffers)(rt_gpu_queue queue,
|
||||
const rt_submit_command_buffers_info *info) {
|
||||
RT_UNUSED(queue);
|
||||
RT_UNUSED(info);
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
|
||||
const rt_gpu_semaphore_info *info,
|
||||
rt_gpu_semaphore_handle *p_semaphores) {
|
||||
RT_UNUSED(info);
|
||||
RETURN_HANDLE_ARRAY_STUB2(p_semaphores, count, 3)
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(DestroySemaphores)(uint32_t count, rt_gpu_semaphore_handle *semaphores) {
|
||||
RT_UNUSED(count);
|
||||
RT_UNUSED(semaphores);
|
||||
}
|
||||
|
||||
/* NOTE(Kevin): It might become necessary to actually track the value, to correctly simulate gpu
|
||||
* behaviour */
|
||||
uint64_t RT_RENDERER_API_FN(GetSemaphoreValue)(rt_gpu_semaphore_handle sem) {
|
||||
RT_UNUSED(sem);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetSwapchainAvailableSemaphore)(void) {
|
||||
return (rt_gpu_semaphore_handle){.index = 1, .version = 1};
|
||||
}
|
||||
|
||||
rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) {
|
||||
return (rt_gpu_semaphore_handle){.index = 2, .version = 1};
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(CmdBeginPass)(rt_command_buffer_handle cmd,
|
||||
const rt_cmd_begin_pass_info *info) {
|
||||
RT_UNUSED(cmd);
|
||||
RT_UNUSED(info);
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(CmdEndPass)(rt_command_buffer_handle cmd) {
|
||||
RT_UNUSED(cmd);
|
||||
}
|
||||
|
||||
void RT_RENDERER_API_FN(CmdTransitionRenderTarget)(rt_command_buffer_handle cmd,
|
||||
rt_render_target_handle target,
|
||||
rt_render_target_state state) {
|
||||
RT_UNUSED(cmd);
|
||||
RT_UNUSED(target);
|
||||
RT_UNUSED(state);
|
||||
}
|
@ -40,7 +40,7 @@ if vk_dep.found()
|
||||
cpp_args : platform_defs,
|
||||
install : true)
|
||||
|
||||
engine_libs = vk_renderer_lib
|
||||
engine_libs += vk_renderer_lib
|
||||
engine_lib_paths += vk_renderer_lib.full_path()
|
||||
endif
|
||||
|
||||
|
@ -8,3 +8,12 @@
|
||||
#if defined(VY_USE_XLIB)
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
/* GFX */
|
||||
#include "gfx/gfx.h"
|
||||
|
||||
/* Commonly used runtime headers */
|
||||
#include "runtime/config.h"
|
||||
#include "runtime/mem_arena.h"
|
||||
#include "runtime/runtime.h"
|
||||
#include "runtime/threading.h"
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "runtime/threading.h"
|
||||
|
||||
#include "gfx/renderer_api.h"
|
||||
#include "gfx/effect.h"
|
||||
|
||||
#include "gpu.h"
|
||||
#include "pipelines.h"
|
||||
|
@ -4,10 +4,6 @@
|
||||
#include "file_tab.h"
|
||||
#include "buffer_manager.h"
|
||||
|
||||
extern rt_cvar rt_Renderer;
|
||||
extern rt_cvar rt_Fullscreen;
|
||||
extern rt_cvar rt_WindowWidth;
|
||||
extern rt_cvar rt_WindowHeight;
|
||||
extern rt_cvar rt_BufferMemoryBudget;
|
||||
extern rt_cvar rt_FileTabCapacity;
|
||||
extern rt_cvar rt_MaxConcurrentAsyncIO;
|
||||
@ -16,13 +12,8 @@ extern rt_cvar rt_ResourceCacheSize;
|
||||
extern rt_cvar rt_MaxCachedResources;
|
||||
extern rt_cvar rt_ResourceNamespaceSize;
|
||||
extern rt_cvar rt_DisableResourceNamespaceLoad;
|
||||
extern rt_cvar rt_MaxFramegraphs;
|
||||
|
||||
void RegisterRuntimeCVars(void) {
|
||||
rtRegisterCVAR(&rt_Renderer);
|
||||
rtRegisterCVAR(&rt_Fullscreen);
|
||||
rtRegisterCVAR(&rt_WindowWidth);
|
||||
rtRegisterCVAR(&rt_WindowHeight);
|
||||
rtRegisterCVAR(&rt_BufferMemoryBudget);
|
||||
rtRegisterCVAR(&rt_FileTabCapacity);
|
||||
rtRegisterCVAR(&rt_MaxConcurrentAsyncIO);
|
||||
@ -31,7 +22,6 @@ void RegisterRuntimeCVars(void) {
|
||||
rtRegisterCVAR(&rt_MaxCachedResources);
|
||||
rtRegisterCVAR(&rt_ResourceNamespaceSize);
|
||||
rtRegisterCVAR(&rt_DisableResourceNamespaceLoad);
|
||||
rtRegisterCVAR(&rt_MaxFramegraphs);
|
||||
}
|
||||
|
||||
extern void SetMainThreadId(void);
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "resources.h"
|
||||
#include "threading.h"
|
||||
|
||||
#include "gfx/effect.h"
|
||||
#include "gfx/renderer_api.h"
|
||||
|
||||
#include <assert.h>
|
||||
@ -92,13 +93,13 @@ typedef struct {
|
||||
|
||||
static size_t GetResourceDataSize(const rt_resource *resource) {
|
||||
switch (resource->type) {
|
||||
case RT_RESOURCE_PIPELINE:
|
||||
return sizeof(rt_pipeline_info);
|
||||
case RT_RESOURCE_SHADER: {
|
||||
/* Sizeof metadata + bytecode */
|
||||
const rt_shader_info *info = resource->data;
|
||||
return sizeof(rt_shader_info) + (info) ? info->bytecode_length : 0;
|
||||
} break;
|
||||
case RT_RESOURCE_PIPELINE:
|
||||
return sizeof(rt_pipeline_info);
|
||||
case RT_RESOURCE_FRAMEGRAPH: {
|
||||
const rt_framegraph_info *info = resource->data;
|
||||
size_t size = sizeof(*info) + sizeof(rt_render_target_info) * info->render_target_count +
|
||||
@ -110,6 +111,9 @@ static size_t GetResourceDataSize(const rt_resource *resource) {
|
||||
}
|
||||
return size;
|
||||
} break;
|
||||
case RT_RESOURCE_EFFECT: {
|
||||
return sizeof(rt_effect_info);
|
||||
} break;
|
||||
default:
|
||||
rtLog("RESMGR", "Tried to get size of an invalid resource type %u", resource->type);
|
||||
}
|
||||
@ -118,9 +122,6 @@ static size_t GetResourceDataSize(const rt_resource *resource) {
|
||||
|
||||
static void CopyResourceData(const rt_resource *resource, void *dest) {
|
||||
switch (resource->type) {
|
||||
case RT_RESOURCE_PIPELINE:
|
||||
memcpy(dest, resource->data, sizeof(rt_pipeline_info));
|
||||
break;
|
||||
case RT_RESOURCE_SHADER: {
|
||||
/* Sizeof metadata + bytecode */
|
||||
const rt_shader_info *info = resource->data;
|
||||
@ -129,6 +130,9 @@ static void CopyResourceData(const rt_resource *resource, void *dest) {
|
||||
memcpy(dest_info + 1, rtResolveConstRelptr(&info->bytecode), info->bytecode_length);
|
||||
rtSetRelptr(&dest_info->bytecode, (void *)(dest_info + 1));
|
||||
} break;
|
||||
case RT_RESOURCE_PIPELINE:
|
||||
memcpy(dest, resource->data, sizeof(rt_pipeline_info));
|
||||
break;
|
||||
case RT_RESOURCE_FRAMEGRAPH: {
|
||||
const rt_framegraph_info *info = resource->data;
|
||||
rt_framegraph_info *dest_info = dest;
|
||||
@ -199,6 +203,9 @@ static void CopyResourceData(const rt_resource *resource, void *dest) {
|
||||
rtSetRelptr(&passes_dest[i].name, names_begin + (src_name - src_names));
|
||||
}
|
||||
} break;
|
||||
case RT_RESOURCE_EFFECT: {
|
||||
memcpy(dest, resource->data, sizeof(rt_effect_info));
|
||||
} break;
|
||||
default:
|
||||
rtLog("RESMGR", "Tried to copy a resource of invalid type %u", resource->type);
|
||||
}
|
||||
@ -956,13 +963,6 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
|
||||
rtLog("RESMGR", " - %llx", resource->dependencies[i]);
|
||||
}
|
||||
switch (resource->type) {
|
||||
case RT_RESOURCE_PIPELINE: {
|
||||
const rt_pipeline_info *pipeline = resource->data;
|
||||
rtLog("RESMGR", " pipeline data:");
|
||||
rtLog("RESMGR", " vertex shader: %llx", pipeline->vertex_shader);
|
||||
rtLog("RESMGR", " fragment shader: %llx", pipeline->fragment_shader);
|
||||
rtLog("RESMGR", " compute shader: %llx", pipeline->compute_shader);
|
||||
} break;
|
||||
case RT_RESOURCE_SHADER: {
|
||||
static const char *stype_str[RT_SHADER_TYPE_count] = {"<INVALID>", "Vulkan"};
|
||||
static const char *stage_str[RT_SHADER_STAGE_count] = {"Vertex", "Fragment", "Compute"};
|
||||
@ -976,6 +976,13 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
|
||||
(shader->stage < RT_SHADER_STAGE_count) ? stage_str[shader->stage] : "<INVALID>");
|
||||
rtLog("RESMGR", " bytecode: %zu bytes", shader->bytecode_length);
|
||||
} break;
|
||||
case RT_RESOURCE_PIPELINE: {
|
||||
const rt_pipeline_info *pipeline = resource->data;
|
||||
rtLog("RESMGR", " pipeline data:");
|
||||
rtLog("RESMGR", " vertex shader: %llx", pipeline->vertex_shader);
|
||||
rtLog("RESMGR", " fragment shader: %llx", pipeline->fragment_shader);
|
||||
rtLog("RESMGR", " compute shader: %llx", pipeline->compute_shader);
|
||||
} break;
|
||||
case RT_RESOURCE_FRAMEGRAPH: {
|
||||
static const char *format_str[RT_PIXEL_FORMAT_count] = {
|
||||
"<INVALID>",
|
||||
@ -1055,6 +1062,15 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case RT_RESOURCE_EFFECT: {
|
||||
const rt_effect_info *effect = resource->data;
|
||||
rtLog("RESMGR", " effect data:");
|
||||
for (uint32_t i = 0; i < effect->pass_count; ++i) {
|
||||
rtLog("RESMGR", " pass %u:", i);
|
||||
rtLog("RESMGR", " id: %llx", effect->passes[i].pass_id);
|
||||
rtLog("RESMGR", " pipeline: %llx", effect->passes[i].pipeline);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
rtLog("RESMGR", " unknown data at: %llx", (uintptr_t)resource->data);
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
test_link_libs = [runtime_lib, gfx_lib]
|
||||
if get_option('default_library') == 'static'
|
||||
test_link_libs += null_renderer_lib
|
||||
endif
|
||||
|
||||
rttest_exe = executable('rttest',
|
||||
'rttest.c',
|
||||
link_with : engine_link_libs,
|
||||
link_with : test_link_libs,
|
||||
include_directories : engine_incdir,
|
||||
win_subsystem : 'console')
|
||||
test('runtime test', rttest_exe)
|
||||
|
157
tests/rttest.c
157
tests/rttest.c
@ -1,13 +1,20 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "runtime/config.h"
|
||||
#include "runtime/runtime.h"
|
||||
|
||||
#include "gfx/gfx.h"
|
||||
#include "gfx/render_list.h"
|
||||
#include "gfx/renderer_api.h"
|
||||
|
||||
extern rt_cvar rt_Renderer;
|
||||
|
||||
/* Check basic relative pointer behaviour */
|
||||
static rt_result RelPtrTest(void) {
|
||||
char buf[sizeof(rt_relptr) + sizeof(unsigned int)];
|
||||
rt_relptr *ptr = (rt_relptr *)buf;
|
||||
rt_relptr *ptr = (rt_relptr *)buf;
|
||||
unsigned int *target = (unsigned int *)&buf[sizeof(rt_relptr)];
|
||||
*target = 42;
|
||||
*target = 42;
|
||||
rtSetRelptr(ptr, target);
|
||||
|
||||
void *resolved = rtResolveRelptr(ptr);
|
||||
@ -37,37 +44,173 @@ static rt_result NegRelPtrTest(void) {
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
static rt_result SetupRenderListFixture(void) {
|
||||
rt_result res = rtInitRuntime();
|
||||
if (res != RT_SUCCESS)
|
||||
return res;
|
||||
|
||||
rt_Renderer.s = "null";
|
||||
|
||||
rt_renderer_init_info info = {0};
|
||||
rtInitGFX(&info);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void TeardownRenderListFixture(void) {
|
||||
rtShutdownGFX();
|
||||
rtShutdownRuntime();
|
||||
}
|
||||
|
||||
/* Check render list interface */
|
||||
static rt_result PushRenderList(void) {
|
||||
typedef struct {
|
||||
int a;
|
||||
float b;
|
||||
} dummy_type;
|
||||
rt_render_object_type type = rtRegisterRenderObjectType(sizeof(dummy_type), "DummyType");
|
||||
|
||||
rt_create_render_list_result list_res = rtCreateRenderList(type);
|
||||
if (!list_res.ok) {
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
rt_render_list list = list_res.list;
|
||||
dummy_type dummy = {42, 21.f};
|
||||
rtPushRenderListEntry(&list, &dummy);
|
||||
|
||||
dummy_type check = RT_GET_RENDER_LIST_ELEMENT(list, dummy_type, 0);
|
||||
|
||||
if (check.a != dummy.a || check.b != dummy.b)
|
||||
return RT_INVALID_VALUE;
|
||||
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
static rt_result PushLongRenderList(void) {
|
||||
typedef struct {
|
||||
float p[3];
|
||||
float v[3];
|
||||
} dummy_type;
|
||||
rt_render_object_type type = rtRegisterRenderObjectType(sizeof(dummy_type), "DummyType");
|
||||
|
||||
rt_create_render_list_result list_res = rtCreateRenderList(type);
|
||||
if (!list_res.ok)
|
||||
return RT_INVALID_VALUE;
|
||||
rt_render_list list = list_res.list;
|
||||
for (uint32_t i = 0; i < 512; ++i) {
|
||||
dummy_type dummy;
|
||||
for (int j = 0; j < 3; ++j)
|
||||
dummy.v[j] = dummy.p[j] = (float)i;
|
||||
rtPushRenderListEntry(&list, &dummy);
|
||||
|
||||
dummy_type check = RT_GET_RENDER_LIST_ELEMENT(list, dummy_type, i);
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (check.p[j] != (float)i || check.v[j] != (float)i)
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 512; ++i) {
|
||||
dummy_type check = RT_GET_RENDER_LIST_ELEMENT(list, dummy_type, i);
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
if (check.p[j] != (float)i || check.v[j] != (float)i)
|
||||
return RT_INVALID_VALUE;
|
||||
}
|
||||
}
|
||||
return RT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Scaffolding
|
||||
*
|
||||
* Run all the test cases, output if they passed or failed.
|
||||
*/
|
||||
|
||||
typedef rt_result rt_fixture_setup_fn(void);
|
||||
typedef void rt_fixture_teardown_fn(void);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
bool is_initialized;
|
||||
rt_fixture_setup_fn *setup;
|
||||
rt_fixture_teardown_fn *teardown;
|
||||
} rt_test_fixture;
|
||||
|
||||
typedef rt_result rt_test_fnc(void);
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
rt_test_fnc *fnc;
|
||||
|
||||
rt_test_fixture *fixture;
|
||||
} rt_test_case;
|
||||
|
||||
#define TEST_CASE(fn) { .name = #fn, .fnc = fn, }
|
||||
#define TEST_CASE(fn) \
|
||||
{ .name = #fn, .fnc = fn, .fixture = NULL, }
|
||||
|
||||
static rt_test_case _test_cases[] = {TEST_CASE(RelPtrTest), TEST_CASE(NegRelPtrTest)};
|
||||
#define TEST_CASE_FIXTURE(fn, _fixture) \
|
||||
{ .name = #fn, .fnc = fn, .fixture = &_fixture }
|
||||
|
||||
/* X-Macro to create named fixtures */
|
||||
|
||||
/* Add more fixtures here*/
|
||||
#define TEST_FIXTURE_LIST \
|
||||
TEST_FIXTURE(render_list_fixture, SetupRenderListFixture, TeardownRenderListFixture)
|
||||
|
||||
#define TEST_FIXTURE(n, setup_fn, teardown_fn) \
|
||||
rt_test_fixture n = {.name = #n, \
|
||||
.is_initialized = false, \
|
||||
.setup = setup_fn, \
|
||||
.teardown = teardown_fn};
|
||||
TEST_FIXTURE_LIST
|
||||
|
||||
#undef TEST_FIXTURE
|
||||
#define TEST_FIXTURE(n, _s, _t) &n
|
||||
|
||||
static rt_test_fixture *_test_fixtures[] = {TEST_FIXTURE_LIST};
|
||||
|
||||
static rt_test_case _test_cases[] = {TEST_CASE(RelPtrTest),
|
||||
TEST_CASE(NegRelPtrTest),
|
||||
TEST_CASE_FIXTURE(PushRenderList, render_list_fixture),
|
||||
TEST_CASE_FIXTURE(PushLongRenderList, render_list_fixture)};
|
||||
|
||||
int main() {
|
||||
int out = 0;
|
||||
|
||||
for (size_t i = 0; i < RT_ARRAY_COUNT(_test_cases); ++i) {
|
||||
if (_test_cases[i].fixture) {
|
||||
rt_test_fixture *fixture = _test_cases[i].fixture;
|
||||
if (!fixture->is_initialized) {
|
||||
printf("[SETUP %s] ... ", fixture->name);
|
||||
rt_result res = fixture->setup();
|
||||
if (res == RT_SUCCESS) {
|
||||
printf("OK\n");
|
||||
fixture->is_initialized = true;
|
||||
} else {
|
||||
printf("FAILED (%u)\n", res);
|
||||
++out;
|
||||
printf("Cannot run test case %s because the setup of fixture %s failed!\n",
|
||||
_test_cases[i].name,
|
||||
fixture->name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("[%s] ... ", _test_cases[i].name);
|
||||
rt_result res = _test_cases[i].fnc();
|
||||
if (res == RT_SUCCESS) {
|
||||
printf("OK\n");
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
printf("FAILED (%u)\n", res);
|
||||
++out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Teardown fixtures */
|
||||
for (size_t i = 0; i < RT_ARRAY_COUNT(_test_fixtures); ++i) {
|
||||
if (_test_fixtures[i]->is_initialized) {
|
||||
printf("[TEARDOWN %s] ... ", _test_fixtures[i]->name);
|
||||
_test_fixtures[i]->teardown();
|
||||
printf("DONE\n");
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user