Load framegraphs from resource files
This commit is contained in:
		
							parent
							
								
									bdd3db98bb
								
							
						
					
					
						commit
						cc49a017f9
					
				
							
								
								
									
										64
									
								
								assets/test.framegraph
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								assets/test.framegraph
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
render_targets {
 | 
			
		||||
    color0 {
 | 
			
		||||
        format R8G8B8A8_SRGB;
 | 
			
		||||
        width 1024;
 | 
			
		||||
        height 768;
 | 
			
		||||
        sample_count 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    swapchain_out {
 | 
			
		||||
        format SWAPCHAIN;
 | 
			
		||||
        width SWAPCHAIN;
 | 
			
		||||
        height SWAPCHAIN;
 | 
			
		||||
        sample_count 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    depth0 {
 | 
			
		||||
        format DEPTH24_STENCIL8;
 | 
			
		||||
        width 512;
 | 
			
		||||
        height 384;
 | 
			
		||||
        sample_count 4;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
passes {
 | 
			
		||||
    pass0 {
 | 
			
		||||
        writes {
 | 
			
		||||
            color0 {
 | 
			
		||||
                clear_value {
 | 
			
		||||
                    r 1.0;
 | 
			
		||||
                    g 1.0;
 | 
			
		||||
                    b 1.0;
 | 
			
		||||
                    a 1.0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                clear YES;
 | 
			
		||||
                discard NO;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            depth0 {
 | 
			
		||||
                clear_value {
 | 
			
		||||
                    d 0.0;
 | 
			
		||||
                    s 0;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                clear YES;
 | 
			
		||||
                discard YES;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pass1 {
 | 
			
		||||
        reads {
 | 
			
		||||
            color0 {
 | 
			
		||||
                mode SAMPLED;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        writes {
 | 
			
		||||
            swapchain_out {
 | 
			
		||||
                clear NO;
 | 
			
		||||
                discard NO;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -28,6 +28,8 @@ elif compiler.get_argument_syntax() == 'msvc'
 | 
			
		||||
  if buildtype == 'debug'
 | 
			
		||||
    add_project_arguments(['/RTCsu'], language : ['c', 'cpp'])
 | 
			
		||||
  endif
 | 
			
		||||
  # Allow nameless struct/unions (standard in C11)
 | 
			
		||||
  add_project_arguments(['/wd4201'], language : 'cpp')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if get_option('default_library') == 'static'
 | 
			
		||||
@ -98,6 +100,7 @@ if get_option('build_asset_compiler')
 | 
			
		||||
 | 
			
		||||
    'src/runtime/asset_compiler.c',
 | 
			
		||||
    'src/runtime/description_parser.c',
 | 
			
		||||
    'src/runtime/framegraph_processor.c',
 | 
			
		||||
    'src/runtime/pipeline_processor.c',
 | 
			
		||||
    'src/runtime/shader_compiler.c',
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,6 @@
 | 
			
		||||
#include "runtime/gfx.h"
 | 
			
		||||
#include "runtime/resources.h"
 | 
			
		||||
#include "runtime/mem_arena.h"
 | 
			
		||||
 | 
			
		||||
static rt_framegraph *_framegraph;
 | 
			
		||||
 | 
			
		||||
@ -6,6 +8,7 @@ static rt_framegraph *_framegraph;
 | 
			
		||||
void Init(void) {
 | 
			
		||||
    rtLog("GAME", "Init");
 | 
			
		||||
 | 
			
		||||
    #if 0
 | 
			
		||||
    rt_render_target_id rt_ids[4] = {rtCalculateRenderTargetID("rt0", sizeof("rt0")),
 | 
			
		||||
                                     rtCalculateRenderTargetID("rt1", sizeof("rt1")),
 | 
			
		||||
                                     rtCalculateRenderTargetID("rt2", sizeof("rt2")),
 | 
			
		||||
@ -54,8 +57,16 @@ void Init(void) {
 | 
			
		||||
    };
 | 
			
		||||
    rtSetRelptr(&info.render_passes, passes);
 | 
			
		||||
    rtSetRelptr(&info.render_targets, rts);
 | 
			
		||||
    #endif
 | 
			
		||||
 | 
			
		||||
    _framegraph = rtCreateFramegraph(&info);
 | 
			
		||||
    rt_resource_id id  = rtGetResourceID("assets/test.framegraph");
 | 
			
		||||
    rt_temp_arena temp = rtGetTemporaryArena(NULL, 0);
 | 
			
		||||
    rt_resource *resource =
 | 
			
		||||
        rtArenaPush(temp.arena, rtGetResourceSize(id));
 | 
			
		||||
    
 | 
			
		||||
    rtGetResource(id, resource);
 | 
			
		||||
 | 
			
		||||
    _framegraph = rtCreateFramegraph(resource->data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Called after exiting the main-loop and before the runtime starts its shutdown */
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,26 @@
 | 
			
		||||
 | 
			
		||||
VkFormat rtPixelFormatToVkFormat(rt_pixel_format format) {
 | 
			
		||||
    switch (format) {
 | 
			
		||||
    case RT_PIXEL_FORMAT_R8G8B8A8_UNORM:
 | 
			
		||||
        return VK_FORMAT_R8G8B8A8_UNORM;
 | 
			
		||||
    case RT_PIXEL_FORMAT_B8G8R8A8_UNORM:
 | 
			
		||||
        return VK_FORMAT_B8G8R8A8_UNORM;
 | 
			
		||||
    case RT_PIXEL_FORMAT_R8G8B8A8_SRGB:
 | 
			
		||||
        return VK_FORMAT_R8G8B8A8_SRGB;
 | 
			
		||||
    case RT_PIXEL_FORMAT_B8G8R8A8_SRGB:
 | 
			
		||||
        return VK_FORMAT_B8G8R8A8_SRGB;
 | 
			
		||||
    case RT_PIXEL_FORMAT_R8G8B8_UNORM:
 | 
			
		||||
        return VK_FORMAT_R8G8B8_UNORM;
 | 
			
		||||
    case RT_PIXEL_FORMAT_B8G8R8_UNORM:
 | 
			
		||||
        return VK_FORMAT_B8G8R8_UNORM;
 | 
			
		||||
    case RT_PIXEL_FORMAT_R8G8B8_SRGB:
 | 
			
		||||
        return VK_FORMAT_R8G8B8_SRGB;
 | 
			
		||||
    case RT_PIXEL_FORMAT_B8G8R8_SRGB:
 | 
			
		||||
        return VK_FORMAT_B8G8R8_SRGB;
 | 
			
		||||
    case RT_PIXEL_FORMAT_DEPTH24_STENCIL8:
 | 
			
		||||
        return VK_FORMAT_D24_UNORM_S8_UINT;
 | 
			
		||||
    case RT_PIXEL_FORMAT_DEPTH32:
 | 
			
		||||
        return VK_FORMAT_D32_SFLOAT;
 | 
			
		||||
    default:
 | 
			
		||||
        return VK_FORMAT_UNDEFINED;
 | 
			
		||||
    }
 | 
			
		||||
@ -20,6 +36,8 @@ VkSampleCountFlagBits rtSampleCountToFlags(unsigned int count) {
 | 
			
		||||
    while (count > 1) {
 | 
			
		||||
        if ((counts & count) == 0)
 | 
			
		||||
            count >>= 1;
 | 
			
		||||
        else
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
    return (VkSampleCountFlagBits)count;
 | 
			
		||||
}
 | 
			
		||||
@ -175,7 +175,7 @@ rt_render_target_handle RT_RENDERER_API_FN(CreateRenderTarget)(const rt_render_t
 | 
			
		||||
            slot->render_target.format = g_swapchain.format;
 | 
			
		||||
            slot->render_target.match_swapchain |= RT_RENDER_TARGET_MATCH_SWAPCHAIN_FORMAT;
 | 
			
		||||
        }
 | 
			
		||||
        if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8) {
 | 
			
		||||
        if (info->format == RT_PIXEL_FORMAT_DEPTH24_STENCIL8 || info->format == RT_PIXEL_FORMAT_DEPTH32) {
 | 
			
		||||
            slot->render_target.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_SAMPLED_BIT |
 | 
			
		||||
                                        VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
 | 
			
		||||
 | 
			
		||||
@ -65,9 +65,11 @@ static rt_asset_db _asset_db;
 | 
			
		||||
static rt_processing_queue _processing_queue;
 | 
			
		||||
 | 
			
		||||
extern RT_ASSET_PROCESSOR_FN(PipelineProcessor);
 | 
			
		||||
extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
 | 
			
		||||
 | 
			
		||||
static rt_asset_processor _processors[] = {
 | 
			
		||||
    {.file_ext = ".pipeline", .proc = PipelineProcessor}
 | 
			
		||||
    {.file_ext = ".pipeline", .proc = PipelineProcessor},
 | 
			
		||||
    {.file_ext = ".framegraph", .proc = FramegraphProcessor},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void ProcessorThreadEntry(void *);
 | 
			
		||||
 | 
			
		||||
@ -17,10 +17,34 @@
 | 
			
		||||
extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef union {
 | 
			
		||||
    float v[4];
 | 
			
		||||
    struct {
 | 
			
		||||
        float r;
 | 
			
		||||
        float g;
 | 
			
		||||
        float b;
 | 
			
		||||
        float a;
 | 
			
		||||
    };
 | 
			
		||||
} rt_color;
 | 
			
		||||
 | 
			
		||||
/* NOTE(kevin): When you add a value here, you need to handle them in
 | 
			
		||||
 * framegraph_processor.c : ParseFramegraph 
 | 
			
		||||
 * and in the render target and texture functions of all renderers. */
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_PIXEL_FORMAT_INVALID,
 | 
			
		||||
 | 
			
		||||
    RT_PIXEL_FORMAT_R8G8B8A8_UNORM,
 | 
			
		||||
    RT_PIXEL_FORMAT_B8G8R8A8_UNORM,
 | 
			
		||||
    RT_PIXEL_FORMAT_R8G8B8A8_SRGB,
 | 
			
		||||
    RT_PIXEL_FORMAT_B8G8R8A8_SRGB,
 | 
			
		||||
    RT_PIXEL_FORMAT_R8G8B8_UNORM,
 | 
			
		||||
    RT_PIXEL_FORMAT_B8G8R8_UNORM,
 | 
			
		||||
    RT_PIXEL_FORMAT_R8G8B8_SRGB,
 | 
			
		||||
    RT_PIXEL_FORMAT_B8G8R8_SRGB,
 | 
			
		||||
 | 
			
		||||
    RT_PIXEL_FORMAT_DEPTH24_STENCIL8,
 | 
			
		||||
    RT_PIXEL_FORMAT_DEPTH32,
 | 
			
		||||
 | 
			
		||||
    /* Special value indicating whichever format the swapchain uses */
 | 
			
		||||
    RT_PIXEL_FORMAT_SWAPCHAIN,
 | 
			
		||||
@ -28,6 +52,21 @@ typedef enum {
 | 
			
		||||
    RT_PIXEL_FORMAT_count,
 | 
			
		||||
} rt_pixel_format;
 | 
			
		||||
 | 
			
		||||
/* In renderer_api.h -> Not necessary for almost all gfx usage */
 | 
			
		||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRendererCVars(void);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtShutdownGFX(void);
 | 
			
		||||
 | 
			
		||||
/* *********************************************************************
 | 
			
		||||
 * Framegraph API 
 | 
			
		||||
 * 
 | 
			
		||||
 * The framegraph is used to organize and schedule the work for a frame.
 | 
			
		||||
 * *********************************************************************/
 | 
			
		||||
 | 
			
		||||
/* Special value for the .width and .height fields of rt_render_target_info
 | 
			
		||||
 * to indicate that these should be set to the width or height of the swapchain, respectively. */
 | 
			
		||||
#define RT_RENDER_TARGET_SIZE_SWAPCHAIN 0
 | 
			
		||||
@ -44,8 +83,8 @@ typedef struct {
 | 
			
		||||
} rt_render_target_info;
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    RT_RENDER_TARGET_READ_INPUT_ATTACHMENT,
 | 
			
		||||
    RT_RENDER_TARGET_READ_SAMPLED,
 | 
			
		||||
    RT_RENDER_TARGET_READ_INPUT_ATTACHMENT,
 | 
			
		||||
 | 
			
		||||
    RT_RENDER_TARGET_READ_count,
 | 
			
		||||
} rt_render_target_read_mode;
 | 
			
		||||
@ -66,7 +105,7 @@ typedef enum {
 | 
			
		||||
typedef struct {
 | 
			
		||||
    rt_render_target_id render_target;
 | 
			
		||||
    union {
 | 
			
		||||
        float color[4];
 | 
			
		||||
        rt_color color;
 | 
			
		||||
        struct {
 | 
			
		||||
            float depth;
 | 
			
		||||
            int32_t stencil;
 | 
			
		||||
@ -102,20 +141,6 @@ typedef struct {
 | 
			
		||||
    rt_render_pass_finalize_fn *Finalize;
 | 
			
		||||
} rt_render_pass_bind_fns;
 | 
			
		||||
 | 
			
		||||
/* In renderer_api.h -> Not necessary for almost all gfx usage */
 | 
			
		||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRendererCVars(void);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_result rtInitGFX(rt_renderer_init_info *renderer_info);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtShutdownGFX(void);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/* Framegraph API 
 | 
			
		||||
 * 
 | 
			
		||||
 * The framegraph is used to organize and schedule the work for a frame.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct rt_framegraph_s rt_framegraph;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -310,6 +310,7 @@ static bool ValidateInfo(const rt_framegraph_info *info) {
 | 
			
		||||
            rtReportError(
 | 
			
		||||
                "GFX",
 | 
			
		||||
                "Framegraph pass %u reads too many rendertargets: %u (maximum allowed is %u)",
 | 
			
		||||
                i,
 | 
			
		||||
                passes[i].read_render_target_count,
 | 
			
		||||
                RT_RENDERPASS_MAX_READS);
 | 
			
		||||
            return false;
 | 
			
		||||
@ -317,6 +318,7 @@ static bool ValidateInfo(const rt_framegraph_info *info) {
 | 
			
		||||
            rtReportError(
 | 
			
		||||
                "GFX",
 | 
			
		||||
                "Framegraph pass %u writes too many rendertargets: %u (maximum allowed is %u)",
 | 
			
		||||
                i,
 | 
			
		||||
                passes[i].write_render_target_count,
 | 
			
		||||
                RT_RENDERPASS_MAX_WRITES);
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
@ -98,6 +98,16 @@ static size_t GetResourceDataSize(const rt_resource *resource) {
 | 
			
		||||
        const rt_shader_info *info = resource->data;
 | 
			
		||||
        return sizeof(rt_shader_info) + (info) ? info->bytecode_length : 0;
 | 
			
		||||
    } break;
 | 
			
		||||
    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 +
 | 
			
		||||
                      sizeof(rt_render_pass_info) * info->render_pass_count;
 | 
			
		||||
        const rt_render_pass_info *passes = rtResolveConstRelptr(&info->render_passes);
 | 
			
		||||
        for (uint32_t i = 0; i < info->render_pass_count; ++i) {
 | 
			
		||||
            size += passes[i].read_render_target_count * sizeof(rt_render_target_read) +
 | 
			
		||||
                    passes[i].write_render_target_count * sizeof(rt_render_target_write);
 | 
			
		||||
        }
 | 
			
		||||
    } break;
 | 
			
		||||
    default:
 | 
			
		||||
        rtLog("RESMGR", "Tried to get size of an invalid resource type %u", resource->type);
 | 
			
		||||
    }
 | 
			
		||||
@ -117,8 +127,38 @@ 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_FRAMEGRAPH: {
 | 
			
		||||
        const rt_framegraph_info *info = resource->data;
 | 
			
		||||
        rt_framegraph_info *dest_info  = dest;
 | 
			
		||||
        memcpy(dest_info, info, sizeof(*info));
 | 
			
		||||
        memcpy(dest_info + 1,
 | 
			
		||||
               rtResolveConstRelptr(&info->render_targets),
 | 
			
		||||
               info->render_target_count * sizeof(rt_render_target_info));
 | 
			
		||||
        rtSetRelptr(&dest_info->render_targets, (void *)(dest_info + 1));
 | 
			
		||||
        char *passes_begin =
 | 
			
		||||
            (char *)(dest_info + 1) + info->render_target_count * sizeof(rt_render_target_info);
 | 
			
		||||
        memcpy(passes_begin,
 | 
			
		||||
               rtResolveConstRelptr(&info->render_passes),
 | 
			
		||||
               info->render_pass_count * sizeof(rt_render_pass_info));
 | 
			
		||||
        char *read_write_dest = passes_begin + info->render_pass_count * sizeof(rt_render_pass_info);
 | 
			
		||||
        rt_render_pass_info *passes_dest = (rt_render_pass_info *)passes_begin;
 | 
			
		||||
        const rt_render_pass_info *passes =
 | 
			
		||||
            (const rt_render_pass_info *)rtResolveConstRelptr(&info->render_passes);
 | 
			
		||||
        for (uint32_t i = 0; i < info->render_pass_count; ++i) {
 | 
			
		||||
            rtSetRelptr(&passes_dest[i].read_render_targets, read_write_dest);
 | 
			
		||||
            memcpy(read_write_dest,
 | 
			
		||||
                   rtResolveConstRelptr(&passes[i].read_render_targets),
 | 
			
		||||
                   sizeof(rt_render_target_read) * passes[i].read_render_target_count);
 | 
			
		||||
            read_write_dest += sizeof(rt_render_target_read) * passes[i].read_render_target_count;
 | 
			
		||||
            rtSetRelptr(&passes_dest[i].write_render_targets, read_write_dest);
 | 
			
		||||
            memcpy(read_write_dest,
 | 
			
		||||
                   rtResolveConstRelptr(&passes[i].write_render_targets),
 | 
			
		||||
                   sizeof(rt_render_target_write) * passes[i].write_render_target_count);
 | 
			
		||||
            read_write_dest += sizeof(rt_render_target_write) * passes[i].write_render_target_count;
 | 
			
		||||
        }
 | 
			
		||||
    } break;
 | 
			
		||||
    default:
 | 
			
		||||
        rtLog("RESMGR", "Tried to get copy a resource of invalid type %u", resource->type);
 | 
			
		||||
        rtLog("RESMGR", "Tried to copy a resource of invalid type %u", resource->type);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -749,6 +789,15 @@ RT_DLLEXPORT void rtPrefetchResources(const rt_resource_id *ids, uint32_t count)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_resource_id rtGetResourceID(const char *name) {
 | 
			
		||||
    size_t name_len   = strlen(name);
 | 
			
		||||
    rt_resource_id id = (rt_resource_id)rtHashBytes(name, name_len);
 | 
			
		||||
    if (id == RT_INVALID_RESOURCE_ID || id == RT_TOMBSTONE_ID)
 | 
			
		||||
        id = ~id;
 | 
			
		||||
    return id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
 | 
			
		||||
                                         const char **names,
 | 
			
		||||
                                         const rt_resource *resources,
 | 
			
		||||
@ -764,11 +813,7 @@ RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
 | 
			
		||||
 | 
			
		||||
    rtLockWrite(&_namespace.lock);
 | 
			
		||||
    for (uint32_t i = 0; i < count; ++i) {
 | 
			
		||||
        size_t name_len   = strlen(names[i]);
 | 
			
		||||
        rt_resource_id id = (rt_resource_id)rtHashBytes(names[i], name_len);
 | 
			
		||||
        if (id == RT_INVALID_RESOURCE_ID || id == RT_TOMBSTONE_ID)
 | 
			
		||||
            id = ~id;
 | 
			
		||||
 | 
			
		||||
        rt_resource_id id = rtGetResourceID(names[i]);
 | 
			
		||||
        bool inserted = false;
 | 
			
		||||
        for (size_t j = 0; j < ns_size; ++j) {
 | 
			
		||||
            size_t at = (id + j) % ns_size;
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,8 @@ typedef enum {
 | 
			
		||||
    /* A pipeline state object */
 | 
			
		||||
    RT_RESOURCE_PIPELINE,
 | 
			
		||||
 | 
			
		||||
    RT_RESOURCE_FRAMEGRAPH,
 | 
			
		||||
 | 
			
		||||
    RT_RESOURCE_TYPE_count,
 | 
			
		||||
} rt_resource_type;
 | 
			
		||||
 | 
			
		||||
@ -74,6 +76,10 @@ RT_DLLEXPORT void rtPrefetchResources(const rt_resource_id *ids, uint32_t count)
 | 
			
		||||
/* Returns the size of a resource in bytes, or 0 if the resource id is invalid. */
 | 
			
		||||
RT_DLLEXPORT size_t rtGetResourceSize(rt_resource_id id);
 | 
			
		||||
 | 
			
		||||
/* Returns the resource id that maps to a given name.
 | 
			
		||||
 * Does not check if a resource with that id does exist. */
 | 
			
		||||
RT_DLLEXPORT rt_resource_id rtGetResourceID(const char *name);
 | 
			
		||||
 | 
			
		||||
/* Logs information about a resource. Useful for debugging */
 | 
			
		||||
RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resource);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -61,6 +61,26 @@ RT_DLLEXPORT void rtLockWrite(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtUnlockWrite(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
/* Semaphore */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    volatile int counter;
 | 
			
		||||
    int max;
 | 
			
		||||
    rt_condition_var *cond;
 | 
			
		||||
} rt_semaphore;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    bool ok;
 | 
			
		||||
    rt_semaphore semaphore;
 | 
			
		||||
} rt_create_semaphore_result;
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_create_semaphore_result rtCreateSemaphore(int initial_value, int max_value);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtDestroySemaphore(rt_semaphore *sem);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtSignalSemaphore(rt_semaphore *sem);
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtWaitOnSemaphore(rt_semaphore *sem);
 | 
			
		||||
 | 
			
		||||
/* Threads */
 | 
			
		||||
 | 
			
		||||
typedef struct rt_thread_s rt_thread;
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
#include "threading.h"
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
/* Based on: https://eli.thegreenplace.net/2019/implementing-reader-writer-locks/ */
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT rt_create_rwlock_result rtCreateRWLock(void) {
 | 
			
		||||
@ -26,7 +24,7 @@ RT_DLLEXPORT void rtLockRead(rt_rwlock *lock) {
 | 
			
		||||
 | 
			
		||||
RT_DLLEXPORT void rtUnlockRead(rt_rwlock *lock) {
 | 
			
		||||
    rtLockConditionVar(lock->cond);
 | 
			
		||||
    assert(lock->reader_count > 0);
 | 
			
		||||
    RT_ASSERT(lock->reader_count > 0, "Tried to unlock a read-write lock that is not held.");
 | 
			
		||||
    --lock->reader_count;
 | 
			
		||||
    bool signal = lock->reader_count == 0;
 | 
			
		||||
    rtUnlockConditionVar(lock->cond, signal);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user