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;
 | 
					optimization speed;
 | 
				
			||||||
 | 
					 | 
				
			||||||
passes {
 | 
					passes {
 | 
				
			||||||
    pass0 {
 | 
					    pass0 {
 | 
				
			||||||
        vertex {
 | 
					        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('default_library') == 'static'
 | 
				
			||||||
  if get_option('static_renderer') == 'vk'
 | 
					  if get_option('static_renderer') == 'vk'
 | 
				
			||||||
    engine_link_libs = [runtime_lib, gfx_lib, app_lib, vk_renderer_lib]
 | 
					    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
 | 
					  else
 | 
				
			||||||
    error('Invalid static_renderer option ', get_option('static_renderer'))
 | 
					    error('Invalid static_renderer option ', get_option('static_renderer'))
 | 
				
			||||||
  endif
 | 
					  endif
 | 
				
			||||||
 | 
				
			|||||||
@ -36,6 +36,10 @@ RT_DLLEXPORT int rtWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
    if (rtInitRuntime() != RT_SUCCESS)
 | 
					    if (rtInitRuntime() != RT_SUCCESS)
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rtRegisterCVAR(&rt_Fullscreen);
 | 
				
			||||||
 | 
					    rtRegisterCVAR(&rt_WindowWidth);
 | 
				
			||||||
 | 
					    rtRegisterCVAR(&rt_WindowHeight);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    rtRegisterRendererCVars();
 | 
					    rtRegisterRendererCVars();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (app_callbacks.RegisterCVars)
 | 
					    if (app_callbacks.RegisterCVars)
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@
 | 
				
			|||||||
#include "runtime/runtime.h"
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
#include "runtime/threading.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_update_fn(unsigned int frame_id);
 | 
				
			||||||
typedef void rt_main_loop_render_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);
 | 
					RT_DLLEXPORT void rtShutdownMainLoop(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -63,11 +63,11 @@ static rt_asset_db _asset_db;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static rt_processing_queue _processing_queue;
 | 
					static rt_processing_queue _processing_queue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern RT_ASSET_PROCESSOR_FN(PipelineProcessor);
 | 
					extern RT_ASSET_PROCESSOR_FN(EffectProcessor);
 | 
				
			||||||
extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
 | 
					extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static rt_asset_processor _processors[] = {
 | 
					static rt_asset_processor _processors[] = {
 | 
				
			||||||
    {  .file_ext = ".pipeline",   .proc = PipelineProcessor},
 | 
					    {    .file_ext = ".effect",     .proc = EffectProcessor},
 | 
				
			||||||
    {.file_ext = ".framegraph", .proc = FramegraphProcessor},
 | 
					    {.file_ext = ".framegraph", .proc = FramegraphProcessor},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@
 | 
				
			|||||||
#include "runtime/mem_arena.h"
 | 
					#include "runtime/mem_arena.h"
 | 
				
			||||||
#include "runtime/runtime.h"
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gfx/effect.h"
 | 
				
			||||||
#include "gfx/gfx.h"
 | 
					#include "gfx/gfx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
@ -35,6 +36,7 @@ typedef struct {
 | 
				
			|||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    unsigned int pass_count;
 | 
					    unsigned int pass_count;
 | 
				
			||||||
    rt_parsed_pipeline_data pipelines[RT_MAX_SUBRESOURCES];
 | 
					    rt_parsed_pipeline_data pipelines[RT_MAX_SUBRESOURCES];
 | 
				
			||||||
 | 
					    rt_render_pass_id pass_ids[RT_MAX_SUBRESOURCES];
 | 
				
			||||||
} rt_parsed_effect_data;
 | 
					} rt_parsed_effect_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
@ -336,6 +338,7 @@ static rt_result ParseEffect(rt_file_id fid,
 | 
				
			|||||||
              file_path);
 | 
					              file_path);
 | 
				
			||||||
        return RT_INVALID_VALUE;
 | 
					        return RT_INVALID_VALUE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    effect->pass_count              = passes_list->count;
 | 
				
			||||||
    const rt_parsed_stmt *pass_stmt = &state.statements[passes_list->first];
 | 
					    const rt_parsed_stmt *pass_stmt = &state.statements[passes_list->first];
 | 
				
			||||||
    for (unsigned int i = 0; i < passes_list->count;
 | 
					    for (unsigned int i = 0; i < passes_list->count;
 | 
				
			||||||
         ++i, pass_stmt = &state.statements[pass_stmt->next]) {
 | 
					         ++i, pass_stmt = &state.statements[pass_stmt->next]) {
 | 
				
			||||||
@ -347,6 +350,9 @@ static rt_result ParseEffect(rt_file_id fid,
 | 
				
			|||||||
                  file_path);
 | 
					                  file_path);
 | 
				
			||||||
            return RT_INVALID_VALUE;
 | 
					            return RT_INVALID_VALUE;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        effect->pass_ids[i] =
 | 
				
			||||||
 | 
					            rtCalculateRenderPassID(pass_stmt->attribute.start, pass_stmt->attribute.length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        result = ParsePipeline(&state,
 | 
					        result = ParsePipeline(&state,
 | 
				
			||||||
                               pass_stmt->list_index,
 | 
					                               pass_stmt->list_index,
 | 
				
			||||||
                               file_path,
 | 
					                               file_path,
 | 
				
			||||||
@ -360,7 +366,7 @@ static rt_result ParseEffect(rt_file_id fid,
 | 
				
			|||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
 | 
					RT_ASSET_PROCESSOR_FN(EffectProcessor) {
 | 
				
			||||||
    rt_loaded_asset asset = LoadAsset(file);
 | 
					    rt_loaded_asset asset = LoadAsset(file);
 | 
				
			||||||
    if (!asset.buffer)
 | 
					    if (!asset.buffer)
 | 
				
			||||||
        return RT_UNKNOWN_ERROR;
 | 
					        return RT_UNKNOWN_ERROR;
 | 
				
			||||||
@ -371,7 +377,21 @@ RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
 | 
				
			|||||||
    if (result != RT_SUCCESS)
 | 
					    if (result != RT_SUCCESS)
 | 
				
			||||||
        goto out;
 | 
					        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) {
 | 
					    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;
 | 
					        rt_parsed_pipeline_data pipeline;
 | 
				
			||||||
        memcpy(&pipeline, &effect.pipelines[i], sizeof(pipeline));
 | 
					        memcpy(&pipeline, &effect.pipelines[i], sizeof(pipeline));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -407,14 +427,27 @@ RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
 | 
				
			|||||||
                                    ? shader_resources[pipeline.compute_shader]
 | 
					                                    ? shader_resources[pipeline.compute_shader]
 | 
				
			||||||
                                    : RT_INVALID_RESOURCE_ID;
 | 
					                                    : RT_INVALID_RESOURCE_ID;
 | 
				
			||||||
        rt_resource_id pipeline_id;
 | 
					        rt_resource_id pipeline_id;
 | 
				
			||||||
        const char *name = rtGetFilePath(file);
 | 
					        char pipeline_name[260];
 | 
				
			||||||
        result           = rtCreateResources(1, &name, &pipeline_resource, &pipeline_id);
 | 
					        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) {
 | 
					        if (result == RT_SUCCESS) {
 | 
				
			||||||
            new_resources[0] = pipeline_id;
 | 
					            new_resources[i] = pipeline_id;
 | 
				
			||||||
            memcpy(&new_resources[1], shader_resources, sizeof(shader_resources));
 | 
					            memcpy(&new_resources[i + 1], shader_resources, sizeof(shader_resources));
 | 
				
			||||||
            *new_resource_count = 1 + pipeline.shader_count;
 | 
					            *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:
 | 
					out:
 | 
				
			||||||
    rtLog("AC", "Released %p", asset.buffer);
 | 
					    rtLog("AC", "Released %p", asset.buffer);
 | 
				
			||||||
    rtReleaseBuffer(asset.buffer, asset.size);
 | 
					    rtReleaseBuffer(asset.buffer, asset.size);
 | 
				
			||||||
 | 
				
			|||||||
@ -9,17 +9,23 @@
 | 
				
			|||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
#include "runtime/resources.h"
 | 
					#include "runtime/resources.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct rt_pipeline_info_s {
 | 
				
			||||||
    /* Id of the render pass during which this effect pass is run. */
 | 
					 | 
				
			||||||
    rt_render_pass_id pass_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    rt_resource_id vertex_shader;
 | 
					    rt_resource_id vertex_shader;
 | 
				
			||||||
    rt_resource_id fragment_shader;
 | 
					    rt_resource_id fragment_shader;
 | 
				
			||||||
    rt_resource_id compute_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;
 | 
					} rt_effect_pass_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    
 | 
					    uint32_t pass_count;
 | 
				
			||||||
 | 
					    rt_effect_pass_info passes[RT_MAX_SUBRESOURCES];
 | 
				
			||||||
} rt_effect_info;
 | 
					} rt_effect_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,7 @@
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rt_renderer_api g_renderer;
 | 
					rt_renderer_api g_renderer;
 | 
				
			||||||
 | 
					extern rt_cvar rt_MaxFramegraphs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef RT_STATIC_LIB
 | 
					#ifndef RT_STATIC_LIB
 | 
				
			||||||
static rt_dynlib _renderer_lib;
 | 
					static rt_dynlib _renderer_lib;
 | 
				
			||||||
@ -22,7 +23,7 @@ static rt_dynlib _renderer_lib;
 | 
				
			|||||||
static bool _renderer_loaded = false;
 | 
					static bool _renderer_loaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RT_DLLEXPORT
 | 
					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
 | 
					#ifdef RT_STATIC_LIB
 | 
				
			||||||
extern void RT_RENDERER_API_FN(RegisterCVars)(void);
 | 
					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 rt_result InitFramegraphManager(void);
 | 
				
			||||||
extern void ShutdownFramegraphManager(void);
 | 
					extern void ShutdownFramegraphManager(void);
 | 
				
			||||||
 | 
					extern rt_result InitRenderLists(void);
 | 
				
			||||||
 | 
					extern void ShutdownRenderLists(void);
 | 
				
			||||||
 | 
					extern void ResetRenderLists(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool LoadRenderer(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) {
 | 
					RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
 | 
				
			||||||
 | 
					    rtRegisterCVAR(&rt_Renderer);
 | 
				
			||||||
 | 
					    rtRegisterCVAR(&rt_MaxFramegraphs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!_renderer_loaded) {
 | 
					    if (!_renderer_loaded) {
 | 
				
			||||||
        if (!LoadRenderer())
 | 
					        if (!LoadRenderer())
 | 
				
			||||||
            return RT_UNKNOWN_ERROR;
 | 
					            return RT_UNKNOWN_ERROR;
 | 
				
			||||||
@ -154,10 +161,14 @@ RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info) {
 | 
				
			|||||||
    if ((result = InitFramegraphManager()) != RT_SUCCESS)
 | 
					    if ((result = InitFramegraphManager()) != RT_SUCCESS)
 | 
				
			||||||
        return result;
 | 
					        return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((result = InitRenderLists()) != RT_SUCCESS)
 | 
				
			||||||
 | 
					        return result;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RT_DLLEXPORT void rtShutdownGFX(void) {
 | 
					RT_DLLEXPORT void rtShutdownGFX(void) {
 | 
				
			||||||
 | 
					    ShutdownRenderLists();
 | 
				
			||||||
    ShutdownFramegraphManager();
 | 
					    ShutdownFramegraphManager();
 | 
				
			||||||
    g_renderer.Shutdown();
 | 
					    g_renderer.Shutdown();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -168,4 +179,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();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -8,6 +8,7 @@ gfx_lib = library('rtgfx',
 | 
				
			|||||||
  
 | 
					  
 | 
				
			||||||
  'gfx_framegraph.c',
 | 
					  'gfx_framegraph.c',
 | 
				
			||||||
  'gfx_main.c',
 | 
					  'gfx_main.c',
 | 
				
			||||||
 | 
					  'render_list.c',
 | 
				
			||||||
  # Contrib Sources
 | 
					  # Contrib Sources
 | 
				
			||||||
  dependencies : gfx_deps,
 | 
					  dependencies : gfx_deps,
 | 
				
			||||||
  include_directories : engine_incdir,
 | 
					  include_directories : engine_incdir,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,11 @@
 | 
				
			|||||||
 | 
					/* Stdlib */
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Project */
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Commonly used runtime headers */
 | 
					/* Commonly used runtime headers */
 | 
				
			||||||
#include "runtime/runtime.h"
 | 
					#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
 | 
					#ifndef RT_RENDER_LIST_H
 | 
				
			||||||
#define 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
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,7 @@ extern "C" {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Handles for backend objects */
 | 
					/* 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_MAX_VERSION 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RT_RENDER_BACKEND_HANDLE(name)                                                             \
 | 
					#define RT_RENDER_BACKEND_HANDLE(name)                                                             \
 | 
				
			||||||
@ -59,13 +60,6 @@ typedef enum {
 | 
				
			|||||||
    RT_TRANSFER_QUEUE,
 | 
					    RT_TRANSFER_QUEUE,
 | 
				
			||||||
} rt_gpu_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
 | 
					#if 0
 | 
				
			||||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
					/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
				
			||||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
					 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
				
			||||||
@ -182,6 +176,8 @@ typedef enum {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Renderer API */
 | 
					/* Renderer API */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct rt_pipeline_info_s rt_pipeline_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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);
 | 
				
			||||||
 | 
				
			|||||||
@ -5,3 +5,4 @@ subdir('app_framework')
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
# Renderer libs
 | 
					# Renderer libs
 | 
				
			||||||
subdir('renderer/vk')
 | 
					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,
 | 
					    cpp_args : platform_defs,
 | 
				
			||||||
    install : true)
 | 
					    install : true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    engine_libs = vk_renderer_lib
 | 
					    engine_libs += vk_renderer_lib
 | 
				
			||||||
    engine_lib_paths += vk_renderer_lib.full_path()
 | 
					    engine_lib_paths += vk_renderer_lib.full_path()
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,3 +8,12 @@
 | 
				
			|||||||
#if defined(VY_USE_XLIB)
 | 
					#if defined(VY_USE_XLIB)
 | 
				
			||||||
#include <X11/Xlib.h>
 | 
					#include <X11/Xlib.h>
 | 
				
			||||||
#endif
 | 
					#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 "runtime/threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gfx/renderer_api.h"
 | 
					#include "gfx/renderer_api.h"
 | 
				
			||||||
 | 
					#include "gfx/effect.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "gpu.h"
 | 
					#include "gpu.h"
 | 
				
			||||||
#include "pipelines.h"
 | 
					#include "pipelines.h"
 | 
				
			||||||
 | 
				
			|||||||
@ -4,10 +4,6 @@
 | 
				
			|||||||
#include "file_tab.h"
 | 
					#include "file_tab.h"
 | 
				
			||||||
#include "buffer_manager.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_BufferMemoryBudget;
 | 
				
			||||||
extern rt_cvar rt_FileTabCapacity;
 | 
					extern rt_cvar rt_FileTabCapacity;
 | 
				
			||||||
extern rt_cvar rt_MaxConcurrentAsyncIO;
 | 
					extern rt_cvar rt_MaxConcurrentAsyncIO;
 | 
				
			||||||
@ -16,13 +12,8 @@ extern rt_cvar rt_ResourceCacheSize;
 | 
				
			|||||||
extern rt_cvar rt_MaxCachedResources;
 | 
					extern rt_cvar rt_MaxCachedResources;
 | 
				
			||||||
extern rt_cvar rt_ResourceNamespaceSize;
 | 
					extern rt_cvar rt_ResourceNamespaceSize;
 | 
				
			||||||
extern rt_cvar rt_DisableResourceNamespaceLoad;
 | 
					extern rt_cvar rt_DisableResourceNamespaceLoad;
 | 
				
			||||||
extern rt_cvar rt_MaxFramegraphs;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RegisterRuntimeCVars(void) {
 | 
					void RegisterRuntimeCVars(void) {
 | 
				
			||||||
    rtRegisterCVAR(&rt_Renderer);
 | 
					 | 
				
			||||||
    rtRegisterCVAR(&rt_Fullscreen);
 | 
					 | 
				
			||||||
    rtRegisterCVAR(&rt_WindowWidth);
 | 
					 | 
				
			||||||
    rtRegisterCVAR(&rt_WindowHeight);
 | 
					 | 
				
			||||||
    rtRegisterCVAR(&rt_BufferMemoryBudget);
 | 
					    rtRegisterCVAR(&rt_BufferMemoryBudget);
 | 
				
			||||||
    rtRegisterCVAR(&rt_FileTabCapacity);
 | 
					    rtRegisterCVAR(&rt_FileTabCapacity);
 | 
				
			||||||
    rtRegisterCVAR(&rt_MaxConcurrentAsyncIO);
 | 
					    rtRegisterCVAR(&rt_MaxConcurrentAsyncIO);
 | 
				
			||||||
@ -31,7 +22,6 @@ void RegisterRuntimeCVars(void) {
 | 
				
			|||||||
    rtRegisterCVAR(&rt_MaxCachedResources);
 | 
					    rtRegisterCVAR(&rt_MaxCachedResources);
 | 
				
			||||||
    rtRegisterCVAR(&rt_ResourceNamespaceSize);
 | 
					    rtRegisterCVAR(&rt_ResourceNamespaceSize);
 | 
				
			||||||
    rtRegisterCVAR(&rt_DisableResourceNamespaceLoad);
 | 
					    rtRegisterCVAR(&rt_DisableResourceNamespaceLoad);
 | 
				
			||||||
    rtRegisterCVAR(&rt_MaxFramegraphs);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void SetMainThreadId(void);
 | 
					extern void SetMainThreadId(void);
 | 
				
			||||||
 | 
				
			|||||||
@ -10,6 +10,7 @@
 | 
				
			|||||||
#include "resources.h"
 | 
					#include "resources.h"
 | 
				
			||||||
#include "threading.h"
 | 
					#include "threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "gfx/effect.h"
 | 
				
			||||||
#include "gfx/renderer_api.h"
 | 
					#include "gfx/renderer_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
@ -92,13 +93,13 @@ typedef struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static size_t GetResourceDataSize(const rt_resource *resource) {
 | 
					static size_t GetResourceDataSize(const rt_resource *resource) {
 | 
				
			||||||
    switch (resource->type) {
 | 
					    switch (resource->type) {
 | 
				
			||||||
    case RT_RESOURCE_PIPELINE:
 | 
					 | 
				
			||||||
        return sizeof(rt_pipeline_info);
 | 
					 | 
				
			||||||
    case RT_RESOURCE_SHADER: {
 | 
					    case RT_RESOURCE_SHADER: {
 | 
				
			||||||
        /* Sizeof metadata + bytecode */
 | 
					        /* Sizeof metadata + bytecode */
 | 
				
			||||||
        const rt_shader_info *info = resource->data;
 | 
					        const rt_shader_info *info = resource->data;
 | 
				
			||||||
        return sizeof(rt_shader_info) + (info) ? info->bytecode_length : 0;
 | 
					        return sizeof(rt_shader_info) + (info) ? info->bytecode_length : 0;
 | 
				
			||||||
    } break;
 | 
					    } break;
 | 
				
			||||||
 | 
					    case RT_RESOURCE_PIPELINE:
 | 
				
			||||||
 | 
					        return sizeof(rt_pipeline_info);
 | 
				
			||||||
    case RT_RESOURCE_FRAMEGRAPH: {
 | 
					    case RT_RESOURCE_FRAMEGRAPH: {
 | 
				
			||||||
        const rt_framegraph_info *info = resource->data;
 | 
					        const rt_framegraph_info *info = resource->data;
 | 
				
			||||||
        size_t size = sizeof(*info) + sizeof(rt_render_target_info) * info->render_target_count +
 | 
					        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;
 | 
					        return size;
 | 
				
			||||||
    } break;
 | 
					    } break;
 | 
				
			||||||
 | 
					    case RT_RESOURCE_EFFECT: {
 | 
				
			||||||
 | 
					        return sizeof(rt_effect_info);
 | 
				
			||||||
 | 
					    } break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        rtLog("RESMGR", "Tried to get size of an invalid resource type %u", resource->type);
 | 
					        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) {
 | 
					static void CopyResourceData(const rt_resource *resource, void *dest) {
 | 
				
			||||||
    switch (resource->type) {
 | 
					    switch (resource->type) {
 | 
				
			||||||
    case RT_RESOURCE_PIPELINE:
 | 
					 | 
				
			||||||
        memcpy(dest, resource->data, sizeof(rt_pipeline_info));
 | 
					 | 
				
			||||||
        break;
 | 
					 | 
				
			||||||
    case RT_RESOURCE_SHADER: {
 | 
					    case RT_RESOURCE_SHADER: {
 | 
				
			||||||
        /* Sizeof metadata + bytecode */
 | 
					        /* Sizeof metadata + bytecode */
 | 
				
			||||||
        const rt_shader_info *info = resource->data;
 | 
					        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);
 | 
					        memcpy(dest_info + 1, rtResolveConstRelptr(&info->bytecode), info->bytecode_length);
 | 
				
			||||||
        rtSetRelptr(&dest_info->bytecode, (void *)(dest_info + 1));
 | 
					        rtSetRelptr(&dest_info->bytecode, (void *)(dest_info + 1));
 | 
				
			||||||
    } break;
 | 
					    } break;
 | 
				
			||||||
 | 
					    case RT_RESOURCE_PIPELINE:
 | 
				
			||||||
 | 
					        memcpy(dest, resource->data, sizeof(rt_pipeline_info));
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    case RT_RESOURCE_FRAMEGRAPH: {
 | 
					    case RT_RESOURCE_FRAMEGRAPH: {
 | 
				
			||||||
        const rt_framegraph_info *info = resource->data;
 | 
					        const rt_framegraph_info *info = resource->data;
 | 
				
			||||||
        rt_framegraph_info *dest_info  = dest;
 | 
					        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));
 | 
					                rtSetRelptr(&passes_dest[i].name, names_begin + (src_name - src_names));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } break;
 | 
					    } break;
 | 
				
			||||||
 | 
					    case RT_RESOURCE_EFFECT: {
 | 
				
			||||||
 | 
					        memcpy(dest, resource->data, sizeof(rt_effect_info));
 | 
				
			||||||
 | 
					    } break;
 | 
				
			||||||
    default:
 | 
					    default:
 | 
				
			||||||
        rtLog("RESMGR", "Tried to copy a resource of invalid type %u", resource->type);
 | 
					        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]);
 | 
					        rtLog("RESMGR", "    - %llx", resource->dependencies[i]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    switch (resource->type) {
 | 
					    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: {
 | 
					    case RT_RESOURCE_SHADER: {
 | 
				
			||||||
        static const char *stype_str[RT_SHADER_TYPE_count]  = {"<INVALID>", "Vulkan"};
 | 
					        static const char *stype_str[RT_SHADER_TYPE_count]  = {"<INVALID>", "Vulkan"};
 | 
				
			||||||
        static const char *stage_str[RT_SHADER_STAGE_count] = {"Vertex", "Fragment", "Compute"};
 | 
					        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>");
 | 
					              (shader->stage < RT_SHADER_STAGE_count) ? stage_str[shader->stage] : "<INVALID>");
 | 
				
			||||||
        rtLog("RESMGR", "    bytecode: %zu bytes", shader->bytecode_length);
 | 
					        rtLog("RESMGR", "    bytecode: %zu bytes", shader->bytecode_length);
 | 
				
			||||||
    } break;
 | 
					    } 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: {
 | 
					    case RT_RESOURCE_FRAMEGRAPH: {
 | 
				
			||||||
        static const char *format_str[RT_PIXEL_FORMAT_count] = {
 | 
					        static const char *format_str[RT_PIXEL_FORMAT_count] = {
 | 
				
			||||||
            "<INVALID>",
 | 
					            "<INVALID>",
 | 
				
			||||||
@ -1055,6 +1062,15 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } break;
 | 
					    } 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:
 | 
					    default:
 | 
				
			||||||
        rtLog("RESMGR", "  unknown data at: %llx", (uintptr_t)resource->data);
 | 
					        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_exe = executable('rttest',
 | 
				
			||||||
  'rttest.c',
 | 
					  'rttest.c',
 | 
				
			||||||
  link_with : engine_link_libs,
 | 
					  link_with : test_link_libs,
 | 
				
			||||||
  include_directories : engine_incdir,
 | 
					  include_directories : engine_incdir,
 | 
				
			||||||
  win_subsystem : 'console')
 | 
					  win_subsystem : 'console')
 | 
				
			||||||
test('runtime test', rttest_exe)
 | 
					test('runtime test', rttest_exe)
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										159
									
								
								tests/rttest.c
									
									
									
									
									
								
							
							
						
						
									
										159
									
								
								tests/rttest.c
									
									
									
									
									
								
							@ -1,13 +1,20 @@
 | 
				
			|||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/config.h"
 | 
				
			||||||
#include "runtime/runtime.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 */
 | 
					/* Check basic relative pointer behaviour */
 | 
				
			||||||
static rt_result RelPtrTest(void) {
 | 
					static rt_result RelPtrTest(void) {
 | 
				
			||||||
    char buf[sizeof(rt_relptr) + sizeof(unsigned int)];
 | 
					    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)];
 | 
					    unsigned int *target = (unsigned int *)&buf[sizeof(rt_relptr)];
 | 
				
			||||||
    *target = 42;
 | 
					    *target              = 42;
 | 
				
			||||||
    rtSetRelptr(ptr, target);
 | 
					    rtSetRelptr(ptr, target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void *resolved = rtResolveRelptr(ptr);
 | 
					    void *resolved = rtResolveRelptr(ptr);
 | 
				
			||||||
@ -37,37 +44,173 @@ static rt_result NegRelPtrTest(void) {
 | 
				
			|||||||
    return RT_SUCCESS;
 | 
					    return RT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Scaffolding 
 | 
					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.
 | 
					 * 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 rt_result rt_test_fnc(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
    rt_test_fnc *fnc;
 | 
					    rt_test_fnc *fnc;
 | 
				
			||||||
 | 
					    rt_test_fixture *fixture;
 | 
				
			||||||
} rt_test_case;
 | 
					} 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 main() {
 | 
				
			||||||
    int out = 0;
 | 
					    int out = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (size_t i = 0; i < RT_ARRAY_COUNT(_test_cases); ++i) {
 | 
					    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);
 | 
					        printf("[%s] ... ", _test_cases[i].name);
 | 
				
			||||||
        rt_result res = _test_cases[i].fnc();
 | 
					        rt_result res = _test_cases[i].fnc();
 | 
				
			||||||
        if (res == RT_SUCCESS) {
 | 
					        if (res == RT_SUCCESS) {
 | 
				
			||||||
            printf("OK\n");
 | 
					            printf("OK\n");
 | 
				
			||||||
        } 
 | 
					        } else {
 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            printf("FAILED (%u)\n", res);
 | 
					            printf("FAILED (%u)\n", res);
 | 
				
			||||||
            ++out;
 | 
					            ++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;
 | 
					    return out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user