rename the engine to recreational.tech
This commit is contained in:
		
							parent
							
								
									448d448430
								
							
						
					
					
						commit
						abb367dffc
					
				
							
								
								
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -4,4 +4,7 @@
 | 
			
		||||
 | 
			
		||||
# assetc directories
 | 
			
		||||
/actemp/*
 | 
			
		||||
/data/*
 | 
			
		||||
/data/*
 | 
			
		||||
 | 
			
		||||
/.cache/*
 | 
			
		||||
/.vs/*
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								meson.build
									
									
									
									
									
								
							@ -22,16 +22,16 @@ elif compiler.get_argument_syntax() == 'msvc'
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if get_option('default_library') == 'static'
 | 
			
		||||
  add_project_arguments(['-DVY_STATIC_LIB'], language : 'c')
 | 
			
		||||
  add_project_arguments(['-DRT_STATIC_LIB'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if get_option('error_report_debugbreak')
 | 
			
		||||
  add_project_arguments(['-DVY_ERROR_REPORT_DEBUGBREAK'], language : 'c')
 | 
			
		||||
  add_project_arguments(['-DRT_ERROR_REPORT_DEBUGBREAK'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Debug specific flags
 | 
			
		||||
if buildtype == 'debug' or buildtype == 'debugoptimized'
 | 
			
		||||
  add_project_arguments([ '-DVY_DEBUG'], language : 'c')
 | 
			
		||||
  add_project_arguments([ '-DRT_DEBUG'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Gather dependencies
 | 
			
		||||
@ -42,12 +42,12 @@ vk_dep = dependency('vulkan', required : false)
 | 
			
		||||
windowing_dep = []
 | 
			
		||||
if get_option('use_xlib')
 | 
			
		||||
  windowing_dep = dependency('x11', required : true)
 | 
			
		||||
  add_project_arguments(['-DVY_USE_XLIB'], language : 'c')
 | 
			
		||||
  add_project_arguments(['-DRT_USE_XLIB'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
incdir = include_directories(['contrib', 'src'])
 | 
			
		||||
 | 
			
		||||
runtime_lib = library('vyrt',
 | 
			
		||||
runtime_lib = library('rt',
 | 
			
		||||
  # Project Sources
 | 
			
		||||
  'src/runtime/aio.h',
 | 
			
		||||
  'src/runtime/app.h',
 | 
			
		||||
@ -107,7 +107,7 @@ if vk_dep.found()
 | 
			
		||||
  endif
 | 
			
		||||
 | 
			
		||||
  vk_inc_dep = vk_dep.partial_dependency(compile_args : true, includes : true)
 | 
			
		||||
  vk_renderer_lib = library('vyvk',
 | 
			
		||||
  vk_renderer_lib = library('rtvk',
 | 
			
		||||
    # Project Sources
 | 
			
		||||
    'src/renderer/vk/gpu.h',
 | 
			
		||||
    'src/renderer/vk/swapchain.h',
 | 
			
		||||
@ -177,7 +177,7 @@ executable('assetc',
 | 
			
		||||
  link_args : ['-L'+shaderc_libdir, '-lshaderc_combined'],
 | 
			
		||||
  win_subsystem : 'console')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Game
 | 
			
		||||
executable('voyage',
 | 
			
		||||
  'src/game/voyage.c',
 | 
			
		||||
  include_directories : incdir,
 | 
			
		||||
@ -190,4 +190,4 @@ rttest_exe = executable('rttest',
 | 
			
		||||
  link_with : runtime_link_libs,
 | 
			
		||||
  include_directories : incdir,
 | 
			
		||||
  win_subsystem : 'console')
 | 
			
		||||
test('runtime test', rttest_exe)
 | 
			
		||||
test('runtime test', rttest_exe)
 | 
			
		||||
 | 
			
		||||
@ -6,13 +6,13 @@
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
 | 
			
		||||
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
 | 
			
		||||
    return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
			
		||||
    return rtWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
    return vyXlibEntry(argc, argv);
 | 
			
		||||
    return rtXlibEntry(argc, argv);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,22 @@
 | 
			
		||||
#ifndef VY_VK_FRAMEBUFFER_H
 | 
			
		||||
#define VY_VK_FRAMEBUFFER_H
 | 
			
		||||
#ifndef RT_VK_FRAMEBUFFER_H
 | 
			
		||||
#define RT_VK_FRAMEBUFFER_H
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkFramebuffer framebuffer;
 | 
			
		||||
    uint32_t pass_idx;
 | 
			
		||||
} vy_framebuffer;
 | 
			
		||||
} rt_framebuffer;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
} vy_framebuffer_handle;
 | 
			
		||||
} rt_framebuffer_handle;
 | 
			
		||||
 | 
			
		||||
/* Reserve a slot, but don't actually create the framebuffer yet.
 | 
			
		||||
 * We can use this if we are unsure if the framebuffer will really be needed.
 | 
			
		||||
 */
 | 
			
		||||
vy_framebuffer_handle vy_reserve_framebuffer(void);
 | 
			
		||||
rt_framebuffer_handle rt_reserve_framebuffer(void);
 | 
			
		||||
 | 
			
		||||
vy_framebuffer *vy_get_framebuffer(vy_framebuffer_handle handle);
 | 
			
		||||
rt_framebuffer *rt_get_framebuffer(rt_framebuffer_handle handle);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
#ifndef VY_VK_GPU_H
 | 
			
		||||
#define VY_VK_GPU_H
 | 
			
		||||
#ifndef RT_VK_GPU_H
 | 
			
		||||
#define RT_VK_GPU_H
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
struct HINSTANCE__;
 | 
			
		||||
struct HWND__;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
struct _XDisplay;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -14,11 +14,11 @@ typedef struct {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    struct HINSTANCE__ *hInstance;
 | 
			
		||||
    struct HWND__ *hWnd;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
    struct _XDisplay *display;
 | 
			
		||||
    unsigned long window;
 | 
			
		||||
#endif
 | 
			
		||||
} vy_native_window;
 | 
			
		||||
} rt_native_window;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkInstance instance;
 | 
			
		||||
@ -34,14 +34,14 @@ typedef struct {
 | 
			
		||||
    uint32_t compute_family;
 | 
			
		||||
    uint32_t present_family;
 | 
			
		||||
 | 
			
		||||
    vy_native_window native_window;
 | 
			
		||||
    rt_native_window native_window;
 | 
			
		||||
 | 
			
		||||
    VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props;
 | 
			
		||||
    VkPhysicalDeviceProperties phys_device_props;
 | 
			
		||||
} vy_vk_gpu;
 | 
			
		||||
} rt_vk_gpu;
 | 
			
		||||
 | 
			
		||||
#ifndef VY_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
extern vy_vk_gpu g_gpu;
 | 
			
		||||
#ifndef RT_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
extern rt_vk_gpu g_gpu;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define VY_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
#define RT_VK_DONT_DEFINE_GPU_GLOBAL
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
 | 
			
		||||
@ -10,13 +10,13 @@
 | 
			
		||||
#include "runtime/renderer_api.h"
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(r_VkEnableAPIAllocTracking,
 | 
			
		||||
RT_CVAR_I(r_VkEnableAPIAllocTracking,
 | 
			
		||||
          "Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
 | 
			
		||||
          0);
 | 
			
		||||
 | 
			
		||||
VY_CVAR_S(r_VkPhysDeviceName, "Name of the selected physical device. Default: \"\"", "");
 | 
			
		||||
RT_CVAR_S(r_VkPhysDeviceName, "Name of the selected physical device. Default: \"\"", "");
 | 
			
		||||
 | 
			
		||||
vy_vk_gpu g_gpu;
 | 
			
		||||
rt_vk_gpu g_gpu;
 | 
			
		||||
 | 
			
		||||
static VkAllocationCallbacks _tracking_alloc_cbs;
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ static const char *AllocationScopeToString(VkSystemAllocationScope scope) {
 | 
			
		||||
 | 
			
		||||
static void *
 | 
			
		||||
TrackAllocation(void *userData, size_t size, size_t alignment, VkSystemAllocationScope scope) {
 | 
			
		||||
    vyLog("vk",
 | 
			
		||||
    rtLog("vk",
 | 
			
		||||
          "Allocation. Size: %zu, Alignment: %zu, Scope: %s",
 | 
			
		||||
          size,
 | 
			
		||||
          alignment,
 | 
			
		||||
@ -56,7 +56,7 @@ static void *TrackReallocation(void *userData,
 | 
			
		||||
                               size_t size,
 | 
			
		||||
                               size_t alignment,
 | 
			
		||||
                               VkSystemAllocationScope scope) {
 | 
			
		||||
    vyLog("vk",
 | 
			
		||||
    rtLog("vk",
 | 
			
		||||
          "Reallocation. Size: %zu, Alignment: %zu, Scope: %s",
 | 
			
		||||
          size,
 | 
			
		||||
          alignment,
 | 
			
		||||
@ -77,20 +77,20 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
 | 
			
		||||
    return VK_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern vy_cvar r_VkPreferredSwapchainImages;
 | 
			
		||||
extern vy_cvar r_VkPreferMailboxMode;
 | 
			
		||||
extern rt_cvar r_VkPreferredSwapchainImages;
 | 
			
		||||
extern rt_cvar r_VkPreferMailboxMode;
 | 
			
		||||
 | 
			
		||||
void VY_RENDERER_API_FN(RegisterCVars)(void) {
 | 
			
		||||
    vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPhysDeviceName);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPreferredSwapchainImages);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPreferMailboxMode);
 | 
			
		||||
void RT_RENDERER_API_FN(RegisterCVars)(void) {
 | 
			
		||||
    rtRegisterCVAR(&r_VkEnableAPIAllocTracking);
 | 
			
		||||
    rtRegisterCVAR(&r_VkPhysDeviceName);
 | 
			
		||||
    rtRegisterCVAR(&r_VkPreferredSwapchainImages);
 | 
			
		||||
    rtRegisterCVAR(&r_VkPreferMailboxMode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result CreateInstance(void) {
 | 
			
		||||
static rt_result CreateInstance(void) {
 | 
			
		||||
    VkResult result = volkInitialize();
 | 
			
		||||
    if (result != VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Initialization failed: volkInitialize()");
 | 
			
		||||
        rtReportError("vk", "Initialization failed: volkInitialize()");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -106,18 +106,18 @@ static vy_result CreateInstance(void) {
 | 
			
		||||
        VK_KHR_SURFACE_EXTENSION_NAME,
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        "VK_KHR_win32_surface",
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
        "VK_KHR_xlib_surface",
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef VY_DEBUG
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
        VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
 | 
			
		||||
#endif
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const char *layers[1];
 | 
			
		||||
    unsigned int layer_count = 0;
 | 
			
		||||
#ifdef VY_DEBUG
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    /* Search for layers we want to enable */
 | 
			
		||||
    uint32_t available_layer_count = 0;
 | 
			
		||||
    result = vkEnumerateInstanceLayerProperties(&available_layer_count, NULL);
 | 
			
		||||
@ -134,10 +134,10 @@ static vy_result CreateInstance(void) {
 | 
			
		||||
            }
 | 
			
		||||
            free(props);
 | 
			
		||||
        } else {
 | 
			
		||||
            vyLog("vk", "Failed to allocate storage for instance layer properties.");
 | 
			
		||||
            rtLog("vk", "Failed to allocate storage for instance layer properties.");
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        vyLog("vk", "vkEnumerateInstanceLayerProperties failed.");
 | 
			
		||||
        rtLog("vk", "vkEnumerateInstanceLayerProperties failed.");
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -145,18 +145,18 @@ static vy_result CreateInstance(void) {
 | 
			
		||||
        .sType                   = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
 | 
			
		||||
        .pApplicationInfo        = &app_info,
 | 
			
		||||
        .ppEnabledExtensionNames = extensions,
 | 
			
		||||
        .enabledExtensionCount   = VY_ARRAY_COUNT(extensions),
 | 
			
		||||
        .enabledExtensionCount   = RT_ARRAY_COUNT(extensions),
 | 
			
		||||
        .ppEnabledLayerNames     = layers,
 | 
			
		||||
        .enabledLayerCount       = layer_count,
 | 
			
		||||
    };
 | 
			
		||||
    result = vkCreateInstance(&instance_info, g_gpu.alloc_cb, &g_gpu.instance);
 | 
			
		||||
    if (result != VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Failed to create the vulkan instance.");
 | 
			
		||||
        rtReportError("vk", "Failed to create the vulkan instance.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    volkLoadInstance(g_gpu.instance);
 | 
			
		||||
 | 
			
		||||
#ifdef VY_DEBUG
 | 
			
		||||
#ifdef RT_DEBUG
 | 
			
		||||
    /* Create the debug utils messenger */
 | 
			
		||||
    VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
 | 
			
		||||
        .sType           = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
			
		||||
@ -171,10 +171,10 @@ static vy_result CreateInstance(void) {
 | 
			
		||||
                                   g_gpu.alloc_cb,
 | 
			
		||||
                                   &g_gpu.messenger);
 | 
			
		||||
#endif
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result CreateSurface(const vy_renderer_init_info *info) {
 | 
			
		||||
static rt_result CreateSurface(const rt_renderer_init_info *info) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    g_gpu.native_window.hInstance            = info->hInstance;
 | 
			
		||||
    g_gpu.native_window.hWnd                 = info->hWnd;
 | 
			
		||||
@ -185,10 +185,10 @@ static vy_result CreateSurface(const vy_renderer_init_info *info) {
 | 
			
		||||
    };
 | 
			
		||||
    if (vkCreateWin32SurfaceKHR(g_gpu.instance, &surface_info, g_gpu.alloc_cb, &g_gpu.surface) ==
 | 
			
		||||
        VK_SUCCESS)
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    else
 | 
			
		||||
        return 100;
 | 
			
		||||
#elif defined(VY_USE_XLIB_KHR)
 | 
			
		||||
#elif defined(RT_USE_XLIB_KHR)
 | 
			
		||||
    g_gpu.native_window.display             = info->display;
 | 
			
		||||
    g_gpu.native_window.window              = info->window;
 | 
			
		||||
    VkXlibSurfaceCreateInfoKHR surface_info = {
 | 
			
		||||
@ -198,7 +198,7 @@ static vy_result CreateSurface(const vy_renderer_init_info *info) {
 | 
			
		||||
    };
 | 
			
		||||
    if (vkCreateXlibSurfaceKHR(g_gpu.instance, &surface_info, &g_gpu.alloc_cb, &g_gpu.surface) ==
 | 
			
		||||
        VK_SUCCESS)
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    else
 | 
			
		||||
        return 100;
 | 
			
		||||
#endif
 | 
			
		||||
@ -208,10 +208,10 @@ typedef struct {
 | 
			
		||||
    uint32_t graphics;
 | 
			
		||||
    uint32_t compute;
 | 
			
		||||
    uint32_t present;
 | 
			
		||||
} vy_queue_indices;
 | 
			
		||||
} rt_queue_indices;
 | 
			
		||||
 | 
			
		||||
static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfaceKHR surface) {
 | 
			
		||||
    vy_queue_indices indices = {.graphics = UINT32_MAX,
 | 
			
		||||
static rt_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfaceKHR surface) {
 | 
			
		||||
    rt_queue_indices indices = {.graphics = UINT32_MAX,
 | 
			
		||||
                                .compute  = UINT32_MAX,
 | 
			
		||||
                                .present  = UINT32_MAX};
 | 
			
		||||
 | 
			
		||||
@ -254,7 +254,7 @@ static bool CheckDeviceExtensionSupported(VkPhysicalDevice phys_dev) {
 | 
			
		||||
    vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &extension_count, supported_extensions);
 | 
			
		||||
 | 
			
		||||
    bool supported = true;
 | 
			
		||||
    for (uint32_t i = 0; i < VY_ARRAY_COUNT(required_extensions); ++i) {
 | 
			
		||||
    for (uint32_t i = 0; i < RT_ARRAY_COUNT(required_extensions); ++i) {
 | 
			
		||||
        bool found = false;
 | 
			
		||||
        for (uint32_t j = 0; j < extension_count; ++j) {
 | 
			
		||||
            if (strncmp(supported_extensions[j].extensionName,
 | 
			
		||||
@ -275,18 +275,18 @@ out:
 | 
			
		||||
    return supported;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result ChoosePhysicalDevice(void) {
 | 
			
		||||
static rt_result ChoosePhysicalDevice(void) {
 | 
			
		||||
 | 
			
		||||
    g_gpu.phys_device          = VK_NULL_HANDLE;
 | 
			
		||||
    uint32_t phys_device_count = 0;
 | 
			
		||||
    VkResult result = vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
 | 
			
		||||
    if (result != VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Failed to enumerate the physical devices.");
 | 
			
		||||
        rtReportError("vk", "Failed to enumerate the physical devices.");
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
    VkPhysicalDevice *phys_devices = calloc(phys_device_count, sizeof(VkPhysicalDevice));
 | 
			
		||||
    if (!phys_devices) {
 | 
			
		||||
        vyReportError("vk", "Failed to enumerate the physical devices: Out of memory.");
 | 
			
		||||
        rtReportError("vk", "Failed to enumerate the physical devices: Out of memory.");
 | 
			
		||||
        return 2;
 | 
			
		||||
    }
 | 
			
		||||
    vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, phys_devices);
 | 
			
		||||
@ -307,7 +307,7 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
			
		||||
        if (!CheckDeviceExtensionSupported(phys_devices[i]))
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        vy_queue_indices indices = RetrieveQueueIndices(phys_devices[i], g_gpu.surface);
 | 
			
		||||
        rt_queue_indices indices = RetrieveQueueIndices(phys_devices[i], g_gpu.surface);
 | 
			
		||||
        if (indices.compute == UINT32_MAX || indices.present == UINT32_MAX ||
 | 
			
		||||
            indices.graphics == UINT32_MAX)
 | 
			
		||||
            continue;
 | 
			
		||||
@ -354,18 +354,18 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
			
		||||
    free(phys_devices);
 | 
			
		||||
 | 
			
		||||
    if (g_gpu.phys_device == VK_NULL_HANDLE) {
 | 
			
		||||
        vyReportError("vk", "Failed to find a suitable physical device.");
 | 
			
		||||
        rtReportError("vk", "Failed to find a suitable physical device.");
 | 
			
		||||
        return 3;
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result CreateDevice(void) {
 | 
			
		||||
static rt_result CreateDevice(void) {
 | 
			
		||||
    const char *extensions[] = {
 | 
			
		||||
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    vy_queue_indices queue_indices = RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
 | 
			
		||||
    rt_queue_indices queue_indices = RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
 | 
			
		||||
 | 
			
		||||
    g_gpu.compute_family  = queue_indices.compute;
 | 
			
		||||
    g_gpu.graphics_family = queue_indices.graphics;
 | 
			
		||||
@ -402,14 +402,14 @@ static vy_result CreateDevice(void) {
 | 
			
		||||
 | 
			
		||||
    VkDeviceCreateInfo device_info = {
 | 
			
		||||
        .sType                   = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
 | 
			
		||||
        .enabledExtensionCount   = VY_ARRAY_COUNT(extensions),
 | 
			
		||||
        .enabledExtensionCount   = RT_ARRAY_COUNT(extensions),
 | 
			
		||||
        .ppEnabledExtensionNames = extensions,
 | 
			
		||||
        .pQueueCreateInfos       = queue_info,
 | 
			
		||||
        .queueCreateInfoCount    = distinct_queue_count,
 | 
			
		||||
    };
 | 
			
		||||
    if (vkCreateDevice(g_gpu.phys_device, &device_info, g_gpu.alloc_cb, &g_gpu.device) !=
 | 
			
		||||
        VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Device creation failed.");
 | 
			
		||||
        rtReportError("vk", "Device creation failed.");
 | 
			
		||||
        return 10;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -417,14 +417,14 @@ static vy_result CreateDevice(void) {
 | 
			
		||||
    vkGetDeviceQueue(g_gpu.device, queue_indices.compute, 0, &g_gpu.compute_queue);
 | 
			
		||||
    vkGetDeviceQueue(g_gpu.device, queue_indices.present, 0, &g_gpu.present_queue);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern vy_result InitPipelineManagement(void);
 | 
			
		||||
extern rt_result InitPipelineManagement(void);
 | 
			
		||||
extern void ShutdownPipelineManagement(void);
 | 
			
		||||
 | 
			
		||||
vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *info) {
 | 
			
		||||
    vyLog("vk", "Init");
 | 
			
		||||
rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *info) {
 | 
			
		||||
    rtLog("vk", "Init");
 | 
			
		||||
 | 
			
		||||
    _tracking_alloc_cbs.pUserData       = NULL;
 | 
			
		||||
    _tracking_alloc_cbs.pfnAllocation   = TrackAllocation;
 | 
			
		||||
@ -438,31 +438,31 @@ vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *info) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int res = CreateInstance();
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = CreateSurface(info);
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = ChoosePhysicalDevice();
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = CreateDevice();
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = InitPipelineManagement();
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = vyCreateSwapchain();
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    res = rtCreateSwapchain();
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VY_RENDERER_API_FN(Shutdown)(void) {
 | 
			
		||||
    vyLog("vk", "Shutdown");
 | 
			
		||||
void RT_RENDERER_API_FN(Shutdown)(void) {
 | 
			
		||||
    rtLog("vk", "Shutdown");
 | 
			
		||||
    vkDeviceWaitIdle(g_gpu.device);
 | 
			
		||||
    vyDestroySwapchain();
 | 
			
		||||
    rtDestroySwapchain();
 | 
			
		||||
    ShutdownPipelineManagement();
 | 
			
		||||
    vkDestroyDevice(g_gpu.device, g_gpu.alloc_cb);
 | 
			
		||||
    vkDestroySurfaceKHR(g_gpu.instance, g_gpu.surface, g_gpu.alloc_cb);
 | 
			
		||||
 | 
			
		||||
@ -9,38 +9,38 @@
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(r_VkMaxPipelineCount, "Maximum number of pipeline objects. Default: 1024", 1024);
 | 
			
		||||
RT_CVAR_I(r_VkMaxPipelineCount, "Maximum number of pipeline objects. Default: 1024", 1024);
 | 
			
		||||
 | 
			
		||||
typedef struct vy_pipeline_s {
 | 
			
		||||
typedef struct rt_pipeline_s {
 | 
			
		||||
    uint32_t version;
 | 
			
		||||
    vy_pipeline pipeline;
 | 
			
		||||
    struct vy_pipeline_s *next_free;
 | 
			
		||||
} vy_pipeline_slot;
 | 
			
		||||
    rt_pipeline pipeline;
 | 
			
		||||
    struct rt_pipeline_s *next_free;
 | 
			
		||||
} rt_pipeline_slot;
 | 
			
		||||
 | 
			
		||||
static vy_pipeline_slot *_pipelines;
 | 
			
		||||
static vy_pipeline_slot *_first_free;
 | 
			
		||||
static vy_rwlock _lock;
 | 
			
		||||
static rt_pipeline_slot *_pipelines;
 | 
			
		||||
static rt_pipeline_slot *_first_free;
 | 
			
		||||
static rt_rwlock _lock;
 | 
			
		||||
 | 
			
		||||
vy_result InitPipelineManagement(void) {
 | 
			
		||||
    vy_create_rwlock_result lock_res = vyCreateRWLock();
 | 
			
		||||
rt_result InitPipelineManagement(void) {
 | 
			
		||||
    rt_create_rwlock_result lock_res = rtCreateRWLock();
 | 
			
		||||
    if (!lock_res.ok)
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    _lock = lock_res.lock;
 | 
			
		||||
 | 
			
		||||
    _pipelines = calloc(r_VkMaxPipelineCount.i, sizeof(vy_pipeline_slot));
 | 
			
		||||
    _pipelines = calloc(r_VkMaxPipelineCount.i, sizeof(rt_pipeline_slot));
 | 
			
		||||
    if (!_pipelines) {
 | 
			
		||||
        vyDestroyRWLock(&_lock);
 | 
			
		||||
        return VY_OUT_OF_MEMORY;
 | 
			
		||||
        rtDestroyRWLock(&_lock);
 | 
			
		||||
        return RT_OUT_OF_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
    /* Keep [0] unused to preserve 0 as the invalid handle */
 | 
			
		||||
    _first_free = &_pipelines[1];
 | 
			
		||||
    for (int i = 1; i < r_VkMaxPipelineCount.i - 1; ++i) {
 | 
			
		||||
        _pipelines[i].next_free = &_pipelines[i + 1];
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void DestroyPipeline(vy_pipeline_slot *slot) {
 | 
			
		||||
static void DestroyPipeline(rt_pipeline_slot *slot) {
 | 
			
		||||
    if (slot->pipeline.pipeline) {
 | 
			
		||||
        vkDestroyPipeline(g_gpu.device, slot->pipeline.pipeline, g_gpu.alloc_cb);
 | 
			
		||||
    }
 | 
			
		||||
@ -53,22 +53,22 @@ void ShutdownPipelineManagement(void) {
 | 
			
		||||
        DestroyPipeline(&_pipelines[i]);
 | 
			
		||||
    }
 | 
			
		||||
    free(_pipelines);
 | 
			
		||||
    vyDestroyRWLock(&_lock);
 | 
			
		||||
    rtDestroyRWLock(&_lock);
 | 
			
		||||
    _first_free = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_pipeline_handle VY_RENDERER_API_FN(CompilePipeline)(const vy_pipeline_info *info) {
 | 
			
		||||
    vy_pipeline_handle handle = VY_INVALID_HANDLE;
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *info) {
 | 
			
		||||
    rt_pipeline_handle handle = RT_INVALID_HANDLE;
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    if (!_first_free) {
 | 
			
		||||
        vyLog("VK", "No free pipeline slots!");
 | 
			
		||||
        vyUnlockWrite(&_lock);
 | 
			
		||||
        rtLog("VK", "No free pipeline slots!");
 | 
			
		||||
        rtUnlockWrite(&_lock);
 | 
			
		||||
        return handle;
 | 
			
		||||
    }
 | 
			
		||||
    vy_pipeline_slot *slot = _first_free;
 | 
			
		||||
    rt_pipeline_slot *slot = _first_free;
 | 
			
		||||
    _first_free            = slot->next_free;
 | 
			
		||||
    slot->version = (slot->version + 1) & VY_GFX_HANDLE_MAX_VERSION;
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    slot->version = (slot->version + 1) & RT_GFX_HANDLE_MAX_VERSION;
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
 | 
			
		||||
    /* No other thread that calls compile gets the same slot.
 | 
			
		||||
     * Another thread accessing the slot via GetPipeline would get a version mismatch.
 | 
			
		||||
@ -78,26 +78,26 @@ vy_pipeline_handle VY_RENDERER_API_FN(CompilePipeline)(const vy_pipeline_info *i
 | 
			
		||||
    return handle;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void VY_RENDERER_API_FN(DestroyPipeline)(vy_pipeline_handle handle) {
 | 
			
		||||
void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle) {
 | 
			
		||||
    if (handle.index >= (uint32_t)r_VkMaxPipelineCount.i)
 | 
			
		||||
        return;
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    if (_pipelines[handle.index].version == handle.version)
 | 
			
		||||
        DestroyPipeline(&_pipelines[handle.index]);
 | 
			
		||||
    else
 | 
			
		||||
        vyLog("VK", "Tried to destroy a pipeline using an outdated handle.");
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
        rtLog("VK", "Tried to destroy a pipeline using an outdated handle.");
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const vy_pipeline *vyGetPipeline(vy_pipeline_handle handle) {
 | 
			
		||||
const rt_pipeline *rtGetPipeline(rt_pipeline_handle handle) {
 | 
			
		||||
    if (handle.index >= (uint32_t)r_VkMaxPipelineCount.i)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    vyLockRead(&_lock);
 | 
			
		||||
    vy_pipeline *res = NULL;
 | 
			
		||||
    rtLockRead(&_lock);
 | 
			
		||||
    rt_pipeline *res = NULL;
 | 
			
		||||
    if (_pipelines[handle.index].version == handle.version)
 | 
			
		||||
        res = &_pipelines[handle.index].pipeline;
 | 
			
		||||
    else
 | 
			
		||||
        vyLog("VK", "Tried to access a pipeline using an outdated handle.");
 | 
			
		||||
    vyUnlockRead(&_lock);
 | 
			
		||||
        rtLog("VK", "Tried to access a pipeline using an outdated handle.");
 | 
			
		||||
    rtUnlockRead(&_lock);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_VK_PIPELINES_H
 | 
			
		||||
#define VY_VK_PIPELINES_H
 | 
			
		||||
#ifndef RT_VK_PIPELINES_H
 | 
			
		||||
#define RT_VK_PIPELINES_H
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
@ -7,9 +7,9 @@
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkPipeline pipeline;
 | 
			
		||||
} vy_pipeline;
 | 
			
		||||
} rt_pipeline;
 | 
			
		||||
 | 
			
		||||
/* A pipeline is immutable after creation. */
 | 
			
		||||
const vy_pipeline *vyGetPipeline(vy_pipeline_handle handle);
 | 
			
		||||
const rt_pipeline *rtGetPipeline(rt_pipeline_handle handle);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#define VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
#define RT_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
#include "swapchain.h"
 | 
			
		||||
#include "gpu.h"
 | 
			
		||||
 | 
			
		||||
@ -9,24 +9,24 @@
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
			
		||||
RT_CVAR_I(r_VkPreferredSwapchainImages,
 | 
			
		||||
          "Preferred number of swapchain iamges. [2/3] Default: 2",
 | 
			
		||||
          2);
 | 
			
		||||
VY_CVAR_I(r_VkPreferMailboxMode, "Prefer mailbox present mode over fifo mode. [0/1] Default: 0", 1);
 | 
			
		||||
RT_CVAR_I(r_VkPreferMailboxMode, "Prefer mailbox present mode over fifo mode. [0/1] Default: 0", 1);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkPresentModeKHR present_mode;
 | 
			
		||||
    VkSurfaceFormatKHR surface_format;
 | 
			
		||||
    VkExtent2D extent;
 | 
			
		||||
    VkSurfaceTransformFlagsKHR pre_transform;
 | 
			
		||||
} vy_device_swapchain_parameters;
 | 
			
		||||
} rt_device_swapchain_parameters;
 | 
			
		||||
 | 
			
		||||
static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
			
		||||
    vy_device_swapchain_parameters params;
 | 
			
		||||
static rt_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
			
		||||
    rt_device_swapchain_parameters params;
 | 
			
		||||
 | 
			
		||||
    /* determine presentation mode. FIFO should always be available */
 | 
			
		||||
    params.present_mode = VK_PRESENT_MODE_FIFO_KHR;
 | 
			
		||||
@ -76,10 +76,10 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
			
		||||
    return params;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_swapchain g_swapchain;
 | 
			
		||||
rt_swapchain g_swapchain;
 | 
			
		||||
 | 
			
		||||
vy_result vyCreateSwapchain(void) {
 | 
			
		||||
    vy_device_swapchain_parameters device_params = DetermineSwapchainParameters();
 | 
			
		||||
rt_result rtCreateSwapchain(void) {
 | 
			
		||||
    rt_device_swapchain_parameters device_params = DetermineSwapchainParameters();
 | 
			
		||||
 | 
			
		||||
    uint32_t image_count = r_VkPreferredSwapchainImages.i;
 | 
			
		||||
    if (image_count < 2)
 | 
			
		||||
@ -117,7 +117,7 @@ vy_result vyCreateSwapchain(void) {
 | 
			
		||||
                             &swapchain_info,
 | 
			
		||||
                             g_gpu.alloc_cb,
 | 
			
		||||
                             &g_swapchain.swapchain) != VK_SUCCESS) {
 | 
			
		||||
        vyReportError("vk", "Failed to create the swapchain");
 | 
			
		||||
        rtReportError("vk", "Failed to create the swapchain");
 | 
			
		||||
        return 50;
 | 
			
		||||
    }
 | 
			
		||||
    g_swapchain.format = device_params.surface_format.format;
 | 
			
		||||
@ -125,8 +125,8 @@ vy_result vyCreateSwapchain(void) {
 | 
			
		||||
    /* Retrieve images */
 | 
			
		||||
    g_swapchain.image_count = 0;
 | 
			
		||||
    vkGetSwapchainImagesKHR(g_gpu.device, g_swapchain.swapchain, &g_swapchain.image_count, NULL);
 | 
			
		||||
    if (g_swapchain.image_count > VY_VK_MAX_SWAPCHAIN_IMAGES) {
 | 
			
		||||
        vyReportError("vk", "Unsupported number of swapchain images: %u", g_swapchain.image_count);
 | 
			
		||||
    if (g_swapchain.image_count > RT_VK_MAX_SWAPCHAIN_IMAGES) {
 | 
			
		||||
        rtReportError("vk", "Unsupported number of swapchain images: %u", g_swapchain.image_count);
 | 
			
		||||
        return 51;
 | 
			
		||||
    }
 | 
			
		||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
			
		||||
@ -161,21 +161,21 @@ vy_result vyCreateSwapchain(void) {
 | 
			
		||||
                              &view_info,
 | 
			
		||||
                              g_gpu.alloc_cb,
 | 
			
		||||
                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
			
		||||
            vyReportError("vk", "Failed to create an image view for the swapchain.");
 | 
			
		||||
            rtReportError("vk", "Failed to create an image view for the swapchain.");
 | 
			
		||||
            return 52;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyRecreateSwapchain(void) {
 | 
			
		||||
rt_result rtRecreateSwapchain(void) {
 | 
			
		||||
    /* TODO(Kevin): Old swapchain in swapchain create info */
 | 
			
		||||
    vyDestroySwapchain();
 | 
			
		||||
    return vyCreateSwapchain();
 | 
			
		||||
    rtDestroySwapchain();
 | 
			
		||||
    return rtCreateSwapchain();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyDestroySwapchain(void) {
 | 
			
		||||
void rtDestroySwapchain(void) {
 | 
			
		||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
			
		||||
        vkDestroyImageView(g_gpu.device, g_swapchain.image_views[i], g_gpu.alloc_cb);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,28 +1,28 @@
 | 
			
		||||
#ifndef VY_VK_SWAPCHAIN_H
 | 
			
		||||
#define VY_VK_SWAPCHAIN_H
 | 
			
		||||
#ifndef RT_VK_SWAPCHAIN_H
 | 
			
		||||
#define RT_VK_SWAPCHAIN_H
 | 
			
		||||
 | 
			
		||||
#include <volk/volk.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
#define VY_VK_MAX_SWAPCHAIN_IMAGES 3
 | 
			
		||||
#define RT_VK_MAX_SWAPCHAIN_IMAGES 3
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    VkSwapchainKHR swapchain;
 | 
			
		||||
    VkImage images[VY_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    VkImageView image_views[VY_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    VkImage images[RT_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    VkImageView image_views[RT_VK_MAX_SWAPCHAIN_IMAGES];
 | 
			
		||||
    uint32_t image_count;
 | 
			
		||||
    VkFormat format;
 | 
			
		||||
} vy_swapchain;
 | 
			
		||||
} rt_swapchain;
 | 
			
		||||
 | 
			
		||||
#ifndef VY_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
extern vy_swapchain g_swapchain;
 | 
			
		||||
#ifndef RT_VK_DONT_DEFINE_SWAPCHAIN_GLOBAL
 | 
			
		||||
extern rt_swapchain g_swapchain;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
vy_result vyCreateSwapchain(void);
 | 
			
		||||
rt_result rtCreateSwapchain(void);
 | 
			
		||||
 | 
			
		||||
vy_result vyRecreateSwapchain(void);
 | 
			
		||||
rt_result rtRecreateSwapchain(void);
 | 
			
		||||
 | 
			
		||||
void vyDestroySwapchain(void);
 | 
			
		||||
void rtDestroySwapchain(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -21,33 +21,33 @@ typedef struct {
 | 
			
		||||
    HANDLE file_handle;
 | 
			
		||||
    OVERLAPPED overlapped;
 | 
			
		||||
#endif
 | 
			
		||||
    volatile vy_aio_state state;
 | 
			
		||||
} vy_aio;
 | 
			
		||||
    volatile rt_aio_state state;
 | 
			
		||||
} rt_aio;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_mutex *guard;
 | 
			
		||||
    rt_mutex *guard;
 | 
			
		||||
 | 
			
		||||
    vy_aio *storage;
 | 
			
		||||
    rt_aio *storage;
 | 
			
		||||
    uint32_t capacity;
 | 
			
		||||
    uint32_t head;
 | 
			
		||||
    uint32_t tail;
 | 
			
		||||
} vy_aio_ringbuffer;
 | 
			
		||||
} rt_aio_ringbuffer;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_aio *a;
 | 
			
		||||
    vy_aio *b;
 | 
			
		||||
    rt_aio *a;
 | 
			
		||||
    rt_aio *b;
 | 
			
		||||
    uint32_t a_count;
 | 
			
		||||
} vy_ringbuffer_space;
 | 
			
		||||
} rt_ringbuffer_space;
 | 
			
		||||
 | 
			
		||||
static vy_aio_ringbuffer _ringbuffer;
 | 
			
		||||
static rt_aio_ringbuffer _ringbuffer;
 | 
			
		||||
 | 
			
		||||
static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
			
		||||
    if (!vyLockMutex(_ringbuffer.guard)) {
 | 
			
		||||
        vy_ringbuffer_space failed = {NULL, NULL, 0};
 | 
			
		||||
static rt_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
			
		||||
    if (!rtLockMutex(_ringbuffer.guard)) {
 | 
			
		||||
        rt_ringbuffer_space failed = {NULL, NULL, 0};
 | 
			
		||||
        return failed;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_ringbuffer_space result = {NULL, NULL, 0};
 | 
			
		||||
    rt_ringbuffer_space result = {NULL, NULL, 0};
 | 
			
		||||
 | 
			
		||||
    if (_ringbuffer.head >= _ringbuffer.tail) {
 | 
			
		||||
        if (_ringbuffer.head + count <= _ringbuffer.capacity) {
 | 
			
		||||
@ -66,7 +66,7 @@ static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
			
		||||
                _ringbuffer.head = b_count;
 | 
			
		||||
            } else {
 | 
			
		||||
                /* Not enough space, we would overwrite the tail */
 | 
			
		||||
                vyLog("aio", "Ringbuffer is full.");
 | 
			
		||||
                rtLog("aio", "Ringbuffer is full.");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
@ -78,78 +78,78 @@ static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
			
		||||
            _ringbuffer.head = (_ringbuffer.head + count) % _ringbuffer.capacity;
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Not enough space, we would overwrite the tail */
 | 
			
		||||
            vyLog("aio", "Ringbuffer is full.");
 | 
			
		||||
            rtLog("aio", "Ringbuffer is full.");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
    rtUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
static void
 | 
			
		||||
win32CompletionRoutine(DWORD error_code, DWORD num_bytes_transfered, LPOVERLAPPED overlapped) {
 | 
			
		||||
    vy_aio *op = (vy_aio *)overlapped->hEvent;
 | 
			
		||||
    assert(op->state == VY_AIO_STATE_PENDING);
 | 
			
		||||
    rt_aio *op = (rt_aio *)overlapped->hEvent;
 | 
			
		||||
    assert(op->state == RT_AIO_STATE_PENDING);
 | 
			
		||||
 | 
			
		||||
    if (error_code != ERROR_SUCCESS) {
 | 
			
		||||
        op->state = VY_AIO_STATE_FAILED;
 | 
			
		||||
        vyLog("aio", "Async io failed: %u", error_code);
 | 
			
		||||
        op->state = RT_AIO_STATE_FAILED;
 | 
			
		||||
        rtLog("aio", "Async io failed: %u", error_code);
 | 
			
		||||
    } else {
 | 
			
		||||
        op->state = VY_AIO_STATE_FINISHED;
 | 
			
		||||
        op->state = RT_AIO_STATE_FINISHED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CloseHandle(op->file_handle);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(rt_MaxConcurrentAsyncIO,
 | 
			
		||||
RT_CVAR_I(rt_MaxConcurrentAsyncIO,
 | 
			
		||||
          "Maximum number of concurrent async. I/O operations. Default: 1024",
 | 
			
		||||
          1024);
 | 
			
		||||
 | 
			
		||||
vy_result InitAIO(void) {
 | 
			
		||||
rt_result InitAIO(void) {
 | 
			
		||||
    unsigned int max_concurrent_operations = rt_MaxConcurrentAsyncIO.i;
 | 
			
		||||
    _ringbuffer.guard = vyCreateMutex();
 | 
			
		||||
    _ringbuffer.guard = rtCreateMutex();
 | 
			
		||||
    if (!_ringbuffer.guard) {
 | 
			
		||||
        return VY_AIO_OUT_OF_MEMORY;
 | 
			
		||||
        return RT_AIO_OUT_OF_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
    if (max_concurrent_operations == 0)
 | 
			
		||||
        max_concurrent_operations = 1024;
 | 
			
		||||
 | 
			
		||||
    _ringbuffer.storage = calloc(max_concurrent_operations, sizeof(vy_aio));
 | 
			
		||||
    _ringbuffer.storage = calloc(max_concurrent_operations, sizeof(rt_aio));
 | 
			
		||||
    if (!_ringbuffer.storage)
 | 
			
		||||
        return VY_AIO_OUT_OF_MEMORY;
 | 
			
		||||
        return RT_AIO_OUT_OF_MEMORY;
 | 
			
		||||
    _ringbuffer.head     = 0;
 | 
			
		||||
    _ringbuffer.tail     = 0;
 | 
			
		||||
    _ringbuffer.capacity = max_concurrent_operations;
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ShutdownAIO(void) {
 | 
			
		||||
    vyDestroyMutex(_ringbuffer.guard);
 | 
			
		||||
    rtDestroyMutex(_ringbuffer.guard);
 | 
			
		||||
    free(_ringbuffer.storage);
 | 
			
		||||
    _ringbuffer.capacity = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_handle *handles) {
 | 
			
		||||
    if (batch->num_loads > VY_LOAD_BATCH_MAX_SIZE) {
 | 
			
		||||
        return VY_AIO_LOAD_TOO_LARGE;
 | 
			
		||||
RT_DLLEXPORT rt_result rtSubmitLoadBatch(const rt_load_batch *batch, rt_aio_handle *handles) {
 | 
			
		||||
    if (batch->num_loads > RT_LOAD_BATCH_MAX_SIZE) {
 | 
			
		||||
        return RT_AIO_LOAD_TOO_LARGE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_ringbuffer_space rbspace = ReserveRingbufferSpace(batch->num_loads);
 | 
			
		||||
    rt_ringbuffer_space rbspace = ReserveRingbufferSpace(batch->num_loads);
 | 
			
		||||
    if (!rbspace.a) {
 | 
			
		||||
        vyReportError("aio", "Too many pending file operations");
 | 
			
		||||
        return VY_AIO_TOO_MANY_OPERATIONS;
 | 
			
		||||
        rtReportError("aio", "Too many pending file operations");
 | 
			
		||||
        return RT_AIO_TOO_MANY_OPERATIONS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < batch->num_loads; ++i) {
 | 
			
		||||
        vy_aio *op = (i < rbspace.a_count) ? &rbspace.a[i] : &rbspace.b[i - rbspace.a_count];
 | 
			
		||||
        op->state  = VY_AIO_STATE_PENDING;
 | 
			
		||||
        const char *file_path = vyGetFilePath(batch->loads[i].file);
 | 
			
		||||
        rt_aio *op = (i < rbspace.a_count) ? &rbspace.a[i] : &rbspace.b[i - rbspace.a_count];
 | 
			
		||||
        op->state  = RT_AIO_STATE_PENDING;
 | 
			
		||||
        const char *file_path = rtGetFilePath(batch->loads[i].file);
 | 
			
		||||
        if (!file_path) {
 | 
			
		||||
            vyReportError("aio", "Failed to resolve file path for a batched load");
 | 
			
		||||
            op->state  = VY_AIO_STATE_INVALID;
 | 
			
		||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
            rtReportError("aio", "Failed to resolve file path for a batched load");
 | 
			
		||||
            op->state  = RT_AIO_STATE_INVALID;
 | 
			
		||||
            handles[i] = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
@ -168,10 +168,10 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_hand
 | 
			
		||||
                                file_path,
 | 
			
		||||
                                -1,
 | 
			
		||||
                                wpath,
 | 
			
		||||
                                VY_ARRAY_COUNT(wpath)) == 0) {
 | 
			
		||||
            vyReportError("aio", "MultiByteToWideChar failed with error code: %u", GetLastError());
 | 
			
		||||
            op->state  = VY_AIO_STATE_FINISHED;
 | 
			
		||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
                                RT_ARRAY_COUNT(wpath)) == 0) {
 | 
			
		||||
            rtReportError("aio", "MultiByteToWideChar failed with error code: %u", GetLastError());
 | 
			
		||||
            op->state  = RT_AIO_STATE_FINISHED;
 | 
			
		||||
            handles[i] = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -183,12 +183,12 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_hand
 | 
			
		||||
                                         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
 | 
			
		||||
                                         NULL);
 | 
			
		||||
        if (file_handle == INVALID_HANDLE_VALUE) {
 | 
			
		||||
            vyReportError("aio",
 | 
			
		||||
            rtReportError("aio",
 | 
			
		||||
                          "CreateFileW failed for file: %s with error code: %u",
 | 
			
		||||
                          file_path,
 | 
			
		||||
                          GetLastError());
 | 
			
		||||
            op->state  = VY_AIO_STATE_INVALID;
 | 
			
		||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
            op->state  = RT_AIO_STATE_INVALID;
 | 
			
		||||
            handles[i] = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        op->file_handle = file_handle;
 | 
			
		||||
@ -199,9 +199,9 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_hand
 | 
			
		||||
                                 win32CompletionRoutine);
 | 
			
		||||
        DWORD err       = GetLastError();
 | 
			
		||||
        if (!result || err != ERROR_SUCCESS) {
 | 
			
		||||
            vyReportError("aio", "ReadFileEx failed with error code: %u", err);
 | 
			
		||||
            op->state  = VY_AIO_STATE_FINISHED;
 | 
			
		||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
            rtReportError("aio", "ReadFileEx failed with error code: %u", err);
 | 
			
		||||
            op->state  = RT_AIO_STATE_FINISHED;
 | 
			
		||||
            handles[i] = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
            CloseHandle(file_handle);
 | 
			
		||||
            op->file_handle = NULL;
 | 
			
		||||
        }
 | 
			
		||||
@ -212,69 +212,69 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_hand
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle) {
 | 
			
		||||
    if (handle == VY_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity)
 | 
			
		||||
        return VY_AIO_STATE_INVALID;
 | 
			
		||||
RT_DLLEXPORT volatile rt_aio_state rtGetAIOState(rt_aio_handle handle) {
 | 
			
		||||
    if (handle == RT_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity)
 | 
			
		||||
        return RT_AIO_STATE_INVALID;
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    /* Give the compation function an opportunity to run */
 | 
			
		||||
    SleepEx(0, TRUE);
 | 
			
		||||
#endif
 | 
			
		||||
    vyLockMutex(_ringbuffer.guard);
 | 
			
		||||
    vy_aio_state state = _ringbuffer.storage[handle - 1].state;
 | 
			
		||||
    vyUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
    rtLockMutex(_ringbuffer.guard);
 | 
			
		||||
    rt_aio_state state = _ringbuffer.storage[handle - 1].state;
 | 
			
		||||
    rtUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseAIO(vy_aio_handle handle) {
 | 
			
		||||
    if (handle == VY_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity) {
 | 
			
		||||
RT_DLLEXPORT void rtReleaseAIO(rt_aio_handle handle) {
 | 
			
		||||
    if (handle == RT_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    vyLockMutex(_ringbuffer.guard);
 | 
			
		||||
    _ringbuffer.storage[handle - 1].state = VY_AIO_STATE_INVALID;
 | 
			
		||||
    rtLockMutex(_ringbuffer.guard);
 | 
			
		||||
    _ringbuffer.storage[handle - 1].state = RT_AIO_STATE_INVALID;
 | 
			
		||||
    if (handle - 1 == _ringbuffer.tail) {
 | 
			
		||||
        /* Advance the tail such that it points to the last used slot. (Or to head, if the
 | 
			
		||||
         * ringbuffer is now empty) */
 | 
			
		||||
        uint32_t i = _ringbuffer.tail;
 | 
			
		||||
        while ((_ringbuffer.storage[i].state == VY_AIO_STATE_INVALID) && i != _ringbuffer.head) {
 | 
			
		||||
        while ((_ringbuffer.storage[i].state == RT_AIO_STATE_INVALID) && i != _ringbuffer.head) {
 | 
			
		||||
            i = (i + 1) % _ringbuffer.capacity;
 | 
			
		||||
        }
 | 
			
		||||
        _ringbuffer.tail = i;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
    rtUnlockMutex(_ringbuffer.guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle) {
 | 
			
		||||
    if (handle == VY_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity)
 | 
			
		||||
        return VY_AIO_STATE_INVALID;
 | 
			
		||||
    vy_aio_state state;
 | 
			
		||||
RT_DLLEXPORT rt_aio_state rtWaitForAIOCompletion(rt_aio_handle handle) {
 | 
			
		||||
    if (handle == RT_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity)
 | 
			
		||||
        return RT_AIO_STATE_INVALID;
 | 
			
		||||
    rt_aio_state state;
 | 
			
		||||
    do {
 | 
			
		||||
        state = vyGetAIOState(handle);
 | 
			
		||||
        state = rtGetAIOState(handle);
 | 
			
		||||
        /* NOTE(Kevin): This is where we could temporarily run a job. */
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
        YieldProcessor();
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
        sched_yield();
 | 
			
		||||
#endif
 | 
			
		||||
    } while (state == VY_AIO_STATE_PENDING);
 | 
			
		||||
    } while (state == RT_AIO_STATE_PENDING);
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vySubmitSingleLoad(vy_file_load load, vy_aio_handle *handle) {
 | 
			
		||||
    vy_load_batch batch;
 | 
			
		||||
RT_DLLEXPORT rt_result rtSubmitSingleLoad(rt_file_load load, rt_aio_handle *handle) {
 | 
			
		||||
    rt_load_batch batch;
 | 
			
		||||
    batch.loads[0] = load;
 | 
			
		||||
    batch.num_loads = 1;
 | 
			
		||||
    return vySubmitLoadBatch(&batch, handle);
 | 
			
		||||
    return rtSubmitLoadBatch(&batch, handle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_aio_state vySubmitSingleLoadSync(vy_file_load load) {
 | 
			
		||||
    vy_aio_handle handle;
 | 
			
		||||
    if (vySubmitSingleLoad(load, &handle) != VY_SUCCESS)
 | 
			
		||||
        return VY_AIO_STATE_FAILED;
 | 
			
		||||
    vy_aio_state state = vyWaitForAIOCompletion(handle);
 | 
			
		||||
    vyReleaseAIO(handle);
 | 
			
		||||
RT_DLLEXPORT rt_aio_state rtSubmitSingleLoadSync(rt_file_load load) {
 | 
			
		||||
    rt_aio_handle handle;
 | 
			
		||||
    if (rtSubmitSingleLoad(load, &handle) != RT_SUCCESS)
 | 
			
		||||
        return RT_AIO_STATE_FAILED;
 | 
			
		||||
    rt_aio_state state = rtWaitForAIOCompletion(handle);
 | 
			
		||||
    rtReleaseAIO(handle);
 | 
			
		||||
    return state;
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_AIO_H
 | 
			
		||||
#define VY_AIO_H
 | 
			
		||||
#ifndef RT_AIO_H
 | 
			
		||||
#define RT_AIO_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
@ -13,57 +13,57 @@ typedef struct {
 | 
			
		||||
     *  Must be valid until the load is finished.
 | 
			
		||||
     */
 | 
			
		||||
    void *dest;
 | 
			
		||||
    vy_file_id file; /**< Unique identifier for the file */
 | 
			
		||||
} vy_file_load;
 | 
			
		||||
    rt_file_id file; /**< Unique identifier for the file */
 | 
			
		||||
} rt_file_load;
 | 
			
		||||
 | 
			
		||||
#define VY_LOAD_BATCH_MAX_SIZE 64
 | 
			
		||||
#define RT_LOAD_BATCH_MAX_SIZE 64
 | 
			
		||||
 | 
			
		||||
/** A batch of loads that will be started together.
 | 
			
		||||
 *
 | 
			
		||||
 * The aio system will hand these to the OS.
 | 
			
		||||
 */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_load loads[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    rt_file_load loads[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
 | 
			
		||||
    /** Must be smaller or equal to @c VY_LOAD_BATCH_MAX_SIZE */
 | 
			
		||||
    /** Must be smaller or equal to @c RT_LOAD_BATCH_MAX_SIZE */
 | 
			
		||||
    unsigned int num_loads;
 | 
			
		||||
} vy_load_batch;
 | 
			
		||||
} rt_load_batch;
 | 
			
		||||
 | 
			
		||||
#define VY_AIO_INVALID_HANDLE 0
 | 
			
		||||
#define RT_AIO_INVALID_HANDLE 0
 | 
			
		||||
 | 
			
		||||
/** Handle for an async io operation. Can be used to query the state and result. */
 | 
			
		||||
typedef uint32_t vy_aio_handle;
 | 
			
		||||
typedef uint32_t rt_aio_handle;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_AIO_LOAD_TOO_LARGE = (VY_SUCCESS + 1),
 | 
			
		||||
    VY_AIO_TOO_MANY_OPERATIONS,
 | 
			
		||||
    VY_AIO_OUT_OF_MEMORY,
 | 
			
		||||
    RT_AIO_LOAD_TOO_LARGE = (RT_SUCCESS + 1),
 | 
			
		||||
    RT_AIO_TOO_MANY_OPERATIONS,
 | 
			
		||||
    RT_AIO_OUT_OF_MEMORY,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_AIO_STATE_INVALID,
 | 
			
		||||
    VY_AIO_STATE_PENDING,
 | 
			
		||||
    VY_AIO_STATE_FINISHED,
 | 
			
		||||
    VY_AIO_STATE_FAILED,
 | 
			
		||||
} vy_aio_state;
 | 
			
		||||
    RT_AIO_STATE_INVALID,
 | 
			
		||||
    RT_AIO_STATE_PENDING,
 | 
			
		||||
    RT_AIO_STATE_FINISHED,
 | 
			
		||||
    RT_AIO_STATE_FAILED,
 | 
			
		||||
} rt_aio_state;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_handle *handles);
 | 
			
		||||
RT_DLLEXPORT rt_result rtSubmitLoadBatch(const rt_load_batch *batch, rt_aio_handle *handles);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle);
 | 
			
		||||
RT_DLLEXPORT volatile rt_aio_state rtGetAIOState(rt_aio_handle handle);
 | 
			
		||||
 | 
			
		||||
/* Blocks until the given operation is no longer pending.
 | 
			
		||||
 * Returns the state that caused the wait to end. The handle is still valid after this function returned. */
 | 
			
		||||
VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle);
 | 
			
		||||
RT_DLLEXPORT rt_aio_state rtWaitForAIOCompletion(rt_aio_handle handle);
 | 
			
		||||
 | 
			
		||||
/* Releases the internal storage for the operation.
 | 
			
		||||
 * The system is allowed to re-use the same handle value for new operations after this was called.
 | 
			
		||||
 */
 | 
			
		||||
VY_DLLEXPORT void vyReleaseAIO(vy_aio_handle handle);
 | 
			
		||||
RT_DLLEXPORT void rtReleaseAIO(rt_aio_handle handle);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vySubmitSingleLoad(vy_file_load load, vy_aio_handle *handle);
 | 
			
		||||
RT_DLLEXPORT rt_result rtSubmitSingleLoad(rt_file_load load, rt_aio_handle *handle);
 | 
			
		||||
 | 
			
		||||
/* Convenience wrapper for a single synchronous file load.
 | 
			
		||||
 * Returns the state that caused the wait for completion to return. */
 | 
			
		||||
VY_DLLEXPORT vy_aio_state vySubmitSingleLoadSync(vy_file_load load);
 | 
			
		||||
RT_DLLEXPORT rt_aio_state rtSubmitSingleLoadSync(rt_file_load load);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -5,9 +5,9 @@
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0);
 | 
			
		||||
VY_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
 | 
			
		||||
VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
			
		||||
RT_CVAR_I(rt_Fullscreen, "Show window in fullscreen mode. [0/1] Default: 0", 0);
 | 
			
		||||
RT_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
 | 
			
		||||
RT_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
@ -23,22 +23,22 @@ static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT int
 | 
			
		||||
vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
 | 
			
		||||
    if (vyInitRuntime() != VY_SUCCESS)
 | 
			
		||||
RT_DLLEXPORT int
 | 
			
		||||
rtWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
 | 
			
		||||
    if (rtInitRuntime() != RT_SUCCESS)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    vyRegisterRendererCVars();
 | 
			
		||||
    rtRegisterRendererCVars();
 | 
			
		||||
 | 
			
		||||
    WNDCLASSEXW wndclass = {
 | 
			
		||||
        .cbSize        = sizeof(wndclass),
 | 
			
		||||
        .hInstance     = hInstance,
 | 
			
		||||
        .lpszClassName = L"vyWndClass",
 | 
			
		||||
        .lpszClassName = L"rtWndClass",
 | 
			
		||||
        .style         = CS_OWNDC,
 | 
			
		||||
        .lpfnWndProc   = win32WndProc,
 | 
			
		||||
    };
 | 
			
		||||
    if (!RegisterClassExW(&wndclass)) {
 | 
			
		||||
        vyReportError("CORE", "RegisterClassEx failed: %u", GetLastError());
 | 
			
		||||
        rtReportError("CORE", "RegisterClassEx failed: %u", GetLastError());
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -48,7 +48,7 @@ vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
 | 
			
		||||
        int w = GetSystemMetrics(SM_CXSCREEN);
 | 
			
		||||
        int h = GetSystemMetrics(SM_CYSCREEN);
 | 
			
		||||
        wnd   = CreateWindowExW(WS_EX_APPWINDOW,
 | 
			
		||||
                              L"vyWndClass",
 | 
			
		||||
                              L"rtWndClass",
 | 
			
		||||
                              L"Voyage",
 | 
			
		||||
                              WS_POPUP,
 | 
			
		||||
                              0,
 | 
			
		||||
@ -65,7 +65,7 @@ vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
 | 
			
		||||
        int w = rt_WindowWidth.i;
 | 
			
		||||
        int h = rt_WindowHeight.i;
 | 
			
		||||
        wnd   = CreateWindowExW(WS_EX_APPWINDOW,
 | 
			
		||||
                              L"vyWndClass",
 | 
			
		||||
                              L"rtWndClass",
 | 
			
		||||
                              L"Voyage",
 | 
			
		||||
                              WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU,
 | 
			
		||||
                              CW_USEDEFAULT,
 | 
			
		||||
@ -80,13 +80,13 @@ vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!wnd) {
 | 
			
		||||
        vyReportError("CORE", "Failed to create the game window: %u", GetLastError());
 | 
			
		||||
        rtReportError("CORE", "Failed to create the game window: %u", GetLastError());
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_renderer_init_info renderer_info = {.hWnd = wnd, .hInstance = hInstance};
 | 
			
		||||
    if (!vyInitGFX(&renderer_info)) {
 | 
			
		||||
        vyReportError("GFX", "Init failed.");
 | 
			
		||||
    rt_renderer_init_info renderer_info = {.hWnd = wnd, .hInstance = hInstance};
 | 
			
		||||
    if (!rtInitGFX(&renderer_info)) {
 | 
			
		||||
        rtReportError("GFX", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -104,17 +104,17 @@ vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyShutdownGFX();
 | 
			
		||||
    rtShutdownGFX();
 | 
			
		||||
 | 
			
		||||
    DestroyWindow(wnd);
 | 
			
		||||
    UnregisterClassW(L"vyWndClass", hInstance);
 | 
			
		||||
    UnregisterClassW(L"rtWndClass", hInstance);
 | 
			
		||||
 | 
			
		||||
    vyShutdownRuntime();
 | 
			
		||||
    rtShutdownRuntime();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
 | 
			
		||||
#include <X11/Xlib.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
@ -123,7 +123,7 @@ static void xlibSetFullscreen(Display *dpy, int screen, Window window, bool enab
 | 
			
		||||
    Atom wm_state      = XInternAtom(dpy, "_NET_W_STATE", False);
 | 
			
		||||
    Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
 | 
			
		||||
    if (wm_state == None || wm_fullscreen == None) {
 | 
			
		||||
        vyLog("CORE", "Window manager does not support fullscreen mode.");
 | 
			
		||||
        rtLog("CORE", "Window manager does not support fullscreen mode.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -146,7 +146,7 @@ static void xlibSetFullscreen(Display *dpy, int screen, Window window, bool enab
 | 
			
		||||
    long ev_mask       = SubstructureRedirectMask;
 | 
			
		||||
 | 
			
		||||
    if (!XSendEvent(dpy, root_window, False, ev_mask, &ev)) {
 | 
			
		||||
        vyReportError("CORE", "Failed to send x11 fullscreen event.");
 | 
			
		||||
        rtReportError("CORE", "Failed to send x11 fullscreen event.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#undef _NET_WM_STATE_ADD
 | 
			
		||||
@ -154,16 +154,16 @@ static void xlibSetFullscreen(Display *dpy, int screen, Window window, bool enab
 | 
			
		||||
#undef EVENT_SOURCE_APPLICATION
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
    if (vyInitRuntime() != VY_SUCCESS)
 | 
			
		||||
RT_DLLEXPORT int rtXlibEntry(int argc, char **argv) {
 | 
			
		||||
    if (rtInitRuntime() != RT_SUCCESS)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    vyRegisterRendererCVars();
 | 
			
		||||
    rtRegisterRendererCVars();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    Display *dpy = XOpenDisplay(NULL);
 | 
			
		||||
    if (!dpy) {
 | 
			
		||||
        vyReportError("CORE", "Failed to open default display");
 | 
			
		||||
        rtReportError("CORE", "Failed to open default display");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    int screen = DefaultScreen(dpy);
 | 
			
		||||
@ -185,7 +185,7 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
 | 
			
		||||
    Atom wm_close = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
 | 
			
		||||
    if (!wm_close) {
 | 
			
		||||
        vyReportError("CORE", "Failed to find WM_DELETE_WINDOW atom.");
 | 
			
		||||
        rtReportError("CORE", "Failed to find WM_DELETE_WINDOW atom.");
 | 
			
		||||
        XDestroyWindow(dpy, window);
 | 
			
		||||
        XCloseDisplay(dpy);
 | 
			
		||||
        return 1;
 | 
			
		||||
@ -195,9 +195,9 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
    if (rt_Fullscreen.i)
 | 
			
		||||
        xlibSetFullscreen(dpy, screen, window, true);
 | 
			
		||||
 | 
			
		||||
    vy_renderer_init_info renderer_info = {.display = dpy, .window = window};
 | 
			
		||||
    if (!vyInitGFX(&renderer_info)) {
 | 
			
		||||
        vyReportError("GFX", "Init failed.");
 | 
			
		||||
    rt_renderer_init_info renderer_info = {.display = dpy, .window = window};
 | 
			
		||||
    if (!rtInitGFX(&renderer_info)) {
 | 
			
		||||
        rtReportError("GFX", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -218,7 +218,7 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
                break;
 | 
			
		||||
            case ClientMessage:
 | 
			
		||||
                if (event.xclient.data.l[0] == (long)wm_close) {
 | 
			
		||||
                    vyLog("CORE", "Received WM_DELETE_WINDOW");
 | 
			
		||||
                    rtLog("CORE", "Received WM_DELETE_WINDOW");
 | 
			
		||||
                    keep_running = false;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
@ -226,10 +226,10 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyShutdownGFX();
 | 
			
		||||
    rtShutdownGFX();
 | 
			
		||||
    XDestroyWindow(dpy, window);
 | 
			
		||||
    XCloseDisplay(dpy);
 | 
			
		||||
    vyShutdownRuntime();
 | 
			
		||||
    rtShutdownRuntime();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_APP_H
 | 
			
		||||
#define VY_APP_H
 | 
			
		||||
#ifndef RT_APP_H
 | 
			
		||||
#define RT_APP_H
 | 
			
		||||
 | 
			
		||||
/* Platform specific application entry point */
 | 
			
		||||
 | 
			
		||||
@ -10,14 +10,14 @@
 | 
			
		||||
/* Forward declared here, to avoid including windows.h */
 | 
			
		||||
struct HINSTANCE__;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT int vyWin32Entry(struct HINSTANCE__ *hInstance,
 | 
			
		||||
RT_DLLEXPORT int rtWin32Entry(struct HINSTANCE__ *hInstance,
 | 
			
		||||
                              struct HINSTANCE__ *hPrevInstance,
 | 
			
		||||
                              wchar_t *pCmdLine,
 | 
			
		||||
                              int nCmdShow);
 | 
			
		||||
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT int vyXlibEntry(int argc, char **argv);
 | 
			
		||||
RT_DLLEXPORT int rtXlibEntry(int argc, char **argv);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,10 +9,10 @@
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(rt_AssetCacheSize, "Number of asset cache entries. Default: 1024.", 1024);
 | 
			
		||||
RT_CVAR_I(rt_AssetCacheSize, "Number of asset cache entries. Default: 1024.", 1024);
 | 
			
		||||
 | 
			
		||||
/* asset_loading.c */
 | 
			
		||||
extern vy_result DecompressAsset(void *compressed_buffer,
 | 
			
		||||
extern rt_result DecompressAsset(void *compressed_buffer,
 | 
			
		||||
                                 size_t compressed_buffer_size,
 | 
			
		||||
                                 void **p_decompressed,
 | 
			
		||||
                                 size_t *p_decompressed_size);
 | 
			
		||||
@ -21,63 +21,63 @@ typedef enum {
 | 
			
		||||
    CACHE_ENTRY_STATE_FREE,
 | 
			
		||||
    CACHE_ENTRY_STATE_LOADING,
 | 
			
		||||
    CACHE_ENTRY_STATE_LOADED,
 | 
			
		||||
} vy_asset_cache_entry_state;
 | 
			
		||||
} rt_asset_cache_entry_state;
 | 
			
		||||
 | 
			
		||||
typedef struct vy_asset_cache_entry_s {
 | 
			
		||||
    vy_asset_cache_entry_state state;
 | 
			
		||||
    vy_aio_handle load;
 | 
			
		||||
typedef struct rt_asset_cache_entry_s {
 | 
			
		||||
    rt_asset_cache_entry_state state;
 | 
			
		||||
    rt_aio_handle load;
 | 
			
		||||
    void *buffer;
 | 
			
		||||
    size_t size;
 | 
			
		||||
    int refcount;
 | 
			
		||||
 | 
			
		||||
    /* Reclaim list */
 | 
			
		||||
    struct vy_asset_cache_entry_s *prev_reclaim;
 | 
			
		||||
    struct vy_asset_cache_entry_s *next_reclaim;
 | 
			
		||||
} vy_asset_cache_entry;
 | 
			
		||||
    struct rt_asset_cache_entry_s *prev_reclaim;
 | 
			
		||||
    struct rt_asset_cache_entry_s *next_reclaim;
 | 
			
		||||
} rt_asset_cache_entry;
 | 
			
		||||
 | 
			
		||||
static vy_uid *_uids;
 | 
			
		||||
static vy_asset_cache_entry *_entries;
 | 
			
		||||
static vy_asset_cache_entry *_first_reclaim;
 | 
			
		||||
static vy_asset_cache_entry *_last_reclaim;
 | 
			
		||||
static rt_uid *_uids;
 | 
			
		||||
static rt_asset_cache_entry *_entries;
 | 
			
		||||
static rt_asset_cache_entry *_first_reclaim;
 | 
			
		||||
static rt_asset_cache_entry *_last_reclaim;
 | 
			
		||||
 | 
			
		||||
/* Locked as writer when modifiying entries, as reader when searching */
 | 
			
		||||
static vy_rwlock _lock;
 | 
			
		||||
static rt_rwlock _lock;
 | 
			
		||||
 | 
			
		||||
vy_result InitAssetCache(void) {
 | 
			
		||||
    _entries = calloc((size_t)rt_AssetCacheSize.i, sizeof(vy_asset_cache_entry));
 | 
			
		||||
rt_result InitAssetCache(void) {
 | 
			
		||||
    _entries = calloc((size_t)rt_AssetCacheSize.i, sizeof(rt_asset_cache_entry));
 | 
			
		||||
    if (!_entries) {
 | 
			
		||||
        return VY_BUFFER_ALLOC_FAILED;
 | 
			
		||||
        return RT_BUFFER_ALLOC_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
    _uids = calloc((size_t)rt_AssetCacheSize.i, sizeof(vy_uid));
 | 
			
		||||
    _uids = calloc((size_t)rt_AssetCacheSize.i, sizeof(rt_uid));
 | 
			
		||||
    if (!_uids) {
 | 
			
		||||
        free(_entries);
 | 
			
		||||
        return VY_BUFFER_ALLOC_FAILED;
 | 
			
		||||
        return RT_BUFFER_ALLOC_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
    vy_create_rwlock_result lock_res = vyCreateRWLock();
 | 
			
		||||
    rt_create_rwlock_result lock_res = rtCreateRWLock();
 | 
			
		||||
    if (!lock_res.ok) {
 | 
			
		||||
        free(_entries);
 | 
			
		||||
        free(_uids);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    _lock = lock_res.lock;
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ShutdownAssetCache(void) {
 | 
			
		||||
    free(_entries);
 | 
			
		||||
    free(_uids);
 | 
			
		||||
    vyDestroyRWLock(&_lock);
 | 
			
		||||
    rtDestroyRWLock(&_lock);
 | 
			
		||||
    _first_reclaim = NULL;
 | 
			
		||||
    _last_reclaim  = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ReleaseEntry(vy_asset_cache_entry *entry) {
 | 
			
		||||
    if (entry->load != VY_AIO_INVALID_HANDLE) {
 | 
			
		||||
        vyWaitForAIOCompletion(entry->load);
 | 
			
		||||
        vyReleaseAIO(entry->load);
 | 
			
		||||
        entry->load = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
static void ReleaseEntry(rt_asset_cache_entry *entry) {
 | 
			
		||||
    if (entry->load != RT_AIO_INVALID_HANDLE) {
 | 
			
		||||
        rtWaitForAIOCompletion(entry->load);
 | 
			
		||||
        rtReleaseAIO(entry->load);
 | 
			
		||||
        entry->load = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
    }
 | 
			
		||||
    vyReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
    rtReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
    entry->buffer       = NULL;
 | 
			
		||||
    entry->size         = 0;
 | 
			
		||||
    entry->next_reclaim = NULL;
 | 
			
		||||
@ -85,28 +85,28 @@ static void ReleaseEntry(vy_asset_cache_entry *entry) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void GarbageCollect(void) {
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
    vy_asset_cache_entry *entry = _first_reclaim;
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    rt_asset_cache_entry *entry = _first_reclaim;
 | 
			
		||||
    while (entry) {
 | 
			
		||||
        assert(entry->refcount == 0);
 | 
			
		||||
        vy_asset_cache_entry *next = entry->next_reclaim;
 | 
			
		||||
        rt_asset_cache_entry *next = entry->next_reclaim;
 | 
			
		||||
        if (entry->state == CACHE_ENTRY_STATE_LOADED) {
 | 
			
		||||
            ReleaseEntry(entry);
 | 
			
		||||
            _first_reclaim = next;
 | 
			
		||||
        }
 | 
			
		||||
        entry          = next;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_asset_cache_entry *GetEntry(vy_uid uid) {
 | 
			
		||||
static rt_asset_cache_entry *GetEntry(rt_uid uid) {
 | 
			
		||||
    /* Hash lookup */
 | 
			
		||||
    unsigned int mod = (unsigned int)rt_AssetCacheSize.i - 1;
 | 
			
		||||
    for (unsigned int i = 0; i < (unsigned int)rt_AssetCacheSize.i; ++i) {
 | 
			
		||||
        unsigned int slot = (uid + i) & mod;
 | 
			
		||||
        if (_uids[slot] == uid) {
 | 
			
		||||
            return &_entries[slot];
 | 
			
		||||
        } else if (_uids[slot] == VY_INVALID_UID) {
 | 
			
		||||
        } else if (_uids[slot] == RT_INVALID_UID) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -114,8 +114,8 @@ static vy_asset_cache_entry *GetEntry(vy_uid uid) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static bool IsAssetLoaded(vy_uid uid) {
 | 
			
		||||
    const vy_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
static bool IsAssetLoaded(rt_uid uid) {
 | 
			
		||||
    const rt_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
    if (entry)
 | 
			
		||||
        return entry->state == CACHE_ENTRY_STATE_LOADED ||
 | 
			
		||||
               entry->state == CACHE_ENTRY_STATE_LOADING;
 | 
			
		||||
@ -123,7 +123,7 @@ static bool IsAssetLoaded(vy_uid uid) {
 | 
			
		||||
        return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int InsertEntry(vy_uid uid) {
 | 
			
		||||
static int InsertEntry(rt_uid uid) {
 | 
			
		||||
    unsigned int mod = (unsigned int)rt_AssetCacheSize.i - 1;
 | 
			
		||||
    for (unsigned int i = 0; i < (unsigned int)rt_AssetCacheSize.i; ++i) {
 | 
			
		||||
        unsigned int slot = (uid + i) & mod;
 | 
			
		||||
@ -133,58 +133,58 @@ static int InsertEntry(vy_uid uid) {
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
static vy_result InsertAndLoadAssets(const vy_uid *uids, size_t count) {
 | 
			
		||||
    vy_load_batch batch = {.num_loads = 0};
 | 
			
		||||
static rt_result InsertAndLoadAssets(const rt_uid *uids, size_t count) {
 | 
			
		||||
    rt_load_batch batch = {.num_loads = 0};
 | 
			
		||||
 | 
			
		||||
    vy_result res = VY_SUCCESS;
 | 
			
		||||
    rt_result res = RT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
    count = (count < VY_LOAD_BATCH_MAX_SIZE) ? count : VY_LOAD_BATCH_MAX_SIZE;
 | 
			
		||||
    vy_asset_cache_entry *load_entries[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    count = (count < RT_LOAD_BATCH_MAX_SIZE) ? count : RT_LOAD_BATCH_MAX_SIZE;
 | 
			
		||||
    rt_asset_cache_entry *load_entries[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < count; ++i) {
 | 
			
		||||
        vyLockRead(&_lock);
 | 
			
		||||
        rtLockRead(&_lock);
 | 
			
		||||
        bool needs_load = !IsAssetLoaded(uids[i]);
 | 
			
		||||
        vyUnlockRead(&_lock);
 | 
			
		||||
        rtUnlockRead(&_lock);
 | 
			
		||||
 | 
			
		||||
        if (!needs_load)
 | 
			
		||||
            continue;
 | 
			
		||||
 | 
			
		||||
        vyLockWrite(&_lock);
 | 
			
		||||
        rtLockWrite(&_lock);
 | 
			
		||||
        /* It's possible that another thread loaded the asset in the meantime */
 | 
			
		||||
        if (!IsAssetLoaded(uids[i])) {
 | 
			
		||||
            const vy_uid_data *data = vyGetUIDData(uids[i]);
 | 
			
		||||
            const rt_uid_data *data = rtGetUIDData(uids[i]);
 | 
			
		||||
            if (!data) {
 | 
			
		||||
                vyUnlockWrite(&_lock);
 | 
			
		||||
                vyLog("ASSET_CACHE", "Failed to get uid data for uid %u", uids[i]);
 | 
			
		||||
                res = VY_UNKNOWN_ASSET;
 | 
			
		||||
                rtUnlockWrite(&_lock);
 | 
			
		||||
                rtLog("ASSET_CACHE", "Failed to get uid data for uid %u", uids[i]);
 | 
			
		||||
                res = RT_UNKNOWN_ASSET;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            void *compressed_data = vyAllocBuffer(data->size);
 | 
			
		||||
            void *compressed_data = rtAllocBuffer(data->size);
 | 
			
		||||
            if (!compressed_data) {
 | 
			
		||||
                /* Try again after garbage collection */
 | 
			
		||||
                vyUnlockWrite(&_lock);
 | 
			
		||||
                rtUnlockWrite(&_lock);
 | 
			
		||||
                GarbageCollect();
 | 
			
		||||
                compressed_data = vyAllocBuffer(data->size);
 | 
			
		||||
                compressed_data = rtAllocBuffer(data->size);
 | 
			
		||||
                if (!compressed_data) {
 | 
			
		||||
                    vyLog("ASSET_CACHE",
 | 
			
		||||
                    rtLog("ASSET_CACHE",
 | 
			
		||||
                          "Failed to allocate intermediate buffer for uid %u",
 | 
			
		||||
                          uids[i]);
 | 
			
		||||
                    res = VY_BUFFER_ALLOC_FAILED;
 | 
			
		||||
                    res = RT_BUFFER_ALLOC_FAILED;
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
                vyLockWrite(&_lock);
 | 
			
		||||
                rtLockWrite(&_lock);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            int slot = InsertEntry(uids[i]);
 | 
			
		||||
            if (slot == -1) {
 | 
			
		||||
                vyUnlockWrite(&_lock);
 | 
			
		||||
                vyLog("ASSET_CACHE", "Failed to insert new entry for uid %u", uids[i]);
 | 
			
		||||
                res = VY_ASSET_CACHE_FULL;
 | 
			
		||||
                rtUnlockWrite(&_lock);
 | 
			
		||||
                rtLog("ASSET_CACHE", "Failed to insert new entry for uid %u", uids[i]);
 | 
			
		||||
                res = RT_ASSET_CACHE_FULL;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            vy_asset_cache_entry *entry = &_entries[slot];
 | 
			
		||||
            rt_asset_cache_entry *entry = &_entries[slot];
 | 
			
		||||
            load_entries[batch.num_loads] = entry;
 | 
			
		||||
 | 
			
		||||
            /* We set the refcount to 0, but don't insert the entry
 | 
			
		||||
@ -197,7 +197,7 @@ static vy_result InsertAndLoadAssets(const vy_uid *uids, size_t count) {
 | 
			
		||||
            entry->size         = data->size;
 | 
			
		||||
            entry->next_reclaim = NULL;
 | 
			
		||||
            entry->prev_reclaim = NULL;
 | 
			
		||||
            entry->load         = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
            entry->load         = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
 | 
			
		||||
            batch.loads[batch.num_loads].file      = data->pkg_file;
 | 
			
		||||
            batch.loads[batch.num_loads].num_bytes = data->size;
 | 
			
		||||
@ -206,45 +206,45 @@ static vy_result InsertAndLoadAssets(const vy_uid *uids, size_t count) {
 | 
			
		||||
            ++batch.num_loads;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
 | 
			
		||||
    /* Dispatch the load */
 | 
			
		||||
    vy_aio_handle handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    if ((res = vySubmitLoadBatch(&batch, handles)) != VY_SUCCESS) {
 | 
			
		||||
        vyLog("ASSET_CACHE", "Failed to submit %u asset loads.", batch.num_loads);
 | 
			
		||||
    rt_aio_handle handles[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    if ((res = rtSubmitLoadBatch(&batch, handles)) != RT_SUCCESS) {
 | 
			
		||||
        rtLog("ASSET_CACHE", "Failed to submit %u asset loads.", batch.num_loads);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Set the aio handles of the inserted entries */
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    for (unsigned int i = 0; i < batch.num_loads; ++i) {
 | 
			
		||||
        load_entries[batch.num_loads]->load = handles[i];
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool DecompressEntry(vy_uid uid, vy_asset_cache_entry *entry) {
 | 
			
		||||
    vyReleaseAIO(entry->load);
 | 
			
		||||
    entry->load = VY_AIO_INVALID_HANDLE;
 | 
			
		||||
static bool DecompressEntry(rt_uid uid, rt_asset_cache_entry *entry) {
 | 
			
		||||
    rtReleaseAIO(entry->load);
 | 
			
		||||
    entry->load = RT_AIO_INVALID_HANDLE;
 | 
			
		||||
 | 
			
		||||
    void *decompressed_buffer;
 | 
			
		||||
    size_t decompressed_size;
 | 
			
		||||
    vy_result dec_res =
 | 
			
		||||
    rt_result dec_res =
 | 
			
		||||
        DecompressAsset(entry->buffer, entry->size, &decompressed_buffer, &decompressed_size);
 | 
			
		||||
    if (dec_res == VY_SUCCESS) {
 | 
			
		||||
        vyReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
    if (dec_res == RT_SUCCESS) {
 | 
			
		||||
        rtReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
        entry->buffer = decompressed_buffer;
 | 
			
		||||
        entry->size   = decompressed_size;
 | 
			
		||||
        entry->state  = CACHE_ENTRY_STATE_LOADED;
 | 
			
		||||
        return true;
 | 
			
		||||
    } else if (dec_res == VY_BUFFER_ALLOC_FAILED) {
 | 
			
		||||
    } else if (dec_res == RT_BUFFER_ALLOC_FAILED) {
 | 
			
		||||
        GarbageCollect();
 | 
			
		||||
        /* Try again */
 | 
			
		||||
        if (DecompressAsset(entry->buffer, entry->size, &decompressed_buffer, &decompressed_size) ==
 | 
			
		||||
            VY_SUCCESS) {
 | 
			
		||||
            vyReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
            RT_SUCCESS) {
 | 
			
		||||
            rtReleaseBuffer(entry->buffer, entry->size);
 | 
			
		||||
            entry->buffer = decompressed_buffer;
 | 
			
		||||
            entry->size   = decompressed_size;
 | 
			
		||||
            entry->state  = CACHE_ENTRY_STATE_LOADED;
 | 
			
		||||
@ -252,74 +252,74 @@ static bool DecompressEntry(vy_uid uid, vy_asset_cache_entry *entry) {
 | 
			
		||||
        }
 | 
			
		||||
        /* Don't do anything yet. We might be able to to do this later, once some
 | 
			
		||||
         * buffers become free. */
 | 
			
		||||
        vyLog("ASSET_CACHE", "Failed to decompress asset %u", uid);
 | 
			
		||||
        rtLog("ASSET_CACHE", "Failed to decompress asset %u", uid);
 | 
			
		||||
        return false;
 | 
			
		||||
    } else {
 | 
			
		||||
        vyLog("ASSET_CACHE", "Failed to decompress asset %u", uid);
 | 
			
		||||
        rtLog("ASSET_CACHE", "Failed to decompress asset %u", uid);
 | 
			
		||||
        ReleaseEntry(entry);
 | 
			
		||||
 | 
			
		||||
        ptrdiff_t idx = entry - _entries;
 | 
			
		||||
        _uids[idx]    = VY_INVALID_UID;
 | 
			
		||||
        _uids[idx]    = RT_INVALID_UID;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void CheckCompletedLoads(const vy_uid *uids, size_t count) {
 | 
			
		||||
static void CheckCompletedLoads(const rt_uid *uids, size_t count) {
 | 
			
		||||
    for (size_t i = 0; i < count; ++i) {
 | 
			
		||||
        vyLockRead(&_lock);
 | 
			
		||||
        volatile vy_asset_cache_entry *entry = (volatile vy_asset_cache_entry *)GetEntry(uids[i]);
 | 
			
		||||
        rtLockRead(&_lock);
 | 
			
		||||
        volatile rt_asset_cache_entry *entry = (volatile rt_asset_cache_entry *)GetEntry(uids[i]);
 | 
			
		||||
        if (!entry) {
 | 
			
		||||
            vyUnlockRead(&_lock);
 | 
			
		||||
            vyLog("ASSET_CACHE", "Passed unknown uid %u to CheckCompletedLoads()", uids[i]);
 | 
			
		||||
            rtUnlockRead(&_lock);
 | 
			
		||||
            rtLog("ASSET_CACHE", "Passed unknown uid %u to CheckCompletedLoads()", uids[i]);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (entry->state != CACHE_ENTRY_STATE_LOADING) {
 | 
			
		||||
            vyUnlockRead(&_lock);
 | 
			
		||||
            rtUnlockRead(&_lock);
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        bool load_finished = vyGetAIOState(entry->load) == VY_AIO_STATE_FINISHED;
 | 
			
		||||
        vyUnlockRead(&_lock);
 | 
			
		||||
        bool load_finished = rtGetAIOState(entry->load) == RT_AIO_STATE_FINISHED;
 | 
			
		||||
        rtUnlockRead(&_lock);
 | 
			
		||||
       
 | 
			
		||||
        if (load_finished) {
 | 
			
		||||
            vyLockWrite(&_lock);
 | 
			
		||||
            rtLockWrite(&_lock);
 | 
			
		||||
            /* Ensure that no-one else handled this */
 | 
			
		||||
            if (entry->state == CACHE_ENTRY_STATE_LOADING) {
 | 
			
		||||
                DecompressEntry(uids[i], (vy_asset_cache_entry *)entry);
 | 
			
		||||
                DecompressEntry(uids[i], (rt_asset_cache_entry *)entry);
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockWrite(&_lock);
 | 
			
		||||
            rtUnlockWrite(&_lock);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_get_asset_result vyGetAsset(vy_uid uid) {
 | 
			
		||||
    vy_get_asset_result result = {
 | 
			
		||||
        .result = VY_SUCCESS,
 | 
			
		||||
RT_DLLEXPORT rt_get_asset_result rtGetAsset(rt_uid uid) {
 | 
			
		||||
    rt_get_asset_result result = {
 | 
			
		||||
        .result = RT_SUCCESS,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    vyLockRead(&_lock);
 | 
			
		||||
    rtLockRead(&_lock);
 | 
			
		||||
    bool needs_load = !IsAssetLoaded(uid);
 | 
			
		||||
    vyUnlockRead(&_lock);
 | 
			
		||||
    rtUnlockRead(&_lock);
 | 
			
		||||
 | 
			
		||||
    if (needs_load) {
 | 
			
		||||
        vy_uid load_uids[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        rt_uid load_uids[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        size_t load_count = 1;
 | 
			
		||||
        load_uids[0]      = uid;
 | 
			
		||||
 | 
			
		||||
        vy_asset_dependency_list deps = vyGetAssetDependencies(uid);
 | 
			
		||||
        for (size_t i = 0; i < deps.count && i < VY_LOAD_BATCH_MAX_SIZE - 1; ++i) {
 | 
			
		||||
        rt_asset_dependency_list deps = rtGetAssetDependencies(uid);
 | 
			
		||||
        for (size_t i = 0; i < deps.count && i < RT_LOAD_BATCH_MAX_SIZE - 1; ++i) {
 | 
			
		||||
            load_uids[i + 1] = deps.dependencies[i];
 | 
			
		||||
            ++load_count;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        result.result = InsertAndLoadAssets(load_uids, load_count);
 | 
			
		||||
        if (result.result == VY_SUCCESS) {
 | 
			
		||||
        if (result.result == RT_SUCCESS) {
 | 
			
		||||
            CheckCompletedLoads(load_uids, load_count);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
    vy_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    rt_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
    if (entry) {
 | 
			
		||||
        if (entry->state == CACHE_ENTRY_STATE_LOADED) {
 | 
			
		||||
            ++entry->refcount;
 | 
			
		||||
@ -327,19 +327,19 @@ VY_DLLEXPORT vy_get_asset_result vyGetAsset(vy_uid uid) {
 | 
			
		||||
            result.size = entry->size;
 | 
			
		||||
        } else if (entry->state == CACHE_ENTRY_STATE_LOADING) {
 | 
			
		||||
            if (entry->state == CACHE_ENTRY_STATE_LOADING) {
 | 
			
		||||
                assert(entry->load != VY_AIO_INVALID_HANDLE);
 | 
			
		||||
                assert(entry->load != RT_AIO_INVALID_HANDLE);
 | 
			
		||||
                ++entry->refcount;
 | 
			
		||||
                if (vyWaitForAIOCompletion(entry->load) == VY_AIO_STATE_FINISHED) {
 | 
			
		||||
                if (rtWaitForAIOCompletion(entry->load) == RT_AIO_STATE_FINISHED) {
 | 
			
		||||
                    if (DecompressEntry(uid, entry)) {
 | 
			
		||||
                        result.data = entry->buffer;
 | 
			
		||||
                        result.size = entry->size;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        result.result = VY_LOAD_FAILED;
 | 
			
		||||
                        result.result = RT_LOAD_FAILED;
 | 
			
		||||
                    }
 | 
			
		||||
                } else {
 | 
			
		||||
                    ReleaseEntry(entry);
 | 
			
		||||
                    vyLog("ASSET_CACHE", "Failed to load asset %u", uid);
 | 
			
		||||
                    result.result = VY_LOAD_FAILED;
 | 
			
		||||
                    rtLog("ASSET_CACHE", "Failed to load asset %u", uid);
 | 
			
		||||
                    result.result = RT_LOAD_FAILED;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@ -354,14 +354,14 @@ VY_DLLEXPORT vy_get_asset_result vyGetAsset(vy_uid uid) {
 | 
			
		||||
        if (entry->prev_reclaim)
 | 
			
		||||
            entry->prev_reclaim->next_reclaim = entry->next_reclaim;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseAsset(vy_uid uid) {
 | 
			
		||||
    vyLockWrite(&_lock);
 | 
			
		||||
    vy_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
RT_DLLEXPORT void rtReleaseAsset(rt_uid uid) {
 | 
			
		||||
    rtLockWrite(&_lock);
 | 
			
		||||
    rt_asset_cache_entry *entry = GetEntry(uid);
 | 
			
		||||
    if (entry && entry->refcount > 0) {
 | 
			
		||||
        --entry->refcount;
 | 
			
		||||
        if (entry->refcount == 0) {
 | 
			
		||||
@ -375,5 +375,5 @@ VY_DLLEXPORT void vyReleaseAsset(vy_uid uid) {
 | 
			
		||||
            _last_reclaim       = entry;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockWrite(&_lock);
 | 
			
		||||
    rtUnlockWrite(&_lock);
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#define VY_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
#include "asset_dependencies.h"
 | 
			
		||||
 | 
			
		||||
#include "aio.h"
 | 
			
		||||
@ -12,87 +12,87 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t begin;
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
} vy_dep_list;
 | 
			
		||||
} rt_dep_list;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid *uids;
 | 
			
		||||
    vy_dep_list *lists;
 | 
			
		||||
    rt_uid *uids;
 | 
			
		||||
    rt_dep_list *lists;
 | 
			
		||||
    uint32_t capacity;
 | 
			
		||||
} vy_dep_map;
 | 
			
		||||
} rt_dep_map;
 | 
			
		||||
 | 
			
		||||
static vy_dep_map _map;
 | 
			
		||||
static vy_uid *_list_mem;
 | 
			
		||||
static rt_dep_map _map;
 | 
			
		||||
static rt_uid *_list_mem;
 | 
			
		||||
 | 
			
		||||
vy_result LoadAssetDependencies(void) {
 | 
			
		||||
    vy_dependency_file_header header;
 | 
			
		||||
    vy_file_id fid = vyAddFile("data/deps.bin");
 | 
			
		||||
rt_result LoadAssetDependencies(void) {
 | 
			
		||||
    rt_dependency_file_header header;
 | 
			
		||||
    rt_file_id fid = rtAddFile("data/deps.bin");
 | 
			
		||||
 | 
			
		||||
    if (vySubmitSingleLoadSync((vy_file_load){.dest      = &header,
 | 
			
		||||
    if (rtSubmitSingleLoadSync((rt_file_load){.dest      = &header,
 | 
			
		||||
                                              .num_bytes = sizeof(header),
 | 
			
		||||
                                              .offset    = 0,
 | 
			
		||||
                                              .file      = fid}) != VY_AIO_STATE_FINISHED) {
 | 
			
		||||
        vyReportError("core", "Failed to load deps.bin");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
                                              .file      = fid}) != RT_AIO_STATE_FINISHED) {
 | 
			
		||||
        rtReportError("core", "Failed to load deps.bin");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    void *buffer = vyAllocBuffer(header.data_size);
 | 
			
		||||
    if (vySubmitSingleLoadSync((vy_file_load){.dest      = buffer,
 | 
			
		||||
    void *buffer = rtAllocBuffer(header.data_size);
 | 
			
		||||
    if (rtSubmitSingleLoadSync((rt_file_load){.dest      = buffer,
 | 
			
		||||
                                              .num_bytes = header.data_size,
 | 
			
		||||
                                              .offset    = sizeof(header),
 | 
			
		||||
                                              .file      = fid}) != VY_AIO_STATE_FINISHED) {
 | 
			
		||||
        vyReportError("core", "Failed to load deps.bin");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
                                              .file      = fid}) != RT_AIO_STATE_FINISHED) {
 | 
			
		||||
        rtReportError("core", "Failed to load deps.bin");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* We know the exact number of list entries */
 | 
			
		||||
    uint64_t total_list_entries =
 | 
			
		||||
        (header.data_size - header.num_lists * sizeof(vy_dependency_file_list_header)) /
 | 
			
		||||
        sizeof(vy_uid);
 | 
			
		||||
    _list_mem = malloc(total_list_entries * sizeof(vy_uid));
 | 
			
		||||
        (header.data_size - header.num_lists * sizeof(rt_dependency_file_list_header)) /
 | 
			
		||||
        sizeof(rt_uid);
 | 
			
		||||
    _list_mem = malloc(total_list_entries * sizeof(rt_uid));
 | 
			
		||||
    if (!_list_mem) {
 | 
			
		||||
        vyReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        vyReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        rtReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _map.capacity = vyNextPowerOfTwo32(header.num_lists);
 | 
			
		||||
    _map.uids     = calloc(_map.capacity, sizeof(vy_uid));
 | 
			
		||||
    _map.capacity = rtNextPowerOfTwo32(header.num_lists);
 | 
			
		||||
    _map.uids     = calloc(_map.capacity, sizeof(rt_uid));
 | 
			
		||||
    if (!_map.uids) {
 | 
			
		||||
        free(_list_mem);
 | 
			
		||||
        vyReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        vyReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        rtReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    _map.lists = calloc(_map.capacity, sizeof(vy_dep_list));
 | 
			
		||||
    _map.lists = calloc(_map.capacity, sizeof(rt_dep_list));
 | 
			
		||||
    if (!_map.uids) {
 | 
			
		||||
        free(_list_mem);
 | 
			
		||||
        free(_map.uids);
 | 
			
		||||
        vyReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        vyReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
        rtReportError("core", "Failed to allocate dependency list storage.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    uint32_t storage_at = 0;
 | 
			
		||||
 | 
			
		||||
    vy_dependency_file_list_header *list = buffer;
 | 
			
		||||
    rt_dependency_file_list_header *list = buffer;
 | 
			
		||||
    for (uint32_t i = 0; i < header.num_lists; ++i) {
 | 
			
		||||
        const vy_uid *entries = (vy_uid *)(list + 1);
 | 
			
		||||
        const rt_uid *entries = (rt_uid *)(list + 1);
 | 
			
		||||
 | 
			
		||||
        /* Validate the checksum */
 | 
			
		||||
        XXH64_hash_t file_hash = XXH64_hashFromCanonical(&list->checksum);
 | 
			
		||||
        XXH64_hash_t calc_hash = XXH3_64bits(entries, sizeof(vy_uid) * list->num_entries);
 | 
			
		||||
        XXH64_hash_t calc_hash = XXH3_64bits(entries, sizeof(rt_uid) * list->num_entries);
 | 
			
		||||
        if (file_hash != calc_hash) {
 | 
			
		||||
            vyReportError("core", "Checksum mismatch in list %u", i);
 | 
			
		||||
            vyReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            rtReportError("core", "Checksum mismatch in list %u", i);
 | 
			
		||||
            rtReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Store the list */
 | 
			
		||||
        memcpy(_list_mem + storage_at, entries, sizeof(vy_uid) * list->num_entries);
 | 
			
		||||
        memcpy(_list_mem + storage_at, entries, sizeof(rt_uid) * list->num_entries);
 | 
			
		||||
        bool inserted = false;
 | 
			
		||||
        for (uint32_t j = 0; j < _map.capacity; ++j) {
 | 
			
		||||
            uint32_t slot = (list->uid + j) % _map.capacity;
 | 
			
		||||
            if (_map.uids[slot] == VY_INVALID_UID) {
 | 
			
		||||
            if (_map.uids[slot] == RT_INVALID_UID) {
 | 
			
		||||
                _map.uids[slot] = list->uid;
 | 
			
		||||
                _map.lists[slot].begin = storage_at;
 | 
			
		||||
                _map.lists[slot].count = list->num_entries;
 | 
			
		||||
@ -104,12 +104,12 @@ vy_result LoadAssetDependencies(void) {
 | 
			
		||||
        assert(inserted);
 | 
			
		||||
        assert(storage_at <= total_list_entries);
 | 
			
		||||
 | 
			
		||||
        list = (vy_dependency_file_list_header *)(entries + list->num_entries);
 | 
			
		||||
        list = (rt_dependency_file_list_header *)(entries + list->num_entries);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
    rtReleaseBuffer(buffer, header.data_size);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReleaseAssetDependencies(void) {
 | 
			
		||||
@ -118,8 +118,8 @@ void ReleaseAssetDependencies(void) {
 | 
			
		||||
    free(_map.lists);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_asset_dependency_list vyGetAssetDependencies(vy_uid asset) {
 | 
			
		||||
    vy_asset_dependency_list result = {
 | 
			
		||||
RT_DLLEXPORT rt_asset_dependency_list rtGetAssetDependencies(rt_uid asset) {
 | 
			
		||||
    rt_asset_dependency_list result = {
 | 
			
		||||
        .dependencies = NULL,
 | 
			
		||||
        .count        = 0,
 | 
			
		||||
    };
 | 
			
		||||
@ -129,7 +129,7 @@ VY_DLLEXPORT vy_asset_dependency_list vyGetAssetDependencies(vy_uid asset) {
 | 
			
		||||
            result.dependencies = &_list_mem[_map.lists[slot].begin];
 | 
			
		||||
            result.count        = _map.lists[slot].count;
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (_map.uids[slot] == VY_INVALID_UID) {
 | 
			
		||||
        } else if (_map.uids[slot] == RT_INVALID_UID) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
#ifndef VY_ASSET_DEPENDENCIES_H
 | 
			
		||||
#define VY_ASSET_DEPENDENCIES_H
 | 
			
		||||
#ifndef RT_ASSET_DEPENDENCIES_H
 | 
			
		||||
#define RT_ASSET_DEPENDENCIES_H
 | 
			
		||||
 | 
			
		||||
#include "assets.h"
 | 
			
		||||
 | 
			
		||||
#ifdef VY_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
#ifdef RT_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
 | 
			
		||||
#include "xxhash/xxhash.h"
 | 
			
		||||
 | 
			
		||||
@ -11,23 +11,23 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint64_t data_size;
 | 
			
		||||
    uint32_t num_lists;
 | 
			
		||||
} vy_dependency_file_header;
 | 
			
		||||
} rt_dependency_file_header;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid uid;
 | 
			
		||||
    rt_uid uid;
 | 
			
		||||
    uint32_t num_entries;
 | 
			
		||||
    XXH64_canonical_t checksum;
 | 
			
		||||
} vy_dependency_file_list_header;
 | 
			
		||||
} rt_dependency_file_list_header;
 | 
			
		||||
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const vy_uid *dependencies;
 | 
			
		||||
    const rt_uid *dependencies;
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
} vy_asset_dependency_list;
 | 
			
		||||
} rt_asset_dependency_list;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_asset_dependency_list vyGetAssetDependencies(vy_uid asset);
 | 
			
		||||
RT_DLLEXPORT rt_asset_dependency_list rtGetAssetDependencies(rt_uid asset);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -3,70 +3,70 @@
 | 
			
		||||
#include "aio.h"
 | 
			
		||||
#include "buffer_manager.h"
 | 
			
		||||
 | 
			
		||||
#define VY_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
#include "packages.h"
 | 
			
		||||
 | 
			
		||||
#include "lz4/lz4.h"
 | 
			
		||||
 | 
			
		||||
vy_result DecompressAsset(void *compressed_buffer,
 | 
			
		||||
rt_result DecompressAsset(void *compressed_buffer,
 | 
			
		||||
                          size_t compressed_buffer_size,
 | 
			
		||||
                          void **p_decompressed,
 | 
			
		||||
                          size_t *p_decompressed_size) {
 | 
			
		||||
 | 
			
		||||
    const vy_package_asset_header *header = compressed_buffer;
 | 
			
		||||
    const rt_package_asset_header *header = compressed_buffer;
 | 
			
		||||
 | 
			
		||||
    size_t compressed_size       = (compressed_buffer_size) - sizeof(*header);
 | 
			
		||||
    XXH64_hash_t calculated_hash = XXH3_64bits((header + 1), compressed_size);
 | 
			
		||||
    XXH64_hash_t file_hash       = XXH64_hashFromCanonical(&header->checksum);
 | 
			
		||||
    if (calculated_hash != file_hash) {
 | 
			
		||||
        vyLog("core", "Checksum mismatch for asset");
 | 
			
		||||
        return VY_LOAD_FAILED;
 | 
			
		||||
        rtLog("core", "Checksum mismatch for asset");
 | 
			
		||||
        return RT_LOAD_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t size               = (size_t)header->decompressed_size;
 | 
			
		||||
    void *decompressed_buffer = vyAllocBuffer(size);
 | 
			
		||||
    void *decompressed_buffer = rtAllocBuffer(size);
 | 
			
		||||
    if (!decompressed_buffer) {
 | 
			
		||||
        return VY_BUFFER_ALLOC_FAILED;
 | 
			
		||||
        return RT_BUFFER_ALLOC_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (LZ4_decompress_safe((const char *)(header + 1),
 | 
			
		||||
                            (char *)decompressed_buffer,
 | 
			
		||||
                            (int)compressed_size,
 | 
			
		||||
                            (int)size) < 0) {
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    *p_decompressed      = decompressed_buffer;
 | 
			
		||||
    *p_decompressed_size = size;
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyLoadAssetDirect(vy_uid uid, void **p_buffer, size_t *p_size) {
 | 
			
		||||
    const vy_uid_data *data = vyGetUIDData(uid);
 | 
			
		||||
RT_DLLEXPORT rt_result rtLoadAssetDirect(rt_uid uid, void **p_buffer, size_t *p_size) {
 | 
			
		||||
    const rt_uid_data *data = rtGetUIDData(uid);
 | 
			
		||||
    if (!data)
 | 
			
		||||
        return VY_UNKNOWN_ASSET;
 | 
			
		||||
        return RT_UNKNOWN_ASSET;
 | 
			
		||||
 | 
			
		||||
    void *compressed_buffer = vyAllocBuffer(data->size);
 | 
			
		||||
    void *compressed_buffer = rtAllocBuffer(data->size);
 | 
			
		||||
    if (!compressed_buffer) {
 | 
			
		||||
        return VY_BUFFER_ALLOC_FAILED;
 | 
			
		||||
        return RT_BUFFER_ALLOC_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vySubmitSingleLoadSync((vy_file_load) {
 | 
			
		||||
    if (rtSubmitSingleLoadSync((rt_file_load) {
 | 
			
		||||
            .file      = data->pkg_file,
 | 
			
		||||
            .offset    = data->offset,
 | 
			
		||||
            .num_bytes = data->size,
 | 
			
		||||
            .dest      = compressed_buffer,
 | 
			
		||||
        }) != VY_AIO_STATE_FINISHED) {
 | 
			
		||||
        vyReleaseBuffer(compressed_buffer, data->size);
 | 
			
		||||
        return VY_LOAD_FAILED;
 | 
			
		||||
        }) != RT_AIO_STATE_FINISHED) {
 | 
			
		||||
        rtReleaseBuffer(compressed_buffer, data->size);
 | 
			
		||||
        return RT_LOAD_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void *decompressed_buffer;
 | 
			
		||||
    size_t decompressed_size;
 | 
			
		||||
    vy_result res = DecompressAsset(compressed_buffer, data->size, &decompressed_buffer, &decompressed_size);
 | 
			
		||||
    rt_result res = DecompressAsset(compressed_buffer, data->size, &decompressed_buffer, &decompressed_size);
 | 
			
		||||
 | 
			
		||||
    vyReleaseBuffer(compressed_buffer, data->size);
 | 
			
		||||
    rtReleaseBuffer(compressed_buffer, data->size);
 | 
			
		||||
    *p_buffer = decompressed_buffer;
 | 
			
		||||
    *p_size   = decompressed_size;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,40 +1,40 @@
 | 
			
		||||
#ifndef VY_ASSETS_H
 | 
			
		||||
#define VY_ASSETS_H
 | 
			
		||||
#ifndef RT_ASSETS_H
 | 
			
		||||
#define RT_ASSETS_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
/* Unique identifier for an asset. */
 | 
			
		||||
typedef uint32_t vy_uid;
 | 
			
		||||
typedef uint32_t rt_uid;
 | 
			
		||||
 | 
			
		||||
#define VY_INVALID_UID 0
 | 
			
		||||
#define RT_INVALID_UID 0
 | 
			
		||||
 | 
			
		||||
/* Used to identify renderer backend dependent assets. */
 | 
			
		||||
enum {
 | 
			
		||||
    VY_INVALID_RENDERER_BACKEND_CODE = 0,
 | 
			
		||||
    VY_RENDERER_BACKEND_CODE_VK      = 1,
 | 
			
		||||
    RT_INVALID_RENDERER_BACKEND_CODE = 0,
 | 
			
		||||
    RT_RENDERER_BACKEND_CODE_VK      = 1,
 | 
			
		||||
 | 
			
		||||
    VY_RENDERER_BACKEND_CODE_ONE_PAST_LAST,
 | 
			
		||||
    RT_RENDERER_BACKEND_CODE_ONE_PAST_LAST,
 | 
			
		||||
};
 | 
			
		||||
typedef uint8_t vy_renderer_backend_code;
 | 
			
		||||
typedef uint8_t rt_renderer_backend_code;
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_UNKNOWN_ASSET = VY_CUSTOM_ERROR_START,
 | 
			
		||||
    VY_BUFFER_ALLOC_FAILED,
 | 
			
		||||
    VY_LOAD_FAILED,
 | 
			
		||||
    VY_ASSET_CACHE_FULL,
 | 
			
		||||
    RT_UNKNOWN_ASSET = RT_CUSTOM_ERROR_START,
 | 
			
		||||
    RT_BUFFER_ALLOC_FAILED,
 | 
			
		||||
    RT_LOAD_FAILED,
 | 
			
		||||
    RT_ASSET_CACHE_FULL,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Load an asset without using the cache */
 | 
			
		||||
VY_DLLEXPORT vy_result vyLoadAssetDirect(vy_uid uid, void **buffer, size_t *size);
 | 
			
		||||
RT_DLLEXPORT rt_result rtLoadAssetDirect(rt_uid uid, void **buffer, size_t *size);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    void *data;
 | 
			
		||||
    size_t size;
 | 
			
		||||
    vy_result result;
 | 
			
		||||
} vy_get_asset_result;
 | 
			
		||||
    rt_result result;
 | 
			
		||||
} rt_get_asset_result;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_get_asset_result vyGetAsset(vy_uid uid);
 | 
			
		||||
RT_DLLEXPORT rt_get_asset_result rtGetAsset(rt_uid uid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -8,13 +8,13 @@
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 | 
			
		||||
typedef struct vy_buffer_region_s {
 | 
			
		||||
typedef struct rt_buffer_region_s {
 | 
			
		||||
    void *memory;
 | 
			
		||||
    int16_t *refcounts; // One per block
 | 
			
		||||
    uint32_t *bitmap;
 | 
			
		||||
    size_t block_count;
 | 
			
		||||
    vy_mutex *guard;
 | 
			
		||||
} vy_buffer_region;
 | 
			
		||||
    rt_mutex *guard;
 | 
			
		||||
} rt_buffer_region;
 | 
			
		||||
 | 
			
		||||
/* Count leading zeroes.
 | 
			
		||||
 * Note that the return value of __builtin_clz(0) is undefined. */
 | 
			
		||||
@ -49,17 +49,17 @@ static inline bool IsLZCNTSupported(void) {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* NOTE(Kevin): Keep these sorted! */
 | 
			
		||||
static size_t _block_sizes[] = {VY_KB(512), VY_MB(1), VY_MB(4), VY_MB(8)};
 | 
			
		||||
static size_t _block_sizes[] = {RT_KB(512), RT_MB(1), RT_MB(4), RT_MB(8)};
 | 
			
		||||
#define NUM_BLOCK_SIZES (sizeof(_block_sizes) / sizeof(_block_sizes[0]))
 | 
			
		||||
static vy_buffer_region _regions[NUM_BLOCK_SIZES];
 | 
			
		||||
static rt_buffer_region _regions[NUM_BLOCK_SIZES];
 | 
			
		||||
 | 
			
		||||
VY_CVAR_SZ(rt_BufferManagerMemory,
 | 
			
		||||
RT_CVAR_SZ(rt_BufferManagerMemory,
 | 
			
		||||
           "Total number of bytes allocated for the buffer manager. Default: 1GB",
 | 
			
		||||
           VY_GB(1));
 | 
			
		||||
           RT_GB(1));
 | 
			
		||||
 | 
			
		||||
vy_result InitBufferManager(void) {
 | 
			
		||||
rt_result InitBufferManager(void) {
 | 
			
		||||
    if ((rt_BufferManagerMemory.sz % NUM_BLOCK_SIZES) != 0)
 | 
			
		||||
        vyLog("BUFFERMGR",
 | 
			
		||||
        rtLog("BUFFERMGR",
 | 
			
		||||
              "Configured memory amount is not dividable by number of block "
 | 
			
		||||
              "sizes: %u MB/%u",
 | 
			
		||||
              rt_BufferManagerMemory.sz / (1024 * 1024),
 | 
			
		||||
@ -68,7 +68,7 @@ vy_result InitBufferManager(void) {
 | 
			
		||||
    size_t mem_per_size = rt_BufferManagerMemory.sz / NUM_BLOCK_SIZES;
 | 
			
		||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
			
		||||
        if ((mem_per_size % _block_sizes[i]) != 0)
 | 
			
		||||
            vyLog("BUFFERMGR",
 | 
			
		||||
            rtLog("BUFFERMGR",
 | 
			
		||||
                  "Memory per block size is not dividable by block size: %u "
 | 
			
		||||
                  "MB/%u KB",
 | 
			
		||||
                  mem_per_size / (1024 * 1024),
 | 
			
		||||
@ -76,46 +76,46 @@ vy_result InitBufferManager(void) {
 | 
			
		||||
 | 
			
		||||
        size_t block_count      = mem_per_size / _block_sizes[i];
 | 
			
		||||
        _regions[i].block_count = block_count;
 | 
			
		||||
        _regions[i].guard       = vyCreateMutex();
 | 
			
		||||
        _regions[i].guard       = rtCreateMutex();
 | 
			
		||||
        if (!_regions[i].guard) {
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to create guard mutex %u", i);
 | 
			
		||||
            return VY_BUFFER_MGR_MUTEX_CREATION_FAILED;
 | 
			
		||||
            rtReportError("BUFFERMGR", "Failed to create guard mutex %u", i);
 | 
			
		||||
            return RT_BUFFER_MGR_MUTEX_CREATION_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        _regions[i].memory = malloc(mem_per_size);
 | 
			
		||||
        if (!_regions[i].memory) {
 | 
			
		||||
            vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return VY_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
            rtDestroyMutex(_regions[i].guard);
 | 
			
		||||
            rtReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return RT_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
        }
 | 
			
		||||
        _regions[i].bitmap = calloc((block_count + 31) / 32, sizeof(uint32_t));
 | 
			
		||||
        if (!_regions[i].bitmap) {
 | 
			
		||||
            vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
            rtDestroyMutex(_regions[i].guard);
 | 
			
		||||
            free(_regions[i].memory);
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return VY_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
            rtReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return RT_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
        }
 | 
			
		||||
        _regions[i].refcounts = calloc(block_count, sizeof(uint16_t));
 | 
			
		||||
        if (!_regions[i].refcounts) {
 | 
			
		||||
            vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
            rtDestroyMutex(_regions[i].guard);
 | 
			
		||||
            free(_regions[i].memory);
 | 
			
		||||
            free(_regions[i].bitmap);
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return VY_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
            rtReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return RT_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ShutdownBufferManager(void) {
 | 
			
		||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
			
		||||
        vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
        rtDestroyMutex(_regions[i].guard);
 | 
			
		||||
        free(_regions[i].memory);
 | 
			
		||||
        free(_regions[i].bitmap);
 | 
			
		||||
        free(_regions[i].refcounts);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
			
		||||
RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
 | 
			
		||||
    assert(IsLZCNTSupported());
 | 
			
		||||
 | 
			
		||||
    // Determine the best block size to use
 | 
			
		||||
@ -131,8 +131,8 @@ VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
			
		||||
 | 
			
		||||
    void *result = NULL;
 | 
			
		||||
 | 
			
		||||
    vy_buffer_region *region = &_regions[best_fit];
 | 
			
		||||
    vyLockMutex(region->guard);
 | 
			
		||||
    rt_buffer_region *region = &_regions[best_fit];
 | 
			
		||||
    rtLockMutex(region->guard);
 | 
			
		||||
    size_t dword_count = (region->block_count + 31) / 32;
 | 
			
		||||
 | 
			
		||||
    if (required_blocks < 32) {
 | 
			
		||||
@ -207,11 +207,11 @@ VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(region->guard);
 | 
			
		||||
    rtUnlockMutex(region->guard);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size) {
 | 
			
		||||
RT_DLLEXPORT void rtReleaseBuffer(const void *begin, size_t size) {
 | 
			
		||||
    if (!begin)
 | 
			
		||||
        return;
 | 
			
		||||
    uintptr_t begin_addr = (uintptr_t)begin;
 | 
			
		||||
@ -223,7 +223,7 @@ VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size) {
 | 
			
		||||
            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
			
		||||
            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
			
		||||
 | 
			
		||||
            vyLockMutex(_regions[i].guard);
 | 
			
		||||
            rtLockMutex(_regions[i].guard);
 | 
			
		||||
            for (size_t j = 0; j < block_count; ++j) {
 | 
			
		||||
                size_t dword = (first_block + j) / 32;
 | 
			
		||||
                size_t bit   = (first_block + j) % 32;
 | 
			
		||||
@ -231,14 +231,14 @@ VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size) {
 | 
			
		||||
                if (--_regions[i].refcounts[first_block + j] == 0)
 | 
			
		||||
                    _regions[i].bitmap[dword] &= ~(1u << bit);
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockMutex(_regions[i].guard);
 | 
			
		||||
            rtUnlockMutex(_regions[i].guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyLog("BUFFERMGR", "Tried to release an invalid buffer");
 | 
			
		||||
    rtLog("BUFFERMGR", "Tried to release an invalid buffer");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyIncreaseBufferRefCount(const void *begin, size_t size) {
 | 
			
		||||
RT_DLLEXPORT void rtIncreaseBufferRefCount(const void *begin, size_t size) {
 | 
			
		||||
    uintptr_t begin_addr = (uintptr_t)begin;
 | 
			
		||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
			
		||||
        uintptr_t region_addr = (uintptr_t)_regions[i].memory;
 | 
			
		||||
@ -248,13 +248,13 @@ VY_DLLEXPORT void vyIncreaseBufferRefCount(const void *begin, size_t size) {
 | 
			
		||||
            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
			
		||||
            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
			
		||||
 | 
			
		||||
            vyLockMutex(_regions[i].guard);
 | 
			
		||||
            rtLockMutex(_regions[i].guard);
 | 
			
		||||
            for (size_t j = 0; j < block_count; ++j) {
 | 
			
		||||
                ++_regions[i].refcounts[first_block + j];
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockMutex(_regions[i].guard);
 | 
			
		||||
            rtUnlockMutex(_regions[i].guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyLog("BUFFERMGR", "Tried to increase the refcount of an invalid buffer");
 | 
			
		||||
    rtLog("BUFFERMGR", "Tried to increase the refcount of an invalid buffer");
 | 
			
		||||
}
 | 
			
		||||
@ -1,17 +1,17 @@
 | 
			
		||||
#ifndef VY_BUFFER_MANAGER_H
 | 
			
		||||
#define VY_BUFFER_MANAGER_H
 | 
			
		||||
#ifndef RT_BUFFER_MANAGER_H
 | 
			
		||||
#define RT_BUFFER_MANAGER_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_BUFFER_MGR_OUT_OF_MEMORY = VY_CUSTOM_ERROR_START,
 | 
			
		||||
    VY_BUFFER_MGR_MUTEX_CREATION_FAILED,
 | 
			
		||||
    RT_BUFFER_MGR_OUT_OF_MEMORY = RT_CUSTOM_ERROR_START,
 | 
			
		||||
    RT_BUFFER_MGR_MUTEX_CREATION_FAILED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyAllocBuffer(size_t size);
 | 
			
		||||
RT_DLLEXPORT void *rtAllocBuffer(size_t size);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size);
 | 
			
		||||
RT_DLLEXPORT void rtReleaseBuffer(const void *begin, size_t size);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyIncreaseBufferRefCount(const void *begin, size_t size);
 | 
			
		||||
RT_DLLEXPORT void rtIncreaseBufferRefCount(const void *begin, size_t size);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -5,35 +5,35 @@
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define VY_MAX_CVARS 1024
 | 
			
		||||
#define RT_MAX_CVARS 1024
 | 
			
		||||
 | 
			
		||||
static vy_cvar *_vars[VY_MAX_CVARS];
 | 
			
		||||
static rt_cvar *_vars[RT_MAX_CVARS];
 | 
			
		||||
static unsigned int _next = 0;
 | 
			
		||||
static vy_mutex *_mutex   = NULL;
 | 
			
		||||
static rt_mutex *_mutex   = NULL;
 | 
			
		||||
 | 
			
		||||
void vyRegisterCVAR(vy_cvar *cvar) {
 | 
			
		||||
void rtRegisterCVAR(rt_cvar *cvar) {
 | 
			
		||||
    if (!_mutex)
 | 
			
		||||
        _mutex = vyCreateMutex();
 | 
			
		||||
    vyLockMutex(_mutex);
 | 
			
		||||
    if (_next < VY_MAX_CVARS) {
 | 
			
		||||
        _mutex = rtCreateMutex();
 | 
			
		||||
    rtLockMutex(_mutex);
 | 
			
		||||
    if (_next < RT_MAX_CVARS) {
 | 
			
		||||
        _vars[_next++] = cvar;
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("cvar", "Ran out of space for CVars");
 | 
			
		||||
        rtReportError("cvar", "Ran out of space for CVars");
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_mutex);
 | 
			
		||||
    rtUnlockMutex(_mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_cvar *vyGetCVAR(const char *name) {
 | 
			
		||||
rt_cvar *rtGetCVAR(const char *name) {
 | 
			
		||||
    if (!_mutex)
 | 
			
		||||
        _mutex = vyCreateMutex();
 | 
			
		||||
    vy_cvar *var = NULL;
 | 
			
		||||
    vyLockMutex(_mutex);
 | 
			
		||||
        _mutex = rtCreateMutex();
 | 
			
		||||
    rt_cvar *var = NULL;
 | 
			
		||||
    rtLockMutex(_mutex);
 | 
			
		||||
    for (unsigned int i = 0; i < _next; ++i) {
 | 
			
		||||
        if (strcmp(name, _vars[i]->name) == 0) {
 | 
			
		||||
            var = _vars[i];
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_mutex);
 | 
			
		||||
    rtUnlockMutex(_mutex);
 | 
			
		||||
    return var;
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +1,14 @@
 | 
			
		||||
#ifndef VY_CONFIG_H
 | 
			
		||||
#define VY_CONFIG_H
 | 
			
		||||
#ifndef RT_CONFIG_H
 | 
			
		||||
#define RT_CONFIG_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_CVAR_TYPE_INT,
 | 
			
		||||
    VY_CVAR_TYPE_FLOAT,
 | 
			
		||||
    VY_CVAR_TYPE_STRING,
 | 
			
		||||
    VY_CVAR_TYPE_SIZE,
 | 
			
		||||
} vy_cvar_type;
 | 
			
		||||
    RT_CVAR_TYPE_INT,
 | 
			
		||||
    RT_CVAR_TYPE_FLOAT,
 | 
			
		||||
    RT_CVAR_TYPE_STRING,
 | 
			
		||||
    RT_CVAR_TYPE_SIZE,
 | 
			
		||||
} rt_cvar_type;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *name;
 | 
			
		||||
@ -19,21 +19,21 @@ typedef struct {
 | 
			
		||||
        const char *s;
 | 
			
		||||
        size_t sz;
 | 
			
		||||
    };
 | 
			
		||||
    vy_cvar_type type;
 | 
			
		||||
} vy_cvar;
 | 
			
		||||
    rt_cvar_type type;
 | 
			
		||||
} rt_cvar;
 | 
			
		||||
 | 
			
		||||
/* n variable name, d description string, v default value*/
 | 
			
		||||
#define VY_CVAR_I(n, d, v)                                                                         \
 | 
			
		||||
    vy_cvar n = {.name = #n, .description = d, .i = (v), .type = VY_CVAR_TYPE_INT}
 | 
			
		||||
#define VY_CVAR_F(n, d, v)                                                                         \
 | 
			
		||||
    vy_cvar n = {.name = #n, .description = d, .f = (v), .type = VY_CVAR_TYPE_FLOAT}
 | 
			
		||||
#define VY_CVAR_S(n, d, v)                                                                         \
 | 
			
		||||
    vy_cvar n = {.name = #n, .description = d, .s = (v), .type = VY_CVAR_TYPE_STRING}
 | 
			
		||||
#define VY_CVAR_SZ(n, d, v)                                                                        \
 | 
			
		||||
    vy_cvar n = {.name = #n, .description = d, .sz = (v), .type = VY_CVAR_TYPE_SIZE}
 | 
			
		||||
#define RT_CVAR_I(n, d, v)                                                                         \
 | 
			
		||||
    rt_cvar n = {.name = #n, .description = d, .i = (v), .type = RT_CVAR_TYPE_INT}
 | 
			
		||||
#define RT_CVAR_F(n, d, v)                                                                         \
 | 
			
		||||
    rt_cvar n = {.name = #n, .description = d, .f = (v), .type = RT_CVAR_TYPE_FLOAT}
 | 
			
		||||
#define RT_CVAR_S(n, d, v)                                                                         \
 | 
			
		||||
    rt_cvar n = {.name = #n, .description = d, .s = (v), .type = RT_CVAR_TYPE_STRING}
 | 
			
		||||
#define RT_CVAR_SZ(n, d, v)                                                                        \
 | 
			
		||||
    rt_cvar n = {.name = #n, .description = d, .sz = (v), .type = RT_CVAR_TYPE_SIZE}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterCVAR(vy_cvar *cvar);
 | 
			
		||||
RT_DLLEXPORT void rtRegisterCVAR(rt_cvar *cvar);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_cvar *vyGetCVAR(const char *name);
 | 
			
		||||
RT_DLLEXPORT rt_cvar *rtGetCVAR(const char *name);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -4,41 +4,41 @@
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
 | 
			
		||||
    return (vy_dynlib)GetModuleHandleW(NULL);
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenCallerLib(void) {
 | 
			
		||||
    return (rt_dynlib)GetModuleHandleW(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenLib(const char *libname) {
 | 
			
		||||
    wchar_t libname_w[MAX_PATH];
 | 
			
		||||
    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, libname, -1, libname_w, MAX_PATH);
 | 
			
		||||
    HMODULE mod = LoadLibraryW(libname_w);
 | 
			
		||||
    return (vy_dynlib)mod;
 | 
			
		||||
    return (rt_dynlib)mod;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol) {
 | 
			
		||||
RT_DLLEXPORT void *rtGetSymbol(rt_dynlib lib, const char *symbol) {
 | 
			
		||||
    return (void *)GetProcAddress((HMODULE)lib, symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
			
		||||
RT_DLLEXPORT void rtCloseLib(rt_dynlib lib) {
 | 
			
		||||
    FreeLibrary((HMODULE)lib);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenCallerLib(void) {
 | 
			
		||||
    return dlopen(NULL, RTLD_NOW | RTLD_LOCAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenLib(const char *libname) {
 | 
			
		||||
    return dlopen(libname, RTLD_NOW | RTLD_LOCAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol) {
 | 
			
		||||
RT_DLLEXPORT void *rtGetSymbol(rt_dynlib lib, const char *symbol) {
 | 
			
		||||
    return dlsym(lib, symbol);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
			
		||||
RT_DLLEXPORT void rtCloseLib(rt_dynlib lib) {
 | 
			
		||||
    dlclose(lib);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,26 +1,26 @@
 | 
			
		||||
#ifndef VY_DYNAMIC_LIBS_H
 | 
			
		||||
#define VY_DYNAMIC_LIBS_H
 | 
			
		||||
#ifndef RT_DYNAMIC_LIBS_H
 | 
			
		||||
#define RT_DYNAMIC_LIBS_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#define VY_DLLNAME(s)                                                                              \
 | 
			
		||||
#define RT_DLLNAME(s)                                                                              \
 | 
			
		||||
    (".\\"s                                                                                        \
 | 
			
		||||
     ".dll")
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
#define VY_DLLNAME(s)                                                                              \
 | 
			
		||||
#define RT_DLLNAME(s)                                                                              \
 | 
			
		||||
    ("./lib"s                                                                                      \
 | 
			
		||||
     ".so")
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef void *vy_dynlib;
 | 
			
		||||
typedef void *rt_dynlib;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname);
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenLib(const char *libname);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void);
 | 
			
		||||
RT_DLLEXPORT rt_dynlib rtOpenCallerLib(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol);
 | 
			
		||||
RT_DLLEXPORT void *rtGetSymbol(rt_dynlib lib, const char *symbol);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib);
 | 
			
		||||
RT_DLLEXPORT void rtCloseLib(rt_dynlib lib);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -22,14 +22,14 @@
 | 
			
		||||
static bool DisplayErrorBox(const char *text) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    WCHAR msg[256];
 | 
			
		||||
    vyUTF8ToWStr(text, msg, VY_ARRAY_COUNT(msg));
 | 
			
		||||
    rtUTF8ToWStr(text, msg, RT_ARRAY_COUNT(msg));
 | 
			
		||||
 | 
			
		||||
#ifdef VY_ERROR_REPORT_DEBUGBREAK
 | 
			
		||||
#ifdef RT_ERROR_REPORT_DEBUGBREAK
 | 
			
		||||
    return MessageBoxW(NULL, msg, L"Error", MB_OKCANCEL | MB_ICONERROR) == IDCANCEL;
 | 
			
		||||
#else
 | 
			
		||||
    MessageBoxW(NULL, msg, L"Error", MB_ICONERROR);
 | 
			
		||||
    return false;
 | 
			
		||||
#endif /* VY_ERROR_REPORT_DEBUGBREAK */
 | 
			
		||||
#endif /* RT_ERROR_REPORT_DEBUGBREAK */
 | 
			
		||||
#else
 | 
			
		||||
    return false;
 | 
			
		||||
#endif
 | 
			
		||||
@ -38,21 +38,21 @@ static bool DisplayErrorBox(const char *text) {
 | 
			
		||||
static void LogOut(const char *text) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    WCHAR msg[256];
 | 
			
		||||
    vyUTF8ToWStr(text, msg, VY_ARRAY_COUNT(msg));
 | 
			
		||||
    rtUTF8ToWStr(text, msg, RT_ARRAY_COUNT(msg));
 | 
			
		||||
    OutputDebugStringW(msg);
 | 
			
		||||
#endif
 | 
			
		||||
    fprintf(stderr, "%s", text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
RT_DLLEXPORT void rtReportError(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
    char buf[256];
 | 
			
		||||
 | 
			
		||||
    int at = snprintf(buf, VY_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem);
 | 
			
		||||
    int at = snprintf(buf, RT_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem);
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    va_start(ap, fmt);
 | 
			
		||||
    at += vsnprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, fmt, ap);
 | 
			
		||||
    at += vsnprintf(&buf[at], RT_ARRAY_COUNT(buf) - at - 1, fmt, ap);
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
			
		||||
    at += snprintf(&buf[at], RT_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
			
		||||
 | 
			
		||||
    LogOut(buf);
 | 
			
		||||
    if (DisplayErrorBox(buf)) {
 | 
			
		||||
@ -60,15 +60,15 @@ VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
RT_DLLEXPORT void rtLog(const char *subsystem, const char *fmt, ...) {
 | 
			
		||||
    char buf[256];
 | 
			
		||||
 | 
			
		||||
    int at = snprintf(buf, VY_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem);
 | 
			
		||||
    int at = snprintf(buf, RT_ARRAY_COUNT(buf) - 1, "[%s] ", subsystem);
 | 
			
		||||
    va_list ap;
 | 
			
		||||
    va_start(ap, fmt);
 | 
			
		||||
    at += vsnprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, fmt, ap);
 | 
			
		||||
    at += vsnprintf(&buf[at], RT_ARRAY_COUNT(buf) - at - 1, fmt, ap);
 | 
			
		||||
    va_end(ap);
 | 
			
		||||
    at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
			
		||||
    at += snprintf(&buf[at], RT_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
			
		||||
 | 
			
		||||
    LogOut(buf);
 | 
			
		||||
}
 | 
			
		||||
@ -6,22 +6,22 @@
 | 
			
		||||
 | 
			
		||||
#define NAME_CAP(cap) ((cap)*128)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id *ids;
 | 
			
		||||
    rt_file_id *ids;
 | 
			
		||||
    unsigned int *name_offsets;
 | 
			
		||||
    char *names;
 | 
			
		||||
    unsigned int capacity;
 | 
			
		||||
    unsigned int name_head;
 | 
			
		||||
 | 
			
		||||
    vy_mutex *mutex;
 | 
			
		||||
} vy_file_tab;
 | 
			
		||||
    rt_mutex *mutex;
 | 
			
		||||
} rt_file_tab;
 | 
			
		||||
 | 
			
		||||
static vy_file_tab _file_tab;
 | 
			
		||||
static rt_file_tab _file_tab;
 | 
			
		||||
 | 
			
		||||
VY_CVAR_I(rt_FileTabCapacity, "Maximum number of filetab entries. Default: 1024", 1024);
 | 
			
		||||
RT_CVAR_I(rt_FileTabCapacity, "Maximum number of filetab entries. Default: 1024", 1024);
 | 
			
		||||
 | 
			
		||||
vy_result InitFileTab(void) {
 | 
			
		||||
rt_result InitFileTab(void) {
 | 
			
		||||
    unsigned int max_files = (unsigned int)rt_FileTabCapacity.i;
 | 
			
		||||
    _file_tab.ids = calloc(max_files, sizeof(vy_file_id));
 | 
			
		||||
    _file_tab.ids = calloc(max_files, sizeof(rt_file_id));
 | 
			
		||||
    if (!_file_tab.ids)
 | 
			
		||||
        return 1;
 | 
			
		||||
    _file_tab.name_offsets = calloc(max_files, sizeof(unsigned int));
 | 
			
		||||
@ -33,38 +33,38 @@ vy_result InitFileTab(void) {
 | 
			
		||||
 | 
			
		||||
    _file_tab.capacity  = max_files;
 | 
			
		||||
    _file_tab.name_head = 0;
 | 
			
		||||
    _file_tab.mutex     = vyCreateMutex();
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    _file_tab.mutex     = rtCreateMutex();
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ShutdownFileTab(void) {
 | 
			
		||||
    free(_file_tab.ids);
 | 
			
		||||
    free(_file_tab.names);
 | 
			
		||||
    free(_file_tab.name_offsets);
 | 
			
		||||
    vyDestroyMutex(_file_tab.mutex);
 | 
			
		||||
    rtDestroyMutex(_file_tab.mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyGetFileId(const char *path) {
 | 
			
		||||
    vy_text_span span;
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtGetFileId(const char *path) {
 | 
			
		||||
    rt_text_span span;
 | 
			
		||||
    span.start  = path;
 | 
			
		||||
    span.length = (unsigned int)strlen(path);
 | 
			
		||||
    return vyGetFileIdFromSpan(span);
 | 
			
		||||
    return rtGetFileIdFromSpan(span);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyGetFileIdFromSpan(vy_text_span path) {
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtGetFileIdFromSpan(rt_text_span path) {
 | 
			
		||||
    /* Randomly choosen, aka finger smash keyboard */
 | 
			
		||||
    XXH64_hash_t seed = 15340978;
 | 
			
		||||
    vy_file_id fid    = (vy_file_id)XXH3_64bits_withSeed(path.start, path.length, seed);
 | 
			
		||||
    rt_file_id fid    = (rt_file_id)XXH3_64bits_withSeed(path.start, path.length, seed);
 | 
			
		||||
    if (fid == 0)
 | 
			
		||||
        fid = ~fid;
 | 
			
		||||
    return fid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyAddFileFromSpan(vy_text_span path) {
 | 
			
		||||
    vy_file_id fid = vyGetFileIdFromSpan(path);
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtAddFileFromSpan(rt_text_span path) {
 | 
			
		||||
    rt_file_id fid = rtGetFileIdFromSpan(path);
 | 
			
		||||
 | 
			
		||||
    if (!vyLockMutex(_file_tab.mutex)) {
 | 
			
		||||
        vyReportError("fio", "Failed to lock the guard mutex.");
 | 
			
		||||
    if (!rtLockMutex(_file_tab.mutex)) {
 | 
			
		||||
        rtReportError("fio", "Failed to lock the guard mutex.");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -97,24 +97,24 @@ VY_DLLEXPORT vy_file_id vyAddFileFromSpan(vy_text_span path) {
 | 
			
		||||
    if (i == _file_tab.capacity)
 | 
			
		||||
        fid = 0;
 | 
			
		||||
 | 
			
		||||
    vyUnlockMutex(_file_tab.mutex);
 | 
			
		||||
    rtUnlockMutex(_file_tab.mutex);
 | 
			
		||||
    return fid;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyAddFile(const char *path) {
 | 
			
		||||
    vy_text_span span;
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtAddFile(const char *path) {
 | 
			
		||||
    rt_text_span span;
 | 
			
		||||
    span.start  = path;
 | 
			
		||||
    span.length = (unsigned int)strlen(path);
 | 
			
		||||
    return vyAddFileFromSpan(span);
 | 
			
		||||
    return rtAddFileFromSpan(span);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT const char *vyGetFilePath(vy_file_id fid) {
 | 
			
		||||
RT_DLLEXPORT const char *rtGetFilePath(rt_file_id fid) {
 | 
			
		||||
    /* Hash Lookup */
 | 
			
		||||
    if (fid == 0)
 | 
			
		||||
        return NULL;
 | 
			
		||||
 | 
			
		||||
    if (!vyLockMutex(_file_tab.mutex)) {
 | 
			
		||||
        vyReportError("fio", "Failed to lock the guard mutex.");
 | 
			
		||||
    if (!rtLockMutex(_file_tab.mutex)) {
 | 
			
		||||
        rtReportError("fio", "Failed to lock the guard mutex.");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    const char *result = NULL;
 | 
			
		||||
@ -130,6 +130,6 @@ VY_DLLEXPORT const char *vyGetFilePath(vy_file_id fid) {
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_file_tab.mutex);
 | 
			
		||||
    rtUnlockMutex(_file_tab.mutex);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,22 @@
 | 
			
		||||
#ifndef VY_FILE_TAB_H
 | 
			
		||||
#define VY_FILE_TAB_H
 | 
			
		||||
#ifndef RT_FILE_TAB_H
 | 
			
		||||
#define RT_FILE_TAB_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
/* used to identify a file (XXH3 hash of the path) */
 | 
			
		||||
typedef uint64_t vy_file_id;
 | 
			
		||||
#define VY_INVALID_FILE_ID 0
 | 
			
		||||
typedef uint64_t rt_file_id;
 | 
			
		||||
#define RT_INVALID_FILE_ID 0
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyGetFileId(const char *path);
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtGetFileId(const char *path);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyGetFileIdFromSpan(vy_text_span path);
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtGetFileIdFromSpan(rt_text_span path);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyAddFile(const char *path);
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtAddFile(const char *path);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_file_id vyAddFileFromSpan(vy_text_span path);
 | 
			
		||||
RT_DLLEXPORT rt_file_id rtAddFileFromSpan(rt_text_span path);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT const char *vyGetFilePath(vy_file_id fid);
 | 
			
		||||
RT_DLLEXPORT const char *rtGetFilePath(rt_file_id fid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_GFX_H
 | 
			
		||||
#define VY_GFX_H
 | 
			
		||||
#ifndef RT_GFX_H
 | 
			
		||||
#define RT_GFX_H
 | 
			
		||||
 | 
			
		||||
/* graphics system. this is the interface of the rendering code.
 | 
			
		||||
 *
 | 
			
		||||
@ -15,22 +15,22 @@
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
/* In renderer_api.h -> Not necessary for almost all gfx usage */
 | 
			
		||||
typedef struct vy_renderer_init_info_s vy_renderer_init_info;
 | 
			
		||||
typedef struct rt_renderer_init_info_s rt_renderer_init_info;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterRendererCVars(void);
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRendererCVars(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info);
 | 
			
		||||
RT_DLLEXPORT bool rtInitGFX(rt_renderer_init_info *renderer_info);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownGFX(void);
 | 
			
		||||
RT_DLLEXPORT void rtShutdownGFX(void);
 | 
			
		||||
 | 
			
		||||
/* Handles backend objects */
 | 
			
		||||
 | 
			
		||||
#define VY_GFX_HANDLE_MAX_VERSION 255
 | 
			
		||||
#define RT_GFX_HANDLE_MAX_VERSION 255
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t version : 8;
 | 
			
		||||
    uint32_t index : 24;
 | 
			
		||||
} vy_pipeline_handle;
 | 
			
		||||
} rt_pipeline_handle;
 | 
			
		||||
 | 
			
		||||
/* Attributes are used to bind buffers (or textures) to symbolic values.
 | 
			
		||||
 * For example, an attribute might be bound to "CELL_GRID", which would be
 | 
			
		||||
@ -39,15 +39,15 @@ typedef struct {
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_ATTRIBUTE_VALUE_UNDEFINED,
 | 
			
		||||
    RT_ATTRIBUTE_VALUE_UNDEFINED,
 | 
			
		||||
 | 
			
		||||
    VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO,
 | 
			
		||||
    VY_ATTRIBUTE_VALUE_MATERIAL_NORMAL,
 | 
			
		||||
} vy_attribute_value;
 | 
			
		||||
    RT_ATTRIBUTE_VALUE_MATERIAL_ALBEDO,
 | 
			
		||||
    RT_ATTRIBUTE_VALUE_MATERIAL_NORMAL,
 | 
			
		||||
} rt_attribute_value;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t index;
 | 
			
		||||
    vy_attribute_value value;
 | 
			
		||||
} vy_attribute_binding;
 | 
			
		||||
    rt_attribute_value value;
 | 
			
		||||
} rt_attribute_binding;
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
#define VY_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
#define RT_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "dynamic_libs.h"
 | 
			
		||||
@ -13,45 +13,45 @@
 | 
			
		||||
 * world cell.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
vy_renderer_api g_renderer;
 | 
			
		||||
static vy_dynlib _renderer_lib;
 | 
			
		||||
rt_renderer_api g_renderer;
 | 
			
		||||
static rt_dynlib _renderer_lib;
 | 
			
		||||
static bool _renderer_loaded = false;
 | 
			
		||||
 | 
			
		||||
VY_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], Default: vk", "vk");
 | 
			
		||||
 | 
			
		||||
#ifdef VY_STATIC_LIB
 | 
			
		||||
extern void VY_RENDERER_API_FN(RegisterCVars)(void);
 | 
			
		||||
extern vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *);
 | 
			
		||||
extern void VY_RENDERER_API_FN(Shutdown)(void);
 | 
			
		||||
extern vy_pipeline_handle VY_RENDERER_API_FN(CompilePipeline)(const vy_pipeline_info *);
 | 
			
		||||
extern void VY_RENDERER_API_FN(DestroyPipeline)(vy_pipeline_handle handle);
 | 
			
		||||
#ifdef RT_STATIC_LIB
 | 
			
		||||
extern void RT_RENDERER_API_FN(RegisterCVars)(void);
 | 
			
		||||
extern rt_result RT_RENDERER_API_FN(Init)(const rt_renderer_init_info *);
 | 
			
		||||
extern void RT_RENDERER_API_FN(Shutdown)(void);
 | 
			
		||||
extern rt_pipeline_handle RT_RENDERER_API_FN(CompilePipeline)(const rt_pipeline_info *);
 | 
			
		||||
extern void RT_RENDERER_API_FN(DestroyPipeline)(rt_pipeline_handle handle);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool LoadRenderer(void) {
 | 
			
		||||
 | 
			
		||||
#if !defined(VY_STATIC_LIB)
 | 
			
		||||
#if !defined(RT_STATIC_LIB)
 | 
			
		||||
#define RETRIEVE_SYMBOL(name, type)                                                                \
 | 
			
		||||
    g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vyRen" #name);                           \
 | 
			
		||||
    g_renderer.name = (type *)rtGetSymbol(_renderer_lib, "rtRen" #name);                           \
 | 
			
		||||
    if (!g_renderer.name) {                                                                        \
 | 
			
		||||
        vyReportError("GFX",                                                                       \
 | 
			
		||||
        rtReportError("GFX",                                                                       \
 | 
			
		||||
                      "Unable to retrieve renderer function %s from backend %s",                   \
 | 
			
		||||
                      #name,                                                                       \
 | 
			
		||||
                      rt_Renderer.s);                                                              \
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strcmp(rt_Renderer.s, "vk") == 0) {
 | 
			
		||||
        _renderer_lib = vyOpenLib(VY_DLLNAME("vyvk"));
 | 
			
		||||
        _renderer_lib = rtOpenLib(RT_DLLNAME("rtvk"));
 | 
			
		||||
        if (!_renderer_lib) {
 | 
			
		||||
            vyReportError("GFX", "Unable to load renderer backend: %s", VY_DLLNAME("vyvk"));
 | 
			
		||||
            rtReportError("GFX", "Unable to load renderer backend: %s", RT_DLLNAME("rtvk"));
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        RETRIEVE_SYMBOL(RegisterCVars, vy_register_renderer_cvars_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(Init, vy_init_renderer_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(Shutdown, vy_shutdown_renderer_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CompilePipeline, vy_compile_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(DestroyPipeline, vy_destroy_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(RegisterCVars, rt_register_renderer_cvars_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(Init, rt_init_renderer_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(Shutdown, rt_shutdown_renderer_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CompilePipeline, rt_compile_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(DestroyPipeline, rt_destroy_pipeline_fn);
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("GFX",
 | 
			
		||||
        rtReportError("GFX",
 | 
			
		||||
                      "Unsupported renderer backend: (%s) %s",
 | 
			
		||||
                      rt_Renderer.name,
 | 
			
		||||
                      rt_Renderer.s);
 | 
			
		||||
@ -59,16 +59,16 @@ static bool LoadRenderer(void) {
 | 
			
		||||
    }
 | 
			
		||||
#undef RETRIEVE_SYMBOL
 | 
			
		||||
#else
 | 
			
		||||
    g_renderer.RegisterCVars           = &vyRenRegisterCVars;
 | 
			
		||||
    g_renderer.Init                    = &vyRenInit;
 | 
			
		||||
    g_renderer.Shutdown                = &vyRenShutdown;
 | 
			
		||||
    g_renderer.CompilePipeline         = &vyRenCompilePipeline;
 | 
			
		||||
    g_renderer.DestroyPipeline         = &vyRenDestroyPipeline;
 | 
			
		||||
    g_renderer.RegisterCVars           = &rtRenRegisterCVars;
 | 
			
		||||
    g_renderer.Init                    = &rtRenInit;
 | 
			
		||||
    g_renderer.Shutdown                = &rtRenShutdown;
 | 
			
		||||
    g_renderer.CompilePipeline         = &rtRenCompilePipeline;
 | 
			
		||||
    g_renderer.DestroyPipeline         = &rtRenDestroyPipeline;
 | 
			
		||||
#endif
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterRendererCVars(void) {
 | 
			
		||||
RT_DLLEXPORT void rtRegisterRendererCVars(void) {
 | 
			
		||||
    if (!_renderer_loaded) {
 | 
			
		||||
        if (!LoadRenderer())
 | 
			
		||||
            return;
 | 
			
		||||
@ -77,19 +77,19 @@ VY_DLLEXPORT void vyRegisterRendererCVars(void) {
 | 
			
		||||
    g_renderer.RegisterCVars();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyInitGFX(vy_renderer_init_info *renderer_info) {
 | 
			
		||||
RT_DLLEXPORT bool rtInitGFX(rt_renderer_init_info *renderer_info) {
 | 
			
		||||
    if (!_renderer_loaded) {
 | 
			
		||||
        if (!LoadRenderer())
 | 
			
		||||
            return false;
 | 
			
		||||
        g_renderer.RegisterCVars();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (g_renderer.Init(renderer_info) != VY_SUCCESS)
 | 
			
		||||
    if (g_renderer.Init(renderer_info) != RT_SUCCESS)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownGFX(void) {
 | 
			
		||||
RT_DLLEXPORT void rtShutdownGFX(void) {
 | 
			
		||||
    g_renderer.Shutdown();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
#ifndef VY_HANDLES_H
 | 
			
		||||
#define VY_HANDLES_H
 | 
			
		||||
#ifndef RT_HANDLES_H
 | 
			
		||||
#define RT_HANDLES_H
 | 
			
		||||
 | 
			
		||||
/* All handle types should contain a uint32_t index */
 | 
			
		||||
 | 
			
		||||
#define VY_INVALID_HANDLE                                                                          \
 | 
			
		||||
#define RT_INVALID_HANDLE                                                                          \
 | 
			
		||||
    { .index = 0 }
 | 
			
		||||
 | 
			
		||||
#define VY_IS_HANDLE_VALID(handle) ((handle).index != 0)
 | 
			
		||||
#define RT_IS_HANDLE_VALID(handle) ((handle).index != 0)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -5,85 +5,85 @@
 | 
			
		||||
#include "buffer_manager.h"
 | 
			
		||||
#include "uidtab.h"
 | 
			
		||||
 | 
			
		||||
extern vy_cvar rt_Renderer;
 | 
			
		||||
extern vy_cvar rt_Fullscreen;
 | 
			
		||||
extern vy_cvar rt_WindowWidth;
 | 
			
		||||
extern vy_cvar rt_WindowHeight;
 | 
			
		||||
extern vy_cvar rt_BufferManagerMemory;
 | 
			
		||||
extern vy_cvar rt_FileTabCapacity;
 | 
			
		||||
extern vy_cvar rt_MaxConcurrentAsyncIO;
 | 
			
		||||
extern vy_cvar rt_AssetCacheSize;
 | 
			
		||||
extern rt_cvar rt_Renderer;
 | 
			
		||||
extern rt_cvar rt_Fullscreen;
 | 
			
		||||
extern rt_cvar rt_WindowWidth;
 | 
			
		||||
extern rt_cvar rt_WindowHeight;
 | 
			
		||||
extern rt_cvar rt_BufferManagerMemory;
 | 
			
		||||
extern rt_cvar rt_FileTabCapacity;
 | 
			
		||||
extern rt_cvar rt_MaxConcurrentAsyncIO;
 | 
			
		||||
extern rt_cvar rt_AssetCacheSize;
 | 
			
		||||
 | 
			
		||||
void RegisterRuntimeCVars(void) {
 | 
			
		||||
    vyRegisterCVAR(&rt_Renderer);
 | 
			
		||||
    vyRegisterCVAR(&rt_Fullscreen);
 | 
			
		||||
    vyRegisterCVAR(&rt_WindowWidth);
 | 
			
		||||
    vyRegisterCVAR(&rt_WindowHeight);
 | 
			
		||||
    vyRegisterCVAR(&rt_BufferManagerMemory);
 | 
			
		||||
    vyRegisterCVAR(&rt_FileTabCapacity);
 | 
			
		||||
    vyRegisterCVAR(&rt_MaxConcurrentAsyncIO);
 | 
			
		||||
    vyRegisterCVAR(&rt_AssetCacheSize);
 | 
			
		||||
    rtRegisterCVAR(&rt_Renderer);
 | 
			
		||||
    rtRegisterCVAR(&rt_Fullscreen);
 | 
			
		||||
    rtRegisterCVAR(&rt_WindowWidth);
 | 
			
		||||
    rtRegisterCVAR(&rt_WindowHeight);
 | 
			
		||||
    rtRegisterCVAR(&rt_BufferManagerMemory);
 | 
			
		||||
    rtRegisterCVAR(&rt_FileTabCapacity);
 | 
			
		||||
    rtRegisterCVAR(&rt_MaxConcurrentAsyncIO);
 | 
			
		||||
    rtRegisterCVAR(&rt_AssetCacheSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
extern void SetMainThreadId(void);
 | 
			
		||||
 | 
			
		||||
extern vy_result InitBufferManager(void);
 | 
			
		||||
extern rt_result InitBufferManager(void);
 | 
			
		||||
extern void ShutdownBufferManager(void);
 | 
			
		||||
extern vy_result InitFileTab(void);
 | 
			
		||||
extern rt_result InitFileTab(void);
 | 
			
		||||
extern void ShutdownFileTab(void);
 | 
			
		||||
extern vy_result InitAIO(void);
 | 
			
		||||
extern rt_result InitAIO(void);
 | 
			
		||||
extern void ShutdownAIO(void);
 | 
			
		||||
extern vy_result InitAssetCache(void);
 | 
			
		||||
extern rt_result InitAssetCache(void);
 | 
			
		||||
extern void ShutdownAssetCache(void);
 | 
			
		||||
 | 
			
		||||
extern vy_result LoadUIDTable(void);
 | 
			
		||||
extern rt_result LoadUIDTable(void);
 | 
			
		||||
extern void ReleaseUIDTable(void);
 | 
			
		||||
extern vy_result LoadAssetDependencies(void); 
 | 
			
		||||
extern rt_result LoadAssetDependencies(void); 
 | 
			
		||||
extern void ReleaseAssetDependencies(void);
 | 
			
		||||
extern vy_result LoadPackageNames(void);
 | 
			
		||||
extern rt_result LoadPackageNames(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyInitRuntime(void) {
 | 
			
		||||
RT_DLLEXPORT rt_result rtInitRuntime(void) {
 | 
			
		||||
    SetMainThreadId();
 | 
			
		||||
    RegisterRuntimeCVars();
 | 
			
		||||
 | 
			
		||||
    vy_result res;
 | 
			
		||||
    if ((res = InitBufferManager()) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("BUFFERMGR", "Init failed.");
 | 
			
		||||
    rt_result res;
 | 
			
		||||
    if ((res = InitBufferManager()) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("BUFFERMGR", "Init failed.");
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = InitFileTab()) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("FTAB", "Init failed.");
 | 
			
		||||
    if ((res = InitFileTab()) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("FTAB", "Init failed.");
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = InitAIO()) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("AIO", "Init failed.");
 | 
			
		||||
    if ((res = InitAIO()) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("AIO", "Init failed.");
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = InitAssetCache()) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("ASSETCACHE", "Init failed.");
 | 
			
		||||
    if ((res = InitAssetCache()) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("ASSETCACHE", "Init failed.");
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = LoadUIDTable()) != VY_SUCCESS) {
 | 
			
		||||
        vyLog("CORE", "LoadUIDTable returned result: %u", res);
 | 
			
		||||
    if ((res = LoadUIDTable()) != RT_SUCCESS) {
 | 
			
		||||
        rtLog("CORE", "LoadUIDTable returned result: %u", res);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = LoadAssetDependencies()) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("ASSETDEP", "Init failed.");
 | 
			
		||||
    if ((res = LoadAssetDependencies()) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("ASSETDEP", "Init failed.");
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((res = LoadPackageNames()) != VY_SUCCESS) {
 | 
			
		||||
        vyLog("CORE", "LoadPackageNames returned result: %u", res);
 | 
			
		||||
    if ((res = LoadPackageNames()) != RT_SUCCESS) {
 | 
			
		||||
        rtLog("CORE", "LoadPackageNames returned result: %u", res);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownRuntime(void) {
 | 
			
		||||
RT_DLLEXPORT void rtShutdownRuntime(void) {
 | 
			
		||||
    ReleaseAssetDependencies();
 | 
			
		||||
    ReleaseUIDTable();
 | 
			
		||||
    ShutdownAssetCache();
 | 
			
		||||
 | 
			
		||||
@ -8,27 +8,27 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t base_iteration;
 | 
			
		||||
    uint32_t iteration_count;
 | 
			
		||||
    vy_job_fn *fn;
 | 
			
		||||
    rt_job_fn *fn;
 | 
			
		||||
    void *param;
 | 
			
		||||
} vy_job_chunk;
 | 
			
		||||
} rt_job_chunk;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    /* Queue */
 | 
			
		||||
    struct {
 | 
			
		||||
        vy_job_chunk *chunks;
 | 
			
		||||
        rt_job_chunk *chunks;
 | 
			
		||||
        unsigned int head;
 | 
			
		||||
        unsigned int tail;
 | 
			
		||||
        vy_condition_var *lock;
 | 
			
		||||
        rt_condition_var *lock;
 | 
			
		||||
    } job_queue;
 | 
			
		||||
 | 
			
		||||
    /* Thread data */
 | 
			
		||||
    vy_thread *thread;
 | 
			
		||||
} vy_worker_data;
 | 
			
		||||
    rt_thread *thread;
 | 
			
		||||
} rt_worker_data;
 | 
			
		||||
 | 
			
		||||
static volatile bool _keep_running = true;
 | 
			
		||||
static vy_worker_data _worker_data[MAX_WORKERS];
 | 
			
		||||
static rt_worker_data _worker_data[MAX_WORKERS];
 | 
			
		||||
 | 
			
		||||
static void ExecOneJobIfAvailable(vy_worker_data *wd) {
 | 
			
		||||
static void ExecOneJobIfAvailable(rt_worker_data *wd) {
 | 
			
		||||
    if (wd->job_queue.head == wd->job_queue.tail) {
 | 
			
		||||
        /* No job available.
 | 
			
		||||
         * TODO: Pick one job queue at random and check if we can steal?
 | 
			
		||||
@ -36,7 +36,7 @@ static void ExecOneJobIfAvailable(vy_worker_data *wd) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_job_chunk chunk = wd->job_queue.chunks[wd->job_queue.head];
 | 
			
		||||
    rt_job_chunk chunk = wd->job_queue.chunks[wd->job_queue.head];
 | 
			
		||||
    wd->job_queue.head = (wd->job_queue.head + 1) % JOB_QUEUE_SIZE;
 | 
			
		||||
    for (uint32_t i = 0; i < chunk.iteration_count; ++i) {
 | 
			
		||||
        chunk.fn(chunk.param, chunk.base_iteration + i);
 | 
			
		||||
@ -44,22 +44,22 @@ static void ExecOneJobIfAvailable(vy_worker_data *wd) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void WorkerEntry(void *param) {
 | 
			
		||||
    vy_worker_data *wd = param;
 | 
			
		||||
    rt_worker_data *wd = param;
 | 
			
		||||
    while (_keep_running) {
 | 
			
		||||
        vyLockConditionVar(wd->job_queue.lock);
 | 
			
		||||
        rtLockConditionVar(wd->job_queue.lock);
 | 
			
		||||
        while (wd->job_queue.head == wd->job_queue.tail && _keep_running) {
 | 
			
		||||
            vyWaitOnConditionVar(wd->job_queue.lock);
 | 
			
		||||
            rtWaitOnConditionVar(wd->job_queue.lock);
 | 
			
		||||
        }
 | 
			
		||||
        ExecOneJobIfAvailable(wd);
 | 
			
		||||
        vyUnlockConditionVar(wd->job_queue.lock, false);
 | 
			
		||||
        rtUnlockConditionVar(wd->job_queue.lock, false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyInitJobSystem(unsigned int worker_count) {
 | 
			
		||||
void rtInitJobSystem(unsigned int worker_count) {
 | 
			
		||||
    if (worker_count > MAX_WORKERS)
 | 
			
		||||
        worker_count = MAX_WORKERS;
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < worker_count; ++i) {
 | 
			
		||||
        _worker_data[i].thread = vySpawnThread(WorkerEntry, &_worker_data[i], "JobWorker");
 | 
			
		||||
        _worker_data[i].thread = rtSpawnThread(WorkerEntry, &_worker_data[i], "JobWorker");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_JOBS_H
 | 
			
		||||
#define VY_JOBS_H
 | 
			
		||||
#ifndef RT_JOBS_H
 | 
			
		||||
#define RT_JOBS_H
 | 
			
		||||
 | 
			
		||||
/* Work stealing job scheduler */
 | 
			
		||||
 | 
			
		||||
@ -7,14 +7,14 @@
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
typedef void vy_job_fn(void *param, uint32_t iteration);
 | 
			
		||||
typedef void rt_job_fn(void *param, uint32_t iteration);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    uint32_t iterations;
 | 
			
		||||
    vy_job_fn *fn;
 | 
			
		||||
    rt_job_fn *fn;
 | 
			
		||||
    void *param;
 | 
			
		||||
} vy_job_decl;
 | 
			
		||||
} rt_job_decl;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDispatchJob(const vy_job_decl *decl);
 | 
			
		||||
RT_DLLEXPORT void rtDispatchJob(const rt_job_decl *decl);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,20 @@
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include "file_tab.h"
 | 
			
		||||
 | 
			
		||||
vy_result LoadPackageNames(void) {
 | 
			
		||||
rt_result LoadPackageNames(void) {
 | 
			
		||||
    FILE *f = fopen("data/packages.txt", "r");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while (!feof(f)) {
 | 
			
		||||
        char line[256];
 | 
			
		||||
        fscanf(f, "%255s\n", line);
 | 
			
		||||
        line[255] = '\0';
 | 
			
		||||
        vyAddFile(line);
 | 
			
		||||
        rtAddFile(line);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fclose(f);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#ifndef VY_PACKAGES_H
 | 
			
		||||
#define VY_PACKAGES_H
 | 
			
		||||
#ifndef RT_PACKAGES_H
 | 
			
		||||
#define RT_PACKAGES_H
 | 
			
		||||
 | 
			
		||||
#ifdef VY_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
#ifdef RT_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include "xxhash/xxhash.h"
 | 
			
		||||
@ -10,7 +10,7 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    XXH64_canonical_t checksum;
 | 
			
		||||
    uint32_t decompressed_size;
 | 
			
		||||
} vy_package_asset_header;
 | 
			
		||||
} rt_package_asset_header;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_GFX_BACKEND_H
 | 
			
		||||
#define VY_GFX_BACKEND_H
 | 
			
		||||
#ifndef RT_GFX_BACKEND_H
 | 
			
		||||
#define RT_GFX_BACKEND_H
 | 
			
		||||
 | 
			
		||||
/* Backend functions and types. */
 | 
			
		||||
 | 
			
		||||
@ -12,52 +12,52 @@
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
struct HINSTANCE__;
 | 
			
		||||
struct HWND__;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
struct _XDisplay;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct vy_renderer_init_info_s {
 | 
			
		||||
struct rt_renderer_init_info_s {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    struct HINSTANCE__ *hInstance;
 | 
			
		||||
    struct HWND__ *hWnd;
 | 
			
		||||
#elif defined(VY_USE_XLIB)
 | 
			
		||||
#elif defined(RT_USE_XLIB)
 | 
			
		||||
    struct _XDisplay *display;
 | 
			
		||||
    unsigned long window;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid vertex_shader;
 | 
			
		||||
    vy_uid fragment_shader;
 | 
			
		||||
    vy_uid compute_shader;
 | 
			
		||||
    rt_uid vertex_shader;
 | 
			
		||||
    rt_uid fragment_shader;
 | 
			
		||||
    rt_uid compute_shader;
 | 
			
		||||
 | 
			
		||||
    vy_relptr texture_bindings;
 | 
			
		||||
    vy_relptr uniform_bindings;
 | 
			
		||||
    vy_relptr storage_bindings;
 | 
			
		||||
    rt_relptr texture_bindings;
 | 
			
		||||
    rt_relptr uniform_bindings;
 | 
			
		||||
    rt_relptr storage_bindings;
 | 
			
		||||
 | 
			
		||||
    uint16_t texture_binding_count;
 | 
			
		||||
    uint16_t uniform_binding_count;
 | 
			
		||||
    uint16_t storage_binding_count;
 | 
			
		||||
} vy_pipeline_info;
 | 
			
		||||
} rt_pipeline_info;
 | 
			
		||||
 | 
			
		||||
typedef void vy_register_renderer_cvars_fn(void);
 | 
			
		||||
typedef vy_result vy_init_renderer_fn(const vy_renderer_init_info *info);
 | 
			
		||||
typedef void vy_shutdown_renderer_fn(void);
 | 
			
		||||
typedef vy_pipeline_handle vy_compile_pipeline_fn(const vy_pipeline_info *info);
 | 
			
		||||
typedef void vy_destroy_pipeline_fn(vy_pipeline_handle handle);
 | 
			
		||||
typedef void rt_register_renderer_cvars_fn(void);
 | 
			
		||||
typedef rt_result rt_init_renderer_fn(const rt_renderer_init_info *info);
 | 
			
		||||
typedef void rt_shutdown_renderer_fn(void);
 | 
			
		||||
typedef rt_pipeline_handle rt_compile_pipeline_fn(const rt_pipeline_info *info);
 | 
			
		||||
typedef void rt_destroy_pipeline_fn(rt_pipeline_handle handle);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_register_renderer_cvars_fn *RegisterCVars;
 | 
			
		||||
    vy_init_renderer_fn *Init;
 | 
			
		||||
    vy_shutdown_renderer_fn *Shutdown;
 | 
			
		||||
    vy_compile_pipeline_fn *CompilePipeline;
 | 
			
		||||
    vy_destroy_pipeline_fn *DestroyPipeline;
 | 
			
		||||
} vy_renderer_api;
 | 
			
		||||
    rt_register_renderer_cvars_fn *RegisterCVars;
 | 
			
		||||
    rt_init_renderer_fn *Init;
 | 
			
		||||
    rt_shutdown_renderer_fn *Shutdown;
 | 
			
		||||
    rt_compile_pipeline_fn *CompilePipeline;
 | 
			
		||||
    rt_destroy_pipeline_fn *DestroyPipeline;
 | 
			
		||||
} rt_renderer_api;
 | 
			
		||||
 | 
			
		||||
#define VY_RENDERER_API_FN(name) VY_DLLEXPORT vyRen##name
 | 
			
		||||
#define RT_RENDERER_API_FN(name) RT_DLLEXPORT rtRen##name
 | 
			
		||||
 | 
			
		||||
#ifndef VY_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
extern vy_renderer_api g_renderer;
 | 
			
		||||
#ifndef RT_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
extern rt_renderer_api g_renderer;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,47 +1,47 @@
 | 
			
		||||
#ifndef VY_VOYAGE_H
 | 
			
		||||
#define VY_VOYAGE_H
 | 
			
		||||
#ifndef RT_VOYAGE_H
 | 
			
		||||
#define RT_VOYAGE_H
 | 
			
		||||
 | 
			
		||||
/* basic types and macros */
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER) && !defined(VY_STATIC_LIB)
 | 
			
		||||
#define VY_DLLEXPORT __declspec(dllexport)
 | 
			
		||||
#if defined(_MSC_VER) && !defined(RT_STATIC_LIB)
 | 
			
		||||
#define RT_DLLEXPORT __declspec(dllexport)
 | 
			
		||||
#else
 | 
			
		||||
#define VY_DLLEXPORT
 | 
			
		||||
#define RT_DLLEXPORT
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if defined(_MSC_VER)
 | 
			
		||||
#define VY_INLINE __forceinline
 | 
			
		||||
#define RT_INLINE __forceinline
 | 
			
		||||
#elif defined(__GNUC__) || defined(__clang__)
 | 
			
		||||
#define VY_INLINE inline __attribute__((always_inline))
 | 
			
		||||
#define RT_INLINE inline __attribute__((always_inline))
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define VY_UNUSED(x)      ((void)sizeof((x)))
 | 
			
		||||
#define VY_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
 | 
			
		||||
#define RT_UNUSED(x)      ((void)sizeof((x)))
 | 
			
		||||
#define RT_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
 | 
			
		||||
 | 
			
		||||
#define VY_KB(n) ((n)*1024U)
 | 
			
		||||
#define VY_MB(n) ((n)*1024U * 1024U)
 | 
			
		||||
#define VY_GB(n) ((n)*1024U * 1024U * 1024U)
 | 
			
		||||
#define RT_KB(n) ((n)*1024U)
 | 
			
		||||
#define RT_MB(n) ((n)*1024U * 1024U)
 | 
			
		||||
#define RT_GB(n) ((n)*1024U * 1024U * 1024U)
 | 
			
		||||
 | 
			
		||||
typedef unsigned int vy_result;
 | 
			
		||||
typedef unsigned int rt_result;
 | 
			
		||||
 | 
			
		||||
/* Default result codes */
 | 
			
		||||
enum {
 | 
			
		||||
    VY_SUCCESS = 0,
 | 
			
		||||
    VY_OUT_OF_MEMORY = 1,
 | 
			
		||||
    RT_SUCCESS = 0,
 | 
			
		||||
    RT_OUT_OF_MEMORY = 1,
 | 
			
		||||
 | 
			
		||||
    VY_CUSTOM_ERROR_START,
 | 
			
		||||
    RT_CUSTOM_ERROR_START,
 | 
			
		||||
 | 
			
		||||
    VY_UNKNOWN_ERROR = (vy_result)-1,
 | 
			
		||||
    RT_UNKNOWN_ERROR = (rt_result)-1,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *start;
 | 
			
		||||
    unsigned int length;
 | 
			
		||||
} vy_text_span;
 | 
			
		||||
} rt_text_span;
 | 
			
		||||
 | 
			
		||||
/* Returns results like strcmp():
 | 
			
		||||
 * - If the first differing character is smaller in span than in cmp: < 0
 | 
			
		||||
@ -50,33 +50,33 @@ typedef struct {
 | 
			
		||||
 * - If span.length is smaller than strlen(cmp): -1
 | 
			
		||||
 * - If span.length is greater than strlen(cmp): 1
 | 
			
		||||
 */
 | 
			
		||||
VY_DLLEXPORT int vyCompareSpanToString(vy_text_span span, const char *cmp);
 | 
			
		||||
RT_DLLEXPORT int rtCompareSpanToString(rt_text_span span, const char *cmp);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...);
 | 
			
		||||
RT_DLLEXPORT void rtReportError(const char *subsystem, const char *fmt, ...);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...);
 | 
			
		||||
RT_DLLEXPORT void rtLog(const char *subsystem, const char *fmt, ...);
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_INVALID_UNICODE     = VY_CUSTOM_ERROR_START,
 | 
			
		||||
    VY_INSUFFICIENT_BUFFER,
 | 
			
		||||
    RT_INVALID_UNICODE     = RT_CUSTOM_ERROR_START,
 | 
			
		||||
    RT_INSUFFICIENT_BUFFER,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Returns VY_SUCCESS if the string was successfully converted,
 | 
			
		||||
 * VY_INVALID_UNICODE if invalid unicode characters were encountered or 
 | 
			
		||||
 * VY_INSUFFICIENT_BUFFER if the provided output buffer is too small */
 | 
			
		||||
VY_DLLEXPORT vy_result vyUTF8ToWStr(const char *utf8, wchar_t *wstr, size_t len);
 | 
			
		||||
/* Returns RT_SUCCESS if the string was successfully converted,
 | 
			
		||||
 * RT_INVALID_UNICODE if invalid unicode characters were encountered or 
 | 
			
		||||
 * RT_INSUFFICIENT_BUFFER if the provided output buffer is too small */
 | 
			
		||||
RT_DLLEXPORT rt_result rtUTF8ToWStr(const char *utf8, wchar_t *wstr, size_t len);
 | 
			
		||||
 | 
			
		||||
/* Returns VY_SUCCESS if the string was successfully converted,
 | 
			
		||||
 * VY_INVALID_UNICODE if invalid unicode characters were encountered or
 | 
			
		||||
 * VY_INSUFFICIENT_BUFFER if the provided output buffer is too small */
 | 
			
		||||
VY_DLLEXPORT vy_result vyWStrToUTF8(const wchar_t *wstr, char *utf8, size_t len);
 | 
			
		||||
/* Returns RT_SUCCESS if the string was successfully converted,
 | 
			
		||||
 * RT_INVALID_UNICODE if invalid unicode characters were encountered or
 | 
			
		||||
 * RT_INSUFFICIENT_BUFFER if the provided output buffer is too small */
 | 
			
		||||
RT_DLLEXPORT rt_result rtWStrToUTF8(const wchar_t *wstr, char *utf8, size_t len);
 | 
			
		||||
 | 
			
		||||
/* Relative pointer */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    int32_t off;
 | 
			
		||||
} vy_relptr;
 | 
			
		||||
} rt_relptr;
 | 
			
		||||
 | 
			
		||||
static VY_INLINE void *vyResolveRelptr(vy_relptr *ptr) {
 | 
			
		||||
static RT_INLINE void *rtResolveRelptr(rt_relptr *ptr) {
 | 
			
		||||
    if (ptr->off != 0) {
 | 
			
		||||
        char *p = (char *)ptr;
 | 
			
		||||
        return (void *)(p + (ptrdiff_t)ptr->off);
 | 
			
		||||
@ -85,7 +85,7 @@ static VY_INLINE void *vyResolveRelptr(vy_relptr *ptr) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static VY_INLINE void vySetRelptr(vy_relptr *ptr, void *target) {
 | 
			
		||||
static RT_INLINE void rtSetRelptr(rt_relptr *ptr, void *target) {
 | 
			
		||||
    if (target) {
 | 
			
		||||
        char *p = (char *)ptr, *t = (char *)target;
 | 
			
		||||
        ptrdiff_t d = t - p;
 | 
			
		||||
@ -98,7 +98,7 @@ static VY_INLINE void vySetRelptr(vy_relptr *ptr, void *target) {
 | 
			
		||||
/* Bitfiddling functions */
 | 
			
		||||
 | 
			
		||||
/* Portable solution, On x64 using clzl is probably faster. */
 | 
			
		||||
static VY_INLINE uint32_t vyNextPowerOfTwo32(uint32_t v) {
 | 
			
		||||
static RT_INLINE uint32_t rtNextPowerOfTwo32(uint32_t v) {
 | 
			
		||||
    v--;
 | 
			
		||||
    v |= v >> 1;
 | 
			
		||||
    v |= v >> 2;
 | 
			
		||||
@ -112,8 +112,8 @@ static VY_INLINE uint32_t vyNextPowerOfTwo32(uint32_t v) {
 | 
			
		||||
 | 
			
		||||
/* Runtime init. Initializes basic systems.
 | 
			
		||||
 * You need to call this, even if you build a CLI only app. */
 | 
			
		||||
VY_DLLEXPORT vy_result vyInitRuntime(void);
 | 
			
		||||
RT_DLLEXPORT rt_result rtInitRuntime(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownRuntime(void);
 | 
			
		||||
RT_DLLEXPORT void rtShutdownRuntime(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT int vyCompareSpanToString(vy_text_span span, const char *cmp) {
 | 
			
		||||
RT_DLLEXPORT int rtCompareSpanToString(rt_text_span span, const char *cmp) {
 | 
			
		||||
    size_t cmp_len = strlen(cmp);
 | 
			
		||||
    if (cmp_len != (size_t)span.length)
 | 
			
		||||
        return (span.length < cmp_len) ? -1 : 1;
 | 
			
		||||
@ -18,40 +18,40 @@ VY_DLLEXPORT int vyCompareSpanToString(vy_text_span span, const char *cmp) {
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyUTF8ToWStr(const char *utf8, wchar_t *wstr, size_t len) {
 | 
			
		||||
RT_DLLEXPORT rt_result rtUTF8ToWStr(const char *utf8, wchar_t *wstr, size_t len) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    int res = MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, utf8, -1, wstr, (int)len);
 | 
			
		||||
    if (res > 0) {
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    } else {
 | 
			
		||||
        DWORD err = GetLastError();
 | 
			
		||||
        if (err == ERROR_INSUFFICIENT_BUFFER)
 | 
			
		||||
            return VY_INSUFFICIENT_BUFFER;
 | 
			
		||||
            return RT_INSUFFICIENT_BUFFER;
 | 
			
		||||
        else if (err == ERROR_NO_UNICODE_TRANSLATION)
 | 
			
		||||
            return VY_INVALID_UNICODE;
 | 
			
		||||
            return RT_INVALID_UNICODE;
 | 
			
		||||
        else {
 | 
			
		||||
            vyReportError("CORE", "Unexpected error in vyUTF8ToWStr(): %u", err);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            rtReportError("CORE", "Unexpected error in rtUTF8ToWStr(): %u", err);
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyWStrToUTF8(const wchar_t *wstr, char *utf8, size_t len) {
 | 
			
		||||
RT_DLLEXPORT rt_result rtWStrToUTF8(const wchar_t *wstr, char *utf8, size_t len) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    int res = WideCharToMultiByte(CP_UTF8, WC_COMPOSITECHECK, wstr, -1, utf8, (int)len, NULL, NULL);
 | 
			
		||||
    if (res > 0) {
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    } else {
 | 
			
		||||
        DWORD err = GetLastError();
 | 
			
		||||
        if (err == ERROR_INSUFFICIENT_BUFFER)
 | 
			
		||||
            return VY_INSUFFICIENT_BUFFER;
 | 
			
		||||
            return RT_INSUFFICIENT_BUFFER;
 | 
			
		||||
        else if (err == ERROR_NO_UNICODE_TRANSLATION)
 | 
			
		||||
            return VY_INVALID_UNICODE;
 | 
			
		||||
            return RT_INVALID_UNICODE;
 | 
			
		||||
        else {
 | 
			
		||||
            vyReportError("CORE", "Unexpected error in vyWStrToUTF8(): %u", err);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            rtReportError("CORE", "Unexpected error in rtWStrToUTF8(): %u", err);
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_THREADING_H
 | 
			
		||||
#define VY_THREADING_H
 | 
			
		||||
#ifndef RT_THREADING_H
 | 
			
		||||
#define RT_THREADING_H
 | 
			
		||||
 | 
			
		||||
/* platform independent threading */
 | 
			
		||||
 | 
			
		||||
@ -9,70 +9,70 @@
 | 
			
		||||
 | 
			
		||||
/* Mutexes */
 | 
			
		||||
 | 
			
		||||
typedef struct vy_mutex_s vy_mutex;
 | 
			
		||||
typedef struct rt_mutex_s rt_mutex;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void);
 | 
			
		||||
RT_DLLEXPORT rt_mutex *rtCreateMutex(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex);
 | 
			
		||||
RT_DLLEXPORT void rtDestroyMutex(rt_mutex *mutex);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex);
 | 
			
		||||
RT_DLLEXPORT bool rtLockMutex(rt_mutex *mutex);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex);
 | 
			
		||||
RT_DLLEXPORT bool rtUnlockMutex(rt_mutex *mutex);
 | 
			
		||||
 | 
			
		||||
/* Condition variables */
 | 
			
		||||
 | 
			
		||||
typedef struct vy_condition_var_s vy_condition_var;
 | 
			
		||||
typedef struct rt_condition_var_s rt_condition_var;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void);
 | 
			
		||||
RT_DLLEXPORT rt_condition_var *rtCreateConditionVar(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var);
 | 
			
		||||
RT_DLLEXPORT void rtDestroyConditionVar(rt_condition_var *var);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var);
 | 
			
		||||
RT_DLLEXPORT void rtLockConditionVar(rt_condition_var *var);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal);
 | 
			
		||||
RT_DLLEXPORT void rtUnlockConditionVar(rt_condition_var *var, bool signal);
 | 
			
		||||
 | 
			
		||||
/* The condition variable must be locked by the thread! */
 | 
			
		||||
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var);
 | 
			
		||||
RT_DLLEXPORT void rtWaitOnConditionVar(rt_condition_var *var);
 | 
			
		||||
 | 
			
		||||
/* Read-Write Lock */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    volatile int reader_count;
 | 
			
		||||
    vy_condition_var *cond;
 | 
			
		||||
} vy_rwlock;
 | 
			
		||||
    rt_condition_var *cond;
 | 
			
		||||
} rt_rwlock;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    bool ok;
 | 
			
		||||
    vy_rwlock lock;
 | 
			
		||||
} vy_create_rwlock_result;
 | 
			
		||||
    rt_rwlock lock;
 | 
			
		||||
} rt_create_rwlock_result;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_create_rwlock_result vyCreateRWLock(void);
 | 
			
		||||
RT_DLLEXPORT rt_create_rwlock_result rtCreateRWLock(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyRWLock(vy_rwlock *lock);
 | 
			
		||||
RT_DLLEXPORT void rtDestroyRWLock(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockRead(vy_rwlock *lock);
 | 
			
		||||
RT_DLLEXPORT void rtLockRead(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockRead(vy_rwlock *lock);
 | 
			
		||||
RT_DLLEXPORT void rtUnlockRead(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockWrite(vy_rwlock *lock);
 | 
			
		||||
RT_DLLEXPORT void rtLockWrite(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockWrite(vy_rwlock *lock);
 | 
			
		||||
RT_DLLEXPORT void rtUnlockWrite(rt_rwlock *lock);
 | 
			
		||||
 | 
			
		||||
/* Threads */
 | 
			
		||||
 | 
			
		||||
typedef struct vy_thread_s vy_thread;
 | 
			
		||||
typedef struct rt_thread_s rt_thread;
 | 
			
		||||
 | 
			
		||||
typedef void vy_thread_entry_fn(void *param);
 | 
			
		||||
typedef void rt_thread_entry_fn(void *param);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name);
 | 
			
		||||
RT_DLLEXPORT rt_thread *rtSpawnThread(rt_thread_entry_fn *entry, void *param, const char *name);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread);
 | 
			
		||||
RT_DLLEXPORT void rtJoinThread(rt_thread *thread);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void);
 | 
			
		||||
RT_DLLEXPORT unsigned int rtGetCPUCoreCount(void);
 | 
			
		||||
 | 
			
		||||
typedef uint32_t vy_thread_id;
 | 
			
		||||
typedef uint32_t rt_thread_id;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread_id vyGetCurrentThreadId(void);
 | 
			
		||||
RT_DLLEXPORT rt_thread_id rtGetCurrentThreadId(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyIsMainThread(void);
 | 
			
		||||
RT_DLLEXPORT bool rtIsMainThread(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -4,46 +4,46 @@
 | 
			
		||||
#ifdef __linux__
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
struct vy_condition_var_s {
 | 
			
		||||
struct rt_condition_var_s {
 | 
			
		||||
    pthread_mutex_t mutex;
 | 
			
		||||
    pthread_cond_t cond;
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_CONDS 1024
 | 
			
		||||
vy_condition_var _conds[MAX_CONDS];
 | 
			
		||||
rt_condition_var _conds[MAX_CONDS];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
static pthread_mutex_t _guard    = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
 | 
			
		||||
RT_DLLEXPORT rt_condition_var *rtCreateConditionVar(void) {
 | 
			
		||||
    pthread_mutex_lock(&_guard);
 | 
			
		||||
    if (_first_reusable < MAX_CONDS) {
 | 
			
		||||
        vy_condition_var *cond = &_conds[_first_reusable];
 | 
			
		||||
        rt_condition_var *cond = &_conds[_first_reusable];
 | 
			
		||||
        _first_reusable        = cond->next_reusable;
 | 
			
		||||
        pthread_mutex_unlock(&_guard);
 | 
			
		||||
        return cond;
 | 
			
		||||
    } else if (_next < MAX_CONDS) {
 | 
			
		||||
        vy_condition_var *cond = &_conds[_next];
 | 
			
		||||
        rt_condition_var *cond = &_conds[_next];
 | 
			
		||||
        if (pthread_mutex_init(&cond->mutex, NULL) != 0) {
 | 
			
		||||
            vyLog("core", "Condition variable creation failed");
 | 
			
		||||
            rtLog("core", "Condition variable creation failed");
 | 
			
		||||
            pthread_mutex_unlock(&_guard);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if (pthread_cond_init(&cond->cond, NULL) != 0) {
 | 
			
		||||
            vyLog("core", "Condition variable creation failed");
 | 
			
		||||
            rtLog("core", "Condition variable creation failed");
 | 
			
		||||
        }
 | 
			
		||||
        cond->next_reusable = MAX_CONDS;
 | 
			
		||||
        ++_next;
 | 
			
		||||
        pthread_mutex_unlock(&_guard);
 | 
			
		||||
        return cond;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("core", "Ran out of condition variable objects");
 | 
			
		||||
    rtReportError("core", "Ran out of condition variable objects");
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtDestroyConditionVar(rt_condition_var *var) {
 | 
			
		||||
    ptrdiff_t index = var - &_conds[0];
 | 
			
		||||
    pthread_mutex_lock(&_guard);
 | 
			
		||||
    var->next_reusable = _first_reusable;
 | 
			
		||||
@ -51,17 +51,17 @@ VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtLockConditionVar(rt_condition_var *var) {
 | 
			
		||||
    pthread_mutex_lock(&var->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal) {
 | 
			
		||||
RT_DLLEXPORT void rtUnlockConditionVar(rt_condition_var *var, bool signal) {
 | 
			
		||||
    if (signal)
 | 
			
		||||
        pthread_cond_signal(&var->cond);
 | 
			
		||||
    pthread_mutex_unlock(&var->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtWaitOnConditionVar(rt_condition_var *var) {
 | 
			
		||||
    pthread_cond_wait(&var->cond, &var->mutex);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -69,47 +69,47 @@ VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
 | 
			
		||||
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
struct vy_condition_var_s {
 | 
			
		||||
struct rt_condition_var_s {
 | 
			
		||||
    CRITICAL_SECTION critical_section;
 | 
			
		||||
    CONDITION_VARIABLE cond;
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_CONDS 1024
 | 
			
		||||
vy_condition_var _conds[MAX_CONDS];
 | 
			
		||||
rt_condition_var _conds[MAX_CONDS];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
static HANDLE _guard;
 | 
			
		||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
			
		||||
 | 
			
		||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
			
		||||
    VY_UNUSED(initOnce);
 | 
			
		||||
    VY_UNUSED(parameter);
 | 
			
		||||
    VY_UNUSED(context);
 | 
			
		||||
    RT_UNUSED(initOnce);
 | 
			
		||||
    RT_UNUSED(parameter);
 | 
			
		||||
    RT_UNUSED(context);
 | 
			
		||||
 | 
			
		||||
    _guard = CreateMutexW(NULL, FALSE, NULL);
 | 
			
		||||
    return _guard != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
 | 
			
		||||
RT_DLLEXPORT rt_condition_var *rtCreateConditionVar(void) {
 | 
			
		||||
    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
			
		||||
        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        rtReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (WaitForSingleObjectEx(_guard, INFINITE, TRUE) != WAIT_OBJECT_0) {
 | 
			
		||||
        vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        rtLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (_first_reusable < MAX_CONDS) {
 | 
			
		||||
        vy_condition_var *cond = &_conds[_first_reusable];
 | 
			
		||||
        rt_condition_var *cond = &_conds[_first_reusable];
 | 
			
		||||
        _first_reusable        = cond->next_reusable;
 | 
			
		||||
        ReleaseMutex(_guard);
 | 
			
		||||
        return cond;
 | 
			
		||||
    } else if (_next < MAX_CONDS) {
 | 
			
		||||
        vy_condition_var *cond = &_conds[_next];
 | 
			
		||||
        rt_condition_var *cond = &_conds[_next];
 | 
			
		||||
        if (!InitializeCriticalSectionAndSpinCount(&cond->critical_section, 4000)) {
 | 
			
		||||
            vyLog("core", "Condition variable creation failed");
 | 
			
		||||
            rtLog("core", "Condition variable creation failed");
 | 
			
		||||
            ReleaseMutex(_guard);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
@ -119,15 +119,15 @@ VY_DLLEXPORT vy_condition_var *vyCreateConditionVar(void) {
 | 
			
		||||
        ReleaseMutex(_guard);
 | 
			
		||||
        return cond;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("core", "Ran out of condition variable objects");
 | 
			
		||||
    rtReportError("core", "Ran out of condition variable objects");
 | 
			
		||||
    ReleaseMutex(_guard);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtDestroyConditionVar(rt_condition_var *var) {
 | 
			
		||||
    ptrdiff_t index = var - &_conds[0];
 | 
			
		||||
    if (WaitForSingleObjectEx(_guard, INFINITE, TRUE) != WAIT_OBJECT_0) {
 | 
			
		||||
        vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        rtLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    var->next_reusable = _first_reusable;
 | 
			
		||||
@ -135,17 +135,17 @@ VY_DLLEXPORT void vyDestroyConditionVar(vy_condition_var *var) {
 | 
			
		||||
    ReleaseMutex(_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtLockConditionVar(rt_condition_var *var) {
 | 
			
		||||
    EnterCriticalSection(&var->critical_section);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockConditionVar(vy_condition_var *var, bool signal) {
 | 
			
		||||
RT_DLLEXPORT void rtUnlockConditionVar(rt_condition_var *var, bool signal) {
 | 
			
		||||
    LeaveCriticalSection(&var->critical_section);
 | 
			
		||||
    if (signal)
 | 
			
		||||
        WakeAllConditionVariable(&var->cond);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
 | 
			
		||||
RT_DLLEXPORT void rtWaitOnConditionVar(rt_condition_var *var) {
 | 
			
		||||
    SleepConditionVariableCS(&var->cond, &var->critical_section, INFINITE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -5,48 +5,48 @@
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
 | 
			
		||||
struct vy_mutex_s {
 | 
			
		||||
struct rt_mutex_s {
 | 
			
		||||
    HANDLE handle;
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
    DWORD owner;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_MUTEX 1024
 | 
			
		||||
static vy_mutex _mutex[MAX_MUTEX];
 | 
			
		||||
static rt_mutex _mutex[MAX_MUTEX];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
static HANDLE _guard;
 | 
			
		||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
			
		||||
 | 
			
		||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
			
		||||
    VY_UNUSED(initOnce);
 | 
			
		||||
    VY_UNUSED(parameter);
 | 
			
		||||
    VY_UNUSED(context);
 | 
			
		||||
    RT_UNUSED(initOnce);
 | 
			
		||||
    RT_UNUSED(parameter);
 | 
			
		||||
    RT_UNUSED(context);
 | 
			
		||||
 | 
			
		||||
    _guard = CreateMutexW(NULL, FALSE, NULL);
 | 
			
		||||
    return _guard != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
			
		||||
RT_DLLEXPORT rt_mutex *rtCreateMutex(void) {
 | 
			
		||||
    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
			
		||||
        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        rtReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (WaitForSingleObjectEx(_guard, INFINITE, TRUE) != WAIT_OBJECT_0) {
 | 
			
		||||
        vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        rtLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (_first_reusable < MAX_MUTEX) {
 | 
			
		||||
        vy_mutex *mtx   = &_mutex[_first_reusable];
 | 
			
		||||
        rt_mutex *mtx   = &_mutex[_first_reusable];
 | 
			
		||||
        _first_reusable = mtx->next_reusable;
 | 
			
		||||
        mtx->owner      = 0;
 | 
			
		||||
        return mtx;
 | 
			
		||||
    } else if (_next < MAX_MUTEX) {
 | 
			
		||||
        vy_mutex *mtx = &_mutex[_next];
 | 
			
		||||
        rt_mutex *mtx = &_mutex[_next];
 | 
			
		||||
        mtx->handle   = CreateMutexW(NULL, FALSE, NULL);
 | 
			
		||||
        if (!mtx->handle) {
 | 
			
		||||
            vyLog("core", "Mutex creation failed: %u", GetLastError());
 | 
			
		||||
            rtLog("core", "Mutex creation failed: %u", GetLastError());
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
        mtx->next_reusable = MAX_MUTEX;
 | 
			
		||||
@ -54,17 +54,17 @@ VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
			
		||||
        ++_next;
 | 
			
		||||
        return mtx;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("core", "Ran out of mutex objects");
 | 
			
		||||
    rtReportError("core", "Ran out of mutex objects");
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT void rtDestroyMutex(rt_mutex *mutex) {
 | 
			
		||||
    ptrdiff_t index      = mutex - &_mutex[0];
 | 
			
		||||
    mutex->next_reusable = _first_reusable;
 | 
			
		||||
    _first_reusable      = index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT bool rtLockMutex(rt_mutex *mutex) {
 | 
			
		||||
    DWORD caller = GetCurrentThreadId();
 | 
			
		||||
    DWORD result;
 | 
			
		||||
    do {
 | 
			
		||||
@ -72,7 +72,7 @@ VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
			
		||||
        if (result == WAIT_OBJECT_0) {
 | 
			
		||||
            mutex->owner = caller;
 | 
			
		||||
        } else if (result != WAIT_IO_COMPLETION) {
 | 
			
		||||
            vyLog("core",
 | 
			
		||||
            rtLog("core",
 | 
			
		||||
                  "WaitForSingleObjectEx returned %x (GetLastError(): %u)",
 | 
			
		||||
                  result,
 | 
			
		||||
                  (result == WAIT_FAILED) ? GetLastError() : 0);
 | 
			
		||||
@ -81,10 +81,10 @@ VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
			
		||||
    return result == WAIT_OBJECT_0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT bool rtUnlockMutex(rt_mutex *mutex) {
 | 
			
		||||
    DWORD caller = GetCurrentThreadId();
 | 
			
		||||
    if (caller != mutex->owner) {
 | 
			
		||||
        vyReportError("core", "Tried to unlock a mutex held by another thread.");
 | 
			
		||||
        rtReportError("core", "Tried to unlock a mutex held by another thread.");
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    mutex->owner = 0;
 | 
			
		||||
@ -97,28 +97,28 @@ VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
struct vy_mutex_s {
 | 
			
		||||
struct rt_mutex_s {
 | 
			
		||||
    pthread_mutex_t handle;
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_MUTEX 1024
 | 
			
		||||
static vy_mutex _mutex[MAX_MUTEX];
 | 
			
		||||
static rt_mutex _mutex[MAX_MUTEX];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
static pthread_mutex_t _guard    = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
			
		||||
RT_DLLEXPORT rt_mutex *rtCreateMutex(void) {
 | 
			
		||||
    pthread_mutex_lock(&_guard);
 | 
			
		||||
    if (_first_reusable < MAX_MUTEX) {
 | 
			
		||||
        vy_mutex *mtx   = &_mutex[_first_reusable];
 | 
			
		||||
        rt_mutex *mtx   = &_mutex[_first_reusable];
 | 
			
		||||
        _first_reusable = mtx->next_reusable;
 | 
			
		||||
        pthread_mutex_unlock(&_guard);
 | 
			
		||||
        return mtx;
 | 
			
		||||
    } else if (_next < MAX_MUTEX) {
 | 
			
		||||
        vy_mutex *mtx = &_mutex[_next];
 | 
			
		||||
        rt_mutex *mtx = &_mutex[_next];
 | 
			
		||||
        if (pthread_mutex_init(&mtx->handle, NULL) != 0) {
 | 
			
		||||
            vyLog("core", "Mutex creation failed");
 | 
			
		||||
            rtLog("core", "Mutex creation failed");
 | 
			
		||||
            pthread_mutex_unlock(&_guard);
 | 
			
		||||
            return NULL;
 | 
			
		||||
        }
 | 
			
		||||
@ -127,12 +127,12 @@ VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
			
		||||
        pthread_mutex_unlock(&_guard);
 | 
			
		||||
        return mtx;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("core", "Ran out of mutex objects");
 | 
			
		||||
    rtReportError("core", "Ran out of mutex objects");
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT void rtDestroyMutex(rt_mutex *mutex) {
 | 
			
		||||
    ptrdiff_t index = mutex - &_mutex[0];
 | 
			
		||||
    pthread_mutex_lock(&_guard);
 | 
			
		||||
    mutex->next_reusable = _first_reusable;
 | 
			
		||||
@ -140,11 +140,11 @@ VY_DLLEXPORT void vyDestroyMutex(vy_mutex *mutex) {
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyLockMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT bool rtLockMutex(rt_mutex *mutex) {
 | 
			
		||||
    return pthread_mutex_lock(&mutex->handle) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
			
		||||
RT_DLLEXPORT bool rtUnlockMutex(rt_mutex *mutex) {
 | 
			
		||||
    return pthread_mutex_unlock(&mutex->handle) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,40 +4,40 @@
 | 
			
		||||
 | 
			
		||||
/* Based on: https://eli.thegreenplace.net/2019/implementing-reader-writer-locks/ */
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_create_rwlock_result vyCreateRWLock(void) {
 | 
			
		||||
    vy_create_rwlock_result res;
 | 
			
		||||
RT_DLLEXPORT rt_create_rwlock_result rtCreateRWLock(void) {
 | 
			
		||||
    rt_create_rwlock_result res;
 | 
			
		||||
    res.lock.reader_count = 0;
 | 
			
		||||
    res.lock.cond         = vyCreateConditionVar();
 | 
			
		||||
    res.lock.cond         = rtCreateConditionVar();
 | 
			
		||||
    res.ok                = res.lock.cond != NULL;
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyDestroyRWLock(vy_rwlock *lock) {
 | 
			
		||||
    vyDestroyConditionVar(lock->cond);
 | 
			
		||||
RT_DLLEXPORT void rtDestroyRWLock(rt_rwlock *lock) {
 | 
			
		||||
    rtDestroyConditionVar(lock->cond);
 | 
			
		||||
    lock->cond         = NULL;
 | 
			
		||||
    lock->reader_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockRead(vy_rwlock *lock) {
 | 
			
		||||
    vyLockConditionVar(lock->cond);
 | 
			
		||||
RT_DLLEXPORT void rtLockRead(rt_rwlock *lock) {
 | 
			
		||||
    rtLockConditionVar(lock->cond);
 | 
			
		||||
    ++lock->reader_count;
 | 
			
		||||
    vyUnlockConditionVar(lock->cond, false);
 | 
			
		||||
    rtUnlockConditionVar(lock->cond, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockRead(vy_rwlock *lock) {
 | 
			
		||||
    vyLockConditionVar(lock->cond);
 | 
			
		||||
RT_DLLEXPORT void rtUnlockRead(rt_rwlock *lock) {
 | 
			
		||||
    rtLockConditionVar(lock->cond);
 | 
			
		||||
    assert(lock->reader_count > 0);
 | 
			
		||||
    --lock->reader_count;
 | 
			
		||||
    bool signal = lock->reader_count == 0;
 | 
			
		||||
    vyUnlockConditionVar(lock->cond, signal);
 | 
			
		||||
    rtUnlockConditionVar(lock->cond, signal);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyLockWrite(vy_rwlock *lock) {
 | 
			
		||||
    vyLockConditionVar(lock->cond);
 | 
			
		||||
RT_DLLEXPORT void rtLockWrite(rt_rwlock *lock) {
 | 
			
		||||
    rtLockConditionVar(lock->cond);
 | 
			
		||||
    while (lock->reader_count > 0)
 | 
			
		||||
        vyWaitOnConditionVar(lock->cond);
 | 
			
		||||
        rtWaitOnConditionVar(lock->cond);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyUnlockWrite(vy_rwlock *lock) {
 | 
			
		||||
    vyUnlockConditionVar(lock->cond, true);
 | 
			
		||||
RT_DLLEXPORT void rtUnlockWrite(rt_rwlock *lock) {
 | 
			
		||||
    rtUnlockConditionVar(lock->cond, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -6,59 +6,59 @@
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
 | 
			
		||||
struct vy_thread_s {
 | 
			
		||||
struct rt_thread_s {
 | 
			
		||||
    HANDLE handle;
 | 
			
		||||
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
 | 
			
		||||
    vy_thread_entry_fn *entry;
 | 
			
		||||
    rt_thread_entry_fn *entry;
 | 
			
		||||
    void *param;
 | 
			
		||||
 | 
			
		||||
    bool needs_join;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_THREADS 256
 | 
			
		||||
static vy_thread _threads[MAX_THREADS];
 | 
			
		||||
static rt_thread _threads[MAX_THREADS];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
 | 
			
		||||
static HANDLE _guard;
 | 
			
		||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
			
		||||
 | 
			
		||||
static vy_thread_id _main_thread_id;
 | 
			
		||||
static rt_thread_id _main_thread_id;
 | 
			
		||||
 | 
			
		||||
/* Called by the runtime during setup */
 | 
			
		||||
extern void SetMainThreadId(void) {
 | 
			
		||||
    _main_thread_id = (vy_thread_id)GetCurrentThreadId();
 | 
			
		||||
    _main_thread_id = (rt_thread_id)GetCurrentThreadId();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
			
		||||
    VY_UNUSED(initOnce);
 | 
			
		||||
    VY_UNUSED(parameter);
 | 
			
		||||
    VY_UNUSED(context);
 | 
			
		||||
    RT_UNUSED(initOnce);
 | 
			
		||||
    RT_UNUSED(parameter);
 | 
			
		||||
    RT_UNUSED(context);
 | 
			
		||||
 | 
			
		||||
    _guard = CreateMutexW(NULL, FALSE, NULL);
 | 
			
		||||
    return _guard != NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DWORD WINAPI win32ThreadWrapper(LPVOID arg) {
 | 
			
		||||
    vy_thread *user_thread  = arg;
 | 
			
		||||
    rt_thread *user_thread  = arg;
 | 
			
		||||
    user_thread->needs_join = false;
 | 
			
		||||
    user_thread->entry(user_thread->param);
 | 
			
		||||
    user_thread->needs_join = true;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name) {
 | 
			
		||||
RT_DLLEXPORT rt_thread *rtSpawnThread(rt_thread_entry_fn *entry, void *param, const char *name) {
 | 
			
		||||
 | 
			
		||||
    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
			
		||||
        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        rtReportError("core", "Failed to initialize the guard mutex.");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_thread *thrd = NULL;
 | 
			
		||||
    rt_thread *thrd = NULL;
 | 
			
		||||
    if (WaitForSingleObject(_guard, INFINITE) != WAIT_OBJECT_0) {
 | 
			
		||||
        vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        rtLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (_first_reusable < MAX_THREADS) {
 | 
			
		||||
@ -79,29 +79,29 @@ VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, co
 | 
			
		||||
        thrd->param  = param;
 | 
			
		||||
        thrd->handle = CreateThread(NULL, 0, win32ThreadWrapper, (LPVOID)thrd, 0, NULL);
 | 
			
		||||
        if (thrd->handle == NULL) {
 | 
			
		||||
            vyLog("core", "Thread creation failed");
 | 
			
		||||
            rtLog("core", "Thread creation failed");
 | 
			
		||||
            thrd = NULL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WCHAR wname[64];
 | 
			
		||||
        if (thrd && name && vyUTF8ToWStr(name, wname, sizeof(wname)) == VY_SUCCESS)
 | 
			
		||||
        if (thrd && name && rtUTF8ToWStr(name, wname, sizeof(wname)) == RT_SUCCESS)
 | 
			
		||||
            SetThreadDescription(thrd->handle, wname);
 | 
			
		||||
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("core", "Ran out of thread objects");
 | 
			
		||||
        rtReportError("core", "Ran out of thread objects");
 | 
			
		||||
    }
 | 
			
		||||
    ReleaseMutex(_guard);
 | 
			
		||||
    return thrd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
			
		||||
RT_DLLEXPORT void rtJoinThread(rt_thread *thread) {
 | 
			
		||||
    WaitForSingleObject(thread->handle, INFINITE);
 | 
			
		||||
    CloseHandle(thread->handle);
 | 
			
		||||
    thread->needs_join = false;
 | 
			
		||||
    ptrdiff_t index    = thread - &_threads[0];
 | 
			
		||||
 | 
			
		||||
    if (WaitForSingleObject(_guard, INFINITE) != WAIT_OBJECT_0) {
 | 
			
		||||
        vyLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        rtLog("core", "Failed to lock the guard variable: %u", GetLastError());
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    thread->next_reusable = _first_reusable;
 | 
			
		||||
@ -109,18 +109,18 @@ VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
			
		||||
    ReleaseMutex(_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void) {
 | 
			
		||||
RT_DLLEXPORT unsigned int rtGetCPUCoreCount(void) {
 | 
			
		||||
    SYSTEM_INFO info;
 | 
			
		||||
    GetSystemInfo(&info);
 | 
			
		||||
    return (unsigned int)info.dwNumberOfProcessors;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread_id vyGetCurrentThreadId(void) {
 | 
			
		||||
    return (vy_thread_id)GetCurrentThreadId();
 | 
			
		||||
RT_DLLEXPORT rt_thread_id rtGetCurrentThreadId(void) {
 | 
			
		||||
    return (rt_thread_id)GetCurrentThreadId();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyIsMainThread(void) {
 | 
			
		||||
    return vyGetCurrentThreadId() == _main_thread_id;
 | 
			
		||||
RT_DLLEXPORT bool rtIsMainThread(void) {
 | 
			
		||||
    return rtGetCurrentThreadId() == _main_thread_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
@ -129,33 +129,33 @@ VY_DLLEXPORT bool vyIsMainThread(void) {
 | 
			
		||||
#include <pthread.h>
 | 
			
		||||
#include <unistd.h>
 | 
			
		||||
 | 
			
		||||
struct vy_thread_s {
 | 
			
		||||
struct rt_thread_s {
 | 
			
		||||
    pthread_t handle;
 | 
			
		||||
    ptrdiff_t next_reusable;
 | 
			
		||||
 | 
			
		||||
    vy_thread_entry_fn *entry;
 | 
			
		||||
    rt_thread_entry_fn *entry;
 | 
			
		||||
    void *param;
 | 
			
		||||
 | 
			
		||||
    bool needs_join;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define MAX_THREADS 256
 | 
			
		||||
static vy_thread _threads[MAX_THREADS];
 | 
			
		||||
static rt_thread _threads[MAX_THREADS];
 | 
			
		||||
static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
			
		||||
static ptrdiff_t _next           = 0;
 | 
			
		||||
 | 
			
		||||
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
 | 
			
		||||
static void *linuxThreadWrapper(void *arg) {
 | 
			
		||||
    vy_thread *user_thread  = arg;
 | 
			
		||||
    rt_thread *user_thread  = arg;
 | 
			
		||||
    user_thread->needs_join = false;
 | 
			
		||||
    user_thread->entry(user_thread->param);
 | 
			
		||||
    user_thread->needs_join = true;
 | 
			
		||||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name) {
 | 
			
		||||
    vy_thread *thrd = NULL;
 | 
			
		||||
RT_DLLEXPORT rt_thread *rtSpawnThread(rt_thread_entry_fn *entry, void *param, const char *name) {
 | 
			
		||||
    rt_thread *thrd = NULL;
 | 
			
		||||
    pthread_mutex_lock(&_guard);
 | 
			
		||||
    if (_first_reusable < MAX_THREADS) {
 | 
			
		||||
        thrd            = &_threads[_first_reusable];
 | 
			
		||||
@ -173,19 +173,19 @@ VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, co
 | 
			
		||||
        thrd->entry = entry;
 | 
			
		||||
        thrd->param = param;
 | 
			
		||||
        if (pthread_create(&thrd->handle, NULL, linuxThreadWrapper, thrd) != 0) {
 | 
			
		||||
            vyLog("core", "Thread creation failed");
 | 
			
		||||
            rtLog("core", "Thread creation failed");
 | 
			
		||||
            thrd = NULL;
 | 
			
		||||
        }
 | 
			
		||||
        if (thrd && name)
 | 
			
		||||
            pthread_setname_np(thrd->handle, name);
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("core", "Ran out of thread objects");
 | 
			
		||||
        rtReportError("core", "Ran out of thread objects");
 | 
			
		||||
    }
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
    return thrd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
			
		||||
RT_DLLEXPORT void rtJoinThread(rt_thread *thread) {
 | 
			
		||||
    pthread_join(thread->handle, NULL);
 | 
			
		||||
    thread->needs_join = false;
 | 
			
		||||
    ptrdiff_t index    = thread - &_threads[0];
 | 
			
		||||
@ -195,17 +195,17 @@ VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
			
		||||
    pthread_mutex_unlock(&_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void) {
 | 
			
		||||
RT_DLLEXPORT unsigned int rtGetCPUCoreCount(void) {
 | 
			
		||||
    int n = (int)sysconf(_SC_NPROCESSORS_ONLN);
 | 
			
		||||
    return (n > 0) ? (unsigned int)n : (unsigned int)sysconf(_SC_NPROCESSORS_CONF);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_thread_id vyGetCurrentThreadId(void) {
 | 
			
		||||
    return (vy_thread_id)GetCurrentThreadId();
 | 
			
		||||
RT_DLLEXPORT rt_thread_id rtGetCurrentThreadId(void) {
 | 
			
		||||
    return (rt_thread_id)GetCurrentThreadId();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT bool vyIsMainThread(void) {
 | 
			
		||||
    return vyGetCurrentThreadId() == _main_thread_id;
 | 
			
		||||
RT_DLLEXPORT bool rtIsMainThread(void) {
 | 
			
		||||
    return rtGetCurrentThreadId() == _main_thread_id;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
#define VY_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#include "uidtab.h"
 | 
			
		||||
#include "aio.h"
 | 
			
		||||
 | 
			
		||||
@ -10,25 +10,25 @@
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid *uids;
 | 
			
		||||
    vy_uid_data *data;
 | 
			
		||||
    rt_uid *uids;
 | 
			
		||||
    rt_uid_data *data;
 | 
			
		||||
    uint32_t slots;
 | 
			
		||||
} vy_uidtab;
 | 
			
		||||
} rt_uidtab;
 | 
			
		||||
 | 
			
		||||
static vy_uidtab _tab;
 | 
			
		||||
static rt_uidtab _tab;
 | 
			
		||||
 | 
			
		||||
vy_result LoadUIDTable(void) {
 | 
			
		||||
rt_result LoadUIDTable(void) {
 | 
			
		||||
    /* We use stdio here, because we cannot load any asset in parallel to this.
 | 
			
		||||
     * This is because the uidtab is what tells us which assets exist.
 | 
			
		||||
     */
 | 
			
		||||
    FILE *f = fopen("data/uidtab.bin", "rb");
 | 
			
		||||
    if (!f)
 | 
			
		||||
        return VY_LOAD_FAILED;
 | 
			
		||||
        return RT_LOAD_FAILED;
 | 
			
		||||
 | 
			
		||||
    vy_uidtab_header header;
 | 
			
		||||
    rt_uidtab_header header;
 | 
			
		||||
    if (fread(&header, sizeof(header), 1, f) != 1) {
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        return VY_LOAD_FAILED;
 | 
			
		||||
        return RT_LOAD_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* TODO(Kevin): For some reason, the checksum calculation causes
 | 
			
		||||
@ -36,29 +36,29 @@ vy_result LoadUIDTable(void) {
 | 
			
		||||
    XXH3_state_t *checksum = XXH3_createState();
 | 
			
		||||
    if (!checksum) {
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
 | 
			
		||||
    _tab.slots = vyNextPowerOfTwo32(header.num_entries * 2);
 | 
			
		||||
    void *mem  = malloc((sizeof(vy_uid) + sizeof(vy_uid_data)) * _tab.slots);
 | 
			
		||||
    _tab.slots = rtNextPowerOfTwo32(header.num_entries * 2);
 | 
			
		||||
    void *mem  = malloc((sizeof(rt_uid) + sizeof(rt_uid_data)) * _tab.slots);
 | 
			
		||||
    if (!mem) {
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        _tab.slots = 0;
 | 
			
		||||
        return VY_OUT_OF_MEMORY;
 | 
			
		||||
        return RT_OUT_OF_MEMORY;
 | 
			
		||||
    }
 | 
			
		||||
    _tab.uids = mem;
 | 
			
		||||
    _tab.data = (vy_uid_data *)(_tab.uids + _tab.slots);
 | 
			
		||||
    memset(mem, 0, (sizeof(vy_uid) + sizeof(vy_uid_data)) * _tab.slots);
 | 
			
		||||
    _tab.data = (rt_uid_data *)(_tab.uids + _tab.slots);
 | 
			
		||||
    memset(mem, 0, (sizeof(rt_uid) + sizeof(rt_uid_data)) * _tab.slots);
 | 
			
		||||
 | 
			
		||||
    uint32_t mod = _tab.slots - 1; 
 | 
			
		||||
    for (uint32_t i = 0; i < header.num_entries; ++i) {
 | 
			
		||||
        vy_uidtab_entry entry;
 | 
			
		||||
        rt_uidtab_entry entry;
 | 
			
		||||
        if (fread(&entry, sizeof(entry), 1, f) != 1) {
 | 
			
		||||
            free(mem);
 | 
			
		||||
            _tab.slots = 0;
 | 
			
		||||
            fclose(f);
 | 
			
		||||
            return VY_LOAD_FAILED;
 | 
			
		||||
            return RT_LOAD_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        //XXH3_64bits_update(checksum, &entry, sizeof(entry));
 | 
			
		||||
 | 
			
		||||
@ -66,7 +66,7 @@ vy_result LoadUIDTable(void) {
 | 
			
		||||
        bool inserted = false;
 | 
			
		||||
        for (uint32_t j = 0; j < _tab.slots; ++j) {
 | 
			
		||||
            uint32_t at = (entry.uid + j) & mod;
 | 
			
		||||
            if (_tab.uids[at] == VY_INVALID_UID) {
 | 
			
		||||
            if (_tab.uids[at] == RT_INVALID_UID) {
 | 
			
		||||
                _tab.uids[at] = entry.uid;
 | 
			
		||||
                _tab.data[at].pkg_file = entry.file;
 | 
			
		||||
                _tab.data[at].size     = entry.size;
 | 
			
		||||
@ -77,12 +77,12 @@ vy_result LoadUIDTable(void) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (!inserted) {
 | 
			
		||||
            vyReportError("core",
 | 
			
		||||
            rtReportError("core",
 | 
			
		||||
                          "Failed to insert an entry into the uid table. This should not happen.");
 | 
			
		||||
            fclose(f);
 | 
			
		||||
            free(mem);
 | 
			
		||||
            _tab.slots = 0;
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -94,12 +94,12 @@ vy_result LoadUIDTable(void) {
 | 
			
		||||
    XXH3_freeState(checksum);
 | 
			
		||||
 | 
			
		||||
    if (checksum_hash != file_hash) {
 | 
			
		||||
        vyLog("core",
 | 
			
		||||
        rtLog("core",
 | 
			
		||||
              "WARNING: uidtab.bin checksum does not match calculated checksum of loaded entries.");
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
    
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ReleaseUIDTable(void) {
 | 
			
		||||
@ -107,13 +107,13 @@ void ReleaseUIDTable(void) {
 | 
			
		||||
    _tab.slots = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT const vy_uid_data *vyGetUIDData(vy_uid uid) {
 | 
			
		||||
RT_DLLEXPORT const rt_uid_data *rtGetUIDData(rt_uid uid) {
 | 
			
		||||
    uint32_t mod = _tab.slots - 1;
 | 
			
		||||
    for (uint32_t j = 0; j < _tab.slots; ++j) {
 | 
			
		||||
        uint32_t at = (uid + j) & mod;
 | 
			
		||||
        if (_tab.uids[at] == uid) {
 | 
			
		||||
            return &_tab.data[at];
 | 
			
		||||
        } else if (_tab.uids[at] == VY_INVALID_UID) {
 | 
			
		||||
        } else if (_tab.uids[at] == RT_INVALID_UID) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -1,36 +1,36 @@
 | 
			
		||||
#ifndef VY_UIDTAB_H
 | 
			
		||||
#define VY_UIDTAB_H
 | 
			
		||||
#ifndef RT_UIDTAB_H
 | 
			
		||||
#define RT_UIDTAB_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "file_tab.h"
 | 
			
		||||
#include "assets.h"
 | 
			
		||||
#include "xxhash/xxhash.h"
 | 
			
		||||
 | 
			
		||||
#ifdef VY_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#ifdef RT_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    XXH64_canonical_t checksum;
 | 
			
		||||
    uint32_t num_entries;
 | 
			
		||||
} vy_uidtab_header;
 | 
			
		||||
} rt_uidtab_header;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id file;
 | 
			
		||||
    rt_file_id file;
 | 
			
		||||
    uint64_t offset;
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
    vy_uid uid;
 | 
			
		||||
} vy_uidtab_entry;
 | 
			
		||||
    rt_uid uid;
 | 
			
		||||
} rt_uidtab_entry;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* Data associated with an uid */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id pkg_file;
 | 
			
		||||
    rt_file_id pkg_file;
 | 
			
		||||
    uint64_t offset;
 | 
			
		||||
    uint64_t size;
 | 
			
		||||
} vy_uid_data;
 | 
			
		||||
} rt_uid_data;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT const vy_uid_data *vyGetUIDData(vy_uid uid);
 | 
			
		||||
RT_DLLEXPORT const rt_uid_data *rtGetUIDData(rt_uid uid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -3,38 +3,38 @@
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
/* Check basic relative pointer behaviour */
 | 
			
		||||
static vy_result RelPtrTest(void) {
 | 
			
		||||
    char buf[sizeof(vy_relptr) + sizeof(unsigned int)];
 | 
			
		||||
    vy_relptr *ptr = (vy_relptr *)buf;
 | 
			
		||||
    unsigned int *target = (unsigned int *)&buf[sizeof(vy_relptr)];
 | 
			
		||||
static rt_result RelPtrTest(void) {
 | 
			
		||||
    char buf[sizeof(rt_relptr) + sizeof(unsigned int)];
 | 
			
		||||
    rt_relptr *ptr = (rt_relptr *)buf;
 | 
			
		||||
    unsigned int *target = (unsigned int *)&buf[sizeof(rt_relptr)];
 | 
			
		||||
    *target = 42;
 | 
			
		||||
    vySetRelptr(ptr, target);
 | 
			
		||||
    rtSetRelptr(ptr, target);
 | 
			
		||||
 | 
			
		||||
    void *resolved = vyResolveRelptr(ptr);
 | 
			
		||||
    void *resolved = rtResolveRelptr(ptr);
 | 
			
		||||
    if ((uintptr_t)resolved != (uintptr_t)target)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    if (*(unsigned int *)resolved != *target)
 | 
			
		||||
        return 2;
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result NegRelPtrTest(void) {
 | 
			
		||||
    char buf[sizeof(unsigned int) + sizeof(vy_relptr)];
 | 
			
		||||
static rt_result NegRelPtrTest(void) {
 | 
			
		||||
    char buf[sizeof(unsigned int) + sizeof(rt_relptr)];
 | 
			
		||||
    unsigned int *target = (unsigned int *)buf;
 | 
			
		||||
    vy_relptr *ptr       = (vy_relptr *)&buf[sizeof(unsigned int)];
 | 
			
		||||
    rt_relptr *ptr       = (rt_relptr *)&buf[sizeof(unsigned int)];
 | 
			
		||||
    *target              = 42;
 | 
			
		||||
    vySetRelptr(ptr, target);
 | 
			
		||||
    rtSetRelptr(ptr, target);
 | 
			
		||||
 | 
			
		||||
    void *resolved = vyResolveRelptr(ptr);
 | 
			
		||||
    void *resolved = rtResolveRelptr(ptr);
 | 
			
		||||
    if ((uintptr_t)resolved != (uintptr_t)target)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    if (*(unsigned int *)resolved != *target)
 | 
			
		||||
        return 2;
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Scaffolding 
 | 
			
		||||
@ -42,25 +42,25 @@ static vy_result NegRelPtrTest(void) {
 | 
			
		||||
 * Run all the test cases, output if they passed or failed.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef vy_result vy_test_fnc(void);
 | 
			
		||||
typedef rt_result rt_test_fnc(void);
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *name;
 | 
			
		||||
    vy_test_fnc *fnc;
 | 
			
		||||
    rt_test_fnc *fnc;
 | 
			
		||||
 | 
			
		||||
} vy_test_case;
 | 
			
		||||
} rt_test_case;
 | 
			
		||||
 | 
			
		||||
#define TEST_CASE(fn) { .name = #fn, .fnc = fn, }
 | 
			
		||||
 | 
			
		||||
static vy_test_case _test_cases[] = {TEST_CASE(RelPtrTest), TEST_CASE(NegRelPtrTest)};
 | 
			
		||||
static rt_test_case _test_cases[] = {TEST_CASE(RelPtrTest), TEST_CASE(NegRelPtrTest)};
 | 
			
		||||
 | 
			
		||||
int main() {
 | 
			
		||||
    int out = 0;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < VY_ARRAY_COUNT(_test_cases); ++i) {
 | 
			
		||||
    for (size_t i = 0; i < RT_ARRAY_COUNT(_test_cases); ++i) {
 | 
			
		||||
        printf("[%s] ... ", _test_cases[i].name);
 | 
			
		||||
        vy_result res = _test_cases[i].fnc();
 | 
			
		||||
        if (res == VY_SUCCESS) {
 | 
			
		||||
        rt_result res = _test_cases[i].fnc();
 | 
			
		||||
        if (res == RT_SUCCESS) {
 | 
			
		||||
            printf("OK\n");
 | 
			
		||||
        } 
 | 
			
		||||
        else {
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
#include "packages.h"
 | 
			
		||||
#include "dependency_tracking.h"
 | 
			
		||||
 | 
			
		||||
#define VY_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
			
		||||
#define RT_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
			
		||||
#include "options.h"
 | 
			
		||||
 | 
			
		||||
#include "runtime/aio.h"
 | 
			
		||||
@ -15,24 +15,24 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
 | 
			
		||||
extern vy_result vyProcessPipelineFile(vy_file_id file,
 | 
			
		||||
extern rt_result rtProcessPipelineFile(rt_file_id file,
 | 
			
		||||
                                       void *buffer,
 | 
			
		||||
                                       size_t size,
 | 
			
		||||
                                       uint32_t flags,
 | 
			
		||||
                                       vy_processor_output *output);
 | 
			
		||||
                                       rt_processor_output *output);
 | 
			
		||||
 | 
			
		||||
extern vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
extern rt_result rtProcessShaderFile(rt_file_id file,
 | 
			
		||||
                                     void *buffer,
 | 
			
		||||
                                     size_t size,
 | 
			
		||||
                                     uint32_t flags,
 | 
			
		||||
                                     vy_processor_output *output);
 | 
			
		||||
                                     rt_processor_output *output);
 | 
			
		||||
 | 
			
		||||
extern void vyDiscoverAssets(void);
 | 
			
		||||
extern void rtDiscoverAssets(void);
 | 
			
		||||
 | 
			
		||||
vy_assetc_options g_assetc_options = {
 | 
			
		||||
rt_assetc_options g_assetc_options = {
 | 
			
		||||
    .root_directory   = ".",
 | 
			
		||||
    .optimization     = VY_ASSET_OPTIMIZATION_NONE,
 | 
			
		||||
    .renderer_backend = VY_RENDERER_BACKEND_CODE_VK,
 | 
			
		||||
    .optimization     = RT_ASSET_OPTIMIZATION_NONE,
 | 
			
		||||
    .renderer_backend = RT_RENDERER_BACKEND_CODE_VK,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
@ -44,9 +44,9 @@ static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
 | 
			
		||||
            if (strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--renderer") == 0) {
 | 
			
		||||
                if (strcmp(val, "vk") == 0) {
 | 
			
		||||
                    g_assetc_options.renderer_backend = VY_RENDERER_BACKEND_CODE_VK;
 | 
			
		||||
                    g_assetc_options.renderer_backend = RT_RENDERER_BACKEND_CODE_VK;
 | 
			
		||||
                } else {
 | 
			
		||||
                    vyReportError("ASSETC",
 | 
			
		||||
                    rtReportError("ASSETC",
 | 
			
		||||
                                  "Invalid render backend %s. Valid options are: vk",
 | 
			
		||||
                                  val);
 | 
			
		||||
                    return false;
 | 
			
		||||
@ -54,13 +54,13 @@ static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
                matched = true;
 | 
			
		||||
            } else if (strcmp(argv[i], "-o") == 0 || strcmp(argv[i], "--optimization") == 0) {
 | 
			
		||||
                if (strcmp(val, "none") == 0) {
 | 
			
		||||
                    g_assetc_options.optimization = VY_ASSET_OPTIMIZATION_NONE;
 | 
			
		||||
                    g_assetc_options.optimization = RT_ASSET_OPTIMIZATION_NONE;
 | 
			
		||||
                } else if (strcmp(val, "space") == 0) {
 | 
			
		||||
                    g_assetc_options.optimization = VY_ASSET_OPTIMIZATION_SPACE;
 | 
			
		||||
                    g_assetc_options.optimization = RT_ASSET_OPTIMIZATION_SPACE;
 | 
			
		||||
                } else if (strcmp(val, "performance") == 0) {
 | 
			
		||||
                    g_assetc_options.optimization = VY_ASSET_OPTIMIZATION_PERFORMANCE;
 | 
			
		||||
                    g_assetc_options.optimization = RT_ASSET_OPTIMIZATION_PERFORMANCE;
 | 
			
		||||
                } else {
 | 
			
		||||
                    vyReportError("ASSETC",
 | 
			
		||||
                    rtReportError("ASSETC",
 | 
			
		||||
                                  "Invalid optimization level %s. Valid options are: none, space, "
 | 
			
		||||
                                  "performance",
 | 
			
		||||
                                  val);
 | 
			
		||||
@ -68,7 +68,7 @@ static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
                }
 | 
			
		||||
                matched = true;
 | 
			
		||||
            } else if (argv[i][0] == '-') {
 | 
			
		||||
                vyReportError("ASSETC", "Invalid command line argument %s", argv[i]);
 | 
			
		||||
                rtReportError("ASSETC", "Invalid command line argument %s", argv[i]);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@ -83,7 +83,7 @@ static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
            g_assetc_options.root_directory = argv[i];
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Maybe have secondary directories later? */
 | 
			
		||||
            vyReportError("ASSETC",
 | 
			
		||||
            rtReportError("ASSETC",
 | 
			
		||||
                          "More than one root directory passed as command line "
 | 
			
		||||
                          "argument.");
 | 
			
		||||
            return false;
 | 
			
		||||
@ -93,57 +93,57 @@ static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
    vyInitRuntime();
 | 
			
		||||
    rtInitRuntime();
 | 
			
		||||
 | 
			
		||||
    /* Init assetc */
 | 
			
		||||
    if (!ParseCommandLineArgs(argc, argv)) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    vyInitPackages();
 | 
			
		||||
    rtInitPackages();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    if (vyLoadAssetMeta() != VY_SUCCESS) {
 | 
			
		||||
    if (rtLoadAssetMeta() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (vyInitDependencyTracking() != VY_SUCCESS) {
 | 
			
		||||
    if (rtInitDependencyTracking() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vyAddAssetProcessor(".pipeline", vyProcessPipelineFile) != VY_SUCCESS)
 | 
			
		||||
    if (rtAddAssetProcessor(".pipeline", rtProcessPipelineFile) != RT_SUCCESS)
 | 
			
		||||
        return 1;
 | 
			
		||||
    if (vyAddAssetProcessor(".glsl", vyProcessShaderFile) != VY_SUCCESS)
 | 
			
		||||
    if (rtAddAssetProcessor(".glsl", rtProcessShaderFile) != RT_SUCCESS)
 | 
			
		||||
        return 1;
 | 
			
		||||
 | 
			
		||||
    if (vyStartProcessing() != VY_SUCCESS) {
 | 
			
		||||
    if (rtStartProcessing() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /* Create necessary directories */
 | 
			
		||||
    vySetWorkingDirectory(g_assetc_options.root_directory);
 | 
			
		||||
    vyCreateDirectory("assets");
 | 
			
		||||
    vyCreateDirectory("actemp");
 | 
			
		||||
    vyCreateDirectory("data");
 | 
			
		||||
    rtSetWorkingDirectory(g_assetc_options.root_directory);
 | 
			
		||||
    rtCreateDirectory("assets");
 | 
			
		||||
    rtCreateDirectory("actemp");
 | 
			
		||||
    rtCreateDirectory("data");
 | 
			
		||||
 | 
			
		||||
    /* "Mainloop" */
 | 
			
		||||
    vyDiscoverAssets();
 | 
			
		||||
    rtDiscoverAssets();
 | 
			
		||||
 | 
			
		||||
    vyWaitUntilProcessingIsFinished();
 | 
			
		||||
    vyStopProcessing();
 | 
			
		||||
    rtWaitUntilProcessingIsFinished();
 | 
			
		||||
    rtStopProcessing();
 | 
			
		||||
 | 
			
		||||
    /* Write result */
 | 
			
		||||
    vySaveAssetMeta();
 | 
			
		||||
    if (vySavePackages() != VY_SUCCESS) {
 | 
			
		||||
    rtSaveAssetMeta();
 | 
			
		||||
    if (rtSavePackages() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (vyWriteUIDTab() != VY_SUCCESS) {
 | 
			
		||||
    if (rtWriteUIDTab() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (vySaveAssetDependencies() != VY_SUCCESS) {
 | 
			
		||||
    if (rtSaveAssetDependencies() != RT_SUCCESS) {
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyShutdownRuntime();
 | 
			
		||||
    rtShutdownRuntime();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -12,113 +12,113 @@
 | 
			
		||||
 | 
			
		||||
#define MAP_SIZE 2048
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id fids[MAP_SIZE];
 | 
			
		||||
    vy_uid uids[MAP_SIZE];
 | 
			
		||||
    vy_assetmeta meta[MAP_SIZE];
 | 
			
		||||
    rt_file_id fids[MAP_SIZE];
 | 
			
		||||
    rt_uid uids[MAP_SIZE];
 | 
			
		||||
    rt_assetmeta meta[MAP_SIZE];
 | 
			
		||||
 | 
			
		||||
    unsigned int used_slots;
 | 
			
		||||
} vy_uid_map;
 | 
			
		||||
} rt_uid_map;
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    XXH64_canonical_t checksum;
 | 
			
		||||
    uint32_t num_entries;
 | 
			
		||||
    uint32_t _reserved;
 | 
			
		||||
} vy_assetmeta_header;
 | 
			
		||||
} rt_assetmeta_header;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
#pragma pack(push, 1)
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid uid;
 | 
			
		||||
    vy_file_id source_file;
 | 
			
		||||
    vy_assetmeta meta;
 | 
			
		||||
} vy_assetmeta_entry;
 | 
			
		||||
    rt_uid uid;
 | 
			
		||||
    rt_file_id source_file;
 | 
			
		||||
    rt_assetmeta meta;
 | 
			
		||||
} rt_assetmeta_entry;
 | 
			
		||||
#pragma pack(pop)
 | 
			
		||||
 | 
			
		||||
static vy_uid_map _map;
 | 
			
		||||
static vy_mutex *_guard;
 | 
			
		||||
static rt_uid_map _map;
 | 
			
		||||
static rt_mutex *_guard;
 | 
			
		||||
 | 
			
		||||
vy_result vyLoadAssetMeta(void) {
 | 
			
		||||
    _guard = vyCreateMutex();
 | 
			
		||||
rt_result rtLoadAssetMeta(void) {
 | 
			
		||||
    _guard = rtCreateMutex();
 | 
			
		||||
    
 | 
			
		||||
    /* Load the meta file */
 | 
			
		||||
    size_t fsz = vyGetFileSize("actemp/meta.bin");
 | 
			
		||||
    size_t fsz = rtGetFileSize("actemp/meta.bin");
 | 
			
		||||
    if (fsz == 0) {
 | 
			
		||||
        vyLog("ASSETC", "Metadata file 'meta.bin' not found. All assets will be processed.");
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        rtLog("ASSETC", "Metadata file 'meta.bin' not found. All assets will be processed.");
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *buffer = vyAllocBuffer(fsz);
 | 
			
		||||
    void *buffer = rtAllocBuffer(fsz);
 | 
			
		||||
    if (!buffer) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to allocate buffer for holding asset metadata.");
 | 
			
		||||
        rtReportError("ASSETC", "Failed to allocate buffer for holding asset metadata.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    vy_load_batch load;
 | 
			
		||||
    rt_load_batch load;
 | 
			
		||||
    load.loads[0].dest      = buffer;
 | 
			
		||||
    load.loads[0].file      = vyAddFile("actemp/meta.bin");
 | 
			
		||||
    load.loads[0].file      = rtAddFile("actemp/meta.bin");
 | 
			
		||||
    load.loads[0].num_bytes = fsz;
 | 
			
		||||
    load.loads[0].offset    = 0;
 | 
			
		||||
    load.num_loads          = 1;
 | 
			
		||||
 | 
			
		||||
    vy_aio_handle handle;
 | 
			
		||||
    if (vySubmitLoadBatch(&load, &handle) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to submit load of 'meta.bin'.");
 | 
			
		||||
        vyReleaseBuffer(buffer, fsz);
 | 
			
		||||
    rt_aio_handle handle;
 | 
			
		||||
    if (rtSubmitLoadBatch(&load, &handle) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to submit load of 'meta.bin'.");
 | 
			
		||||
        rtReleaseBuffer(buffer, fsz);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    if (vyWaitForAIOCompletion(handle) != VY_AIO_STATE_FINISHED) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to load 'meta.bin'.");
 | 
			
		||||
        vyReleaseBuffer(buffer, fsz);
 | 
			
		||||
        vyReleaseAIO(handle);
 | 
			
		||||
    if (rtWaitForAIOCompletion(handle) != RT_AIO_STATE_FINISHED) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to load 'meta.bin'.");
 | 
			
		||||
        rtReleaseBuffer(buffer, fsz);
 | 
			
		||||
        rtReleaseAIO(handle);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    vyReleaseAIO(handle);
 | 
			
		||||
    rtReleaseAIO(handle);
 | 
			
		||||
 | 
			
		||||
    const vy_assetmeta_header *header = buffer;
 | 
			
		||||
    const vy_assetmeta_entry *entries = (vy_assetmeta_entry *)(header + 1);
 | 
			
		||||
    const rt_assetmeta_header *header = buffer;
 | 
			
		||||
    const rt_assetmeta_entry *entries = (rt_assetmeta_entry *)(header + 1);
 | 
			
		||||
    
 | 
			
		||||
    if ((sizeof(vy_assetmeta_entry) * header->num_entries + sizeof(*header)) > fsz) {
 | 
			
		||||
        vyReportError("ASSETC", "Header of 'meta.bin' is corrupted: Mismatched num_entries and filesize.");
 | 
			
		||||
        vyReleaseBuffer(buffer, fsz);
 | 
			
		||||
    if ((sizeof(rt_assetmeta_entry) * header->num_entries + sizeof(*header)) > fsz) {
 | 
			
		||||
        rtReportError("ASSETC", "Header of 'meta.bin' is corrupted: Mismatched num_entries and filesize.");
 | 
			
		||||
        rtReleaseBuffer(buffer, fsz);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(vy_assetmeta_entry) * header->num_entries);
 | 
			
		||||
    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(rt_assetmeta_entry) * header->num_entries);
 | 
			
		||||
    XXH64_hash_t header_hash = XXH64_hashFromCanonical(&header->checksum);
 | 
			
		||||
    if (hash != header_hash) {
 | 
			
		||||
        vyReportError("ASSETC",
 | 
			
		||||
        rtReportError("ASSETC",
 | 
			
		||||
                      "Metadata file 'meta.bin' is corrupted: Wrong checksum.");
 | 
			
		||||
        vyReleaseBuffer(buffer, fsz);
 | 
			
		||||
        rtReleaseBuffer(buffer, fsz);
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (uint32_t i = 0; i < header->num_entries; ++i) {
 | 
			
		||||
        /* Load here to avoid unaligned pointer */
 | 
			
		||||
        vy_assetmeta meta = entries[i].meta;
 | 
			
		||||
        vyAddUIDMapping(entries[i].source_file, entries[i].uid, &meta);
 | 
			
		||||
        rt_assetmeta meta = entries[i].meta;
 | 
			
		||||
        rtAddUIDMapping(entries[i].source_file, entries[i].uid, &meta);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyReleaseBuffer(buffer, fsz);
 | 
			
		||||
    rtReleaseBuffer(buffer, fsz);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vySaveAssetMeta(void) {
 | 
			
		||||
    vy_assetmeta_header header = {0};
 | 
			
		||||
rt_result rtSaveAssetMeta(void) {
 | 
			
		||||
    rt_assetmeta_header header = {0};
 | 
			
		||||
 | 
			
		||||
    /* Count number of entries */
 | 
			
		||||
    for (size_t i = 0; i < MAP_SIZE; ++i) {
 | 
			
		||||
        if (_map.fids[i] != VY_INVALID_FILE_ID)
 | 
			
		||||
        if (_map.fids[i] != RT_INVALID_FILE_ID)
 | 
			
		||||
            header.num_entries += 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_assetmeta_entry *entries = vyAllocBuffer(sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
			
		||||
    rt_assetmeta_entry *entries = rtAllocBuffer(sizeof(rt_assetmeta_entry) * header.num_entries);
 | 
			
		||||
    if (!entries)
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
 | 
			
		||||
    /* Store entries */
 | 
			
		||||
    size_t j = 0;
 | 
			
		||||
    for (size_t i = 0; i < MAP_SIZE; ++i) {
 | 
			
		||||
        if (_map.fids[i] != VY_INVALID_FILE_ID) {
 | 
			
		||||
        if (_map.fids[i] != RT_INVALID_FILE_ID) {
 | 
			
		||||
            entries[j].source_file = _map.fids[i];
 | 
			
		||||
            entries[j].uid         = _map.uids[i];
 | 
			
		||||
            entries[j].meta        = _map.meta[i];
 | 
			
		||||
@ -126,52 +126,52 @@ vy_result vySaveAssetMeta(void) {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
			
		||||
    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(rt_assetmeta_entry) * header.num_entries);
 | 
			
		||||
    XXH64_canonicalFromHash(&header.checksum, hash);
 | 
			
		||||
    header._reserved = 0;
 | 
			
		||||
 | 
			
		||||
    FILE *f = fopen("actemp/meta.bin", "wb");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to open 'meta.bin'");
 | 
			
		||||
        vyReleaseBuffer(entries, sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to open 'meta.bin'");
 | 
			
		||||
        rtReleaseBuffer(entries, sizeof(rt_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (fwrite(&header, sizeof(header), 1, f) != 1) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write 'meta.bin'");
 | 
			
		||||
        vyReleaseBuffer(entries, sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write 'meta.bin'");
 | 
			
		||||
        rtReleaseBuffer(entries, sizeof(rt_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (fwrite(entries, sizeof(vy_assetmeta_entry), header.num_entries, f) != header.num_entries) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write 'meta.bin'");
 | 
			
		||||
        vyReleaseBuffer(entries, sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
    if (fwrite(entries, sizeof(rt_assetmeta_entry), header.num_entries, f) != header.num_entries) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write 'meta.bin'");
 | 
			
		||||
        rtReleaseBuffer(entries, sizeof(rt_assetmeta_entry) * header.num_entries);
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fclose(f);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_uid vyLookupUID(vy_file_id fid) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
rt_uid rtLookupUID(rt_file_id fid) {
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    unsigned int i = 0;
 | 
			
		||||
    vy_uid result  = VY_INVALID_UID;
 | 
			
		||||
    rt_uid result  = RT_INVALID_UID;
 | 
			
		||||
    while (i < MAP_SIZE) {
 | 
			
		||||
        unsigned int slot = (fid + i) % MAP_SIZE;
 | 
			
		||||
        if (_map.fids[slot] == fid) {
 | 
			
		||||
            result          = _map.uids[slot];
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (_map.fids[slot] == VY_INVALID_FILE_ID) {
 | 
			
		||||
        } else if (_map.fids[slot] == RT_INVALID_FILE_ID) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool vyGetAssetMeta(vy_file_id source_file, vy_assetmeta *meta) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
bool rtGetAssetMeta(rt_file_id source_file, rt_assetmeta *meta) {
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    unsigned int i = 0;
 | 
			
		||||
    bool result    = false;
 | 
			
		||||
    while (i < MAP_SIZE) {
 | 
			
		||||
@ -180,25 +180,25 @@ bool vyGetAssetMeta(vy_file_id source_file, vy_assetmeta *meta) {
 | 
			
		||||
            *meta  = _map.meta[slot];
 | 
			
		||||
            result = true;
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (_map.fids[slot] == VY_INVALID_FILE_ID) {
 | 
			
		||||
        } else if (_map.fids[slot] == RT_INVALID_FILE_ID) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyAddUIDMapping(vy_file_id fid, vy_uid uid, const vy_assetmeta *meta) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
void rtAddUIDMapping(rt_file_id fid, rt_uid uid, const rt_assetmeta *meta) {
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    float fill_rate = (float)_map.used_slots / MAP_SIZE;
 | 
			
		||||
    if (fill_rate >= .5f) {
 | 
			
		||||
        vyLog("ASSETC", "UID map is above 50% filled.");
 | 
			
		||||
        rtLog("ASSETC", "UID map is above 50% filled.");
 | 
			
		||||
    }
 | 
			
		||||
    unsigned int i = 0;
 | 
			
		||||
    while (i < MAP_SIZE) {
 | 
			
		||||
        unsigned int slot = (fid + i) % MAP_SIZE;
 | 
			
		||||
        if (_map.fids[slot] == VY_INVALID_FILE_ID) {
 | 
			
		||||
        if (_map.fids[slot] == RT_INVALID_FILE_ID) {
 | 
			
		||||
            _map.fids[slot] = fid;
 | 
			
		||||
            _map.uids[slot] = uid;
 | 
			
		||||
            if (meta) {
 | 
			
		||||
@ -216,7 +216,7 @@ void vyAddUIDMapping(vy_file_id fid, vy_uid uid, const vy_assetmeta *meta) {
 | 
			
		||||
        ++i;
 | 
			
		||||
    }
 | 
			
		||||
    if (i == MAP_SIZE) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to insert entry into UID map.");
 | 
			
		||||
        rtReportError("ASSETC", "Failed to insert entry into UID map.");
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_ASSETC_ASSETMETA_H
 | 
			
		||||
#define VY_ASSETC_ASSETMETA_H
 | 
			
		||||
#ifndef RT_ASSETC_ASSETMETA_H
 | 
			
		||||
#define RT_ASSETC_ASSETMETA_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/file_tab.h"
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
@ -11,18 +11,18 @@ typedef struct {
 | 
			
		||||
    uint64_t last_changed;
 | 
			
		||||
    uint64_t compiled_ts;
 | 
			
		||||
    uint32_t processing_flags;
 | 
			
		||||
} vy_assetmeta;
 | 
			
		||||
} rt_assetmeta;
 | 
			
		||||
 | 
			
		||||
vy_result vyLoadAssetMeta(void);
 | 
			
		||||
rt_result rtLoadAssetMeta(void);
 | 
			
		||||
 | 
			
		||||
vy_result vySaveAssetMeta(void);
 | 
			
		||||
rt_result rtSaveAssetMeta(void);
 | 
			
		||||
 | 
			
		||||
/* The UID map associates processed files with generated asset uids. */
 | 
			
		||||
void vyAddUIDMapping(vy_file_id fid, vy_uid uid, const vy_assetmeta *meta);
 | 
			
		||||
void rtAddUIDMapping(rt_file_id fid, rt_uid uid, const rt_assetmeta *meta);
 | 
			
		||||
 | 
			
		||||
/* Returns true if the asset is found. false otherwise */
 | 
			
		||||
bool vyGetAssetMeta(vy_file_id source_file, vy_assetmeta *meta);
 | 
			
		||||
bool rtGetAssetMeta(rt_file_id source_file, rt_assetmeta *meta);
 | 
			
		||||
 | 
			
		||||
vy_uid vyLookupUID(vy_file_id fid);
 | 
			
		||||
rt_uid rtLookupUID(rt_file_id fid);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -10,15 +10,15 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
vy_result vyParseAssetSettings(const char *text,
 | 
			
		||||
rt_result rtParseAssetSettings(const char *text,
 | 
			
		||||
                               size_t length,
 | 
			
		||||
                               const char *file_path,
 | 
			
		||||
                               vy_asset_settings *settings) {
 | 
			
		||||
                               rt_asset_settings *settings) {
 | 
			
		||||
    unsigned int root_list;
 | 
			
		||||
    vy_parse_state state;
 | 
			
		||||
    vy_result res = vyParseDescription(text, length, file_path, &root_list, &state);
 | 
			
		||||
    if (res != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to parse asset settings: %s", file_path);
 | 
			
		||||
    rt_parse_state state;
 | 
			
		||||
    rt_result res = rtParseDescription(text, length, file_path, &root_list, &state);
 | 
			
		||||
    if (res != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to parse asset settings: %s", file_path);
 | 
			
		||||
        return res;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -27,66 +27,66 @@ vy_result vyParseAssetSettings(const char *text,
 | 
			
		||||
    settings->processing_flags = 0;
 | 
			
		||||
    settings->reprocess_on_dependency_change = false;
 | 
			
		||||
    
 | 
			
		||||
    const vy_parsed_stmt *package_stmt = vyFindStatement(&state, root_list, "package");
 | 
			
		||||
    const rt_parsed_stmt *package_stmt = rtFindStatement(&state, root_list, "package");
 | 
			
		||||
    if (package_stmt) {
 | 
			
		||||
        if (package_stmt->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
            vyReportError("ASSETC",
 | 
			
		||||
        if (package_stmt->form != RT_STMT_FORM_VALUE) {
 | 
			
		||||
            rtReportError("ASSETC",
 | 
			
		||||
                          "Expected a package name as the value of 'package' in %s.",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            res = VY_UNKNOWN_ERROR;
 | 
			
		||||
            res = RT_UNKNOWN_ERROR;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        settings->package = vyAddPackageFile(package_stmt->value);
 | 
			
		||||
        settings->package = rtAddPackageFile(package_stmt->value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *flags_stmt = vyFindStatement(&state, root_list, "processing_flags");
 | 
			
		||||
    const rt_parsed_stmt *flags_stmt = rtFindStatement(&state, root_list, "processing_flags");
 | 
			
		||||
    if (flags_stmt) {
 | 
			
		||||
        if (flags_stmt->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
            vyReportError("ASSETC",
 | 
			
		||||
        if (flags_stmt->form != RT_STMT_FORM_VALUE) {
 | 
			
		||||
            rtReportError("ASSETC",
 | 
			
		||||
                          "Expected a hexadecimal number as the value of 'processing_flags' in %s.",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            res = VY_UNKNOWN_ERROR;
 | 
			
		||||
            res = RT_UNKNOWN_ERROR;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        sscanf(flags_stmt->value.start, "%x", &settings->processing_flags);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *reprocess_stmt =
 | 
			
		||||
        vyFindStatement(&state, root_list, "reprocess_on_dependency_change");
 | 
			
		||||
    const rt_parsed_stmt *reprocess_stmt =
 | 
			
		||||
        rtFindStatement(&state, root_list, "reprocess_on_dependency_change");
 | 
			
		||||
    if (reprocess_stmt) {
 | 
			
		||||
        if (reprocess_stmt->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
            vyReportError("ASSETC",
 | 
			
		||||
        if (reprocess_stmt->form != RT_STMT_FORM_VALUE) {
 | 
			
		||||
            rtReportError("ASSETC",
 | 
			
		||||
                          "Expected either 'true' or 'false' as the value of 'reprocess_on_dependency_change' in %s.",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            res = VY_UNKNOWN_ERROR;
 | 
			
		||||
            res = RT_UNKNOWN_ERROR;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
        if (vyCompareSpanToString(reprocess_stmt->value, "true") == 0)
 | 
			
		||||
        if (rtCompareSpanToString(reprocess_stmt->value, "true") == 0)
 | 
			
		||||
            settings->reprocess_on_dependency_change = true;
 | 
			
		||||
        else if (vyCompareSpanToString(reprocess_stmt->value, "false") == 0)
 | 
			
		||||
        else if (rtCompareSpanToString(reprocess_stmt->value, "false") == 0)
 | 
			
		||||
            settings->reprocess_on_dependency_change = false;
 | 
			
		||||
        else {
 | 
			
		||||
            vyReportError("ASSETC",
 | 
			
		||||
            rtReportError("ASSETC",
 | 
			
		||||
                          "Expected either 'true' or 'false' as the value of "
 | 
			
		||||
                          "'reprocess_on_dependency_change' in %s.",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            res = VY_UNKNOWN_ERROR;
 | 
			
		||||
            res = RT_UNKNOWN_ERROR;
 | 
			
		||||
            goto out;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
    vyReleaseParseState(&state);
 | 
			
		||||
    rtReleaseParseState(&state);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyLoadAssetSettings(const char *asset_path, vy_asset_settings *settings) {
 | 
			
		||||
rt_result rtLoadAssetSettings(const char *asset_path, rt_asset_settings *settings) {
 | 
			
		||||
    size_t path_len = strlen(asset_path);
 | 
			
		||||
 | 
			
		||||
    char *as_path = malloc(path_len + 3);
 | 
			
		||||
    if (!as_path) {
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    memcpy(as_path, asset_path, path_len);
 | 
			
		||||
 | 
			
		||||
@ -98,47 +98,47 @@ vy_result vyLoadAssetSettings(const char *asset_path, vy_asset_settings *setting
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    strcpy(&as_path[path_len - ext_len], ".as");
 | 
			
		||||
    size_t as_size = vyGetFileSize(as_path);
 | 
			
		||||
    size_t as_size = rtGetFileSize(as_path);
 | 
			
		||||
    if (as_size == 0) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to retrieve size of setting file %s", as_path);
 | 
			
		||||
        rtReportError("ASSETC", "Failed to retrieve size of setting file %s", as_path);
 | 
			
		||||
        free(as_path);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *as_buffer = vyAllocBuffer(as_size);
 | 
			
		||||
    void *as_buffer = rtAllocBuffer(as_size);
 | 
			
		||||
 | 
			
		||||
    vy_load_batch as_load;
 | 
			
		||||
    as_load.loads[0].file      = vyAddFile(as_path);
 | 
			
		||||
    rt_load_batch as_load;
 | 
			
		||||
    as_load.loads[0].file      = rtAddFile(as_path);
 | 
			
		||||
    as_load.loads[0].num_bytes = as_size;
 | 
			
		||||
    as_load.loads[0].dest      = as_buffer;
 | 
			
		||||
    if (!as_load.loads[0].dest) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to allocate buffer for setting file %s", as_path);
 | 
			
		||||
        rtReportError("ASSETC", "Failed to allocate buffer for setting file %s", as_path);
 | 
			
		||||
        free(as_path);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    as_load.loads[0].offset = 0;
 | 
			
		||||
    as_load.num_loads       = 1;
 | 
			
		||||
 | 
			
		||||
    vy_aio_handle as_handle;
 | 
			
		||||
    if (vySubmitLoadBatch(&as_load, &as_handle) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to submit load of setting file %s", as_path);
 | 
			
		||||
    rt_aio_handle as_handle;
 | 
			
		||||
    if (rtSubmitLoadBatch(&as_load, &as_handle) != RT_SUCCESS) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to submit load of setting file %s", as_path);
 | 
			
		||||
        free(as_path);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vyWaitForAIOCompletion(as_handle) != VY_AIO_STATE_FINISHED) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to load setting file %s", as_path);
 | 
			
		||||
    if (rtWaitForAIOCompletion(as_handle) != RT_AIO_STATE_FINISHED) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to load setting file %s", as_path);
 | 
			
		||||
        free(as_path);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vyReleaseAIO(as_handle);
 | 
			
		||||
    rtReleaseAIO(as_handle);
 | 
			
		||||
 | 
			
		||||
    if (vyParseAssetSettings(as_buffer, as_size, as_path, settings) != VY_SUCCESS) {
 | 
			
		||||
    if (rtParseAssetSettings(as_buffer, as_size, as_path, settings) != RT_SUCCESS) {
 | 
			
		||||
        free(as_path);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    free(as_path);
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
#ifndef VY_ASSETC_ASSETSETTINGS_H
 | 
			
		||||
#define VY_ASSETC_ASSETSETTINGS_H
 | 
			
		||||
#ifndef RT_ASSETC_ASSETSETTINGS_H
 | 
			
		||||
#define RT_ASSETC_ASSETSETTINGS_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
@ -8,14 +8,14 @@ typedef struct {
 | 
			
		||||
    unsigned int package;
 | 
			
		||||
    uint32_t processing_flags;
 | 
			
		||||
    bool reprocess_on_dependency_change;
 | 
			
		||||
} vy_asset_settings;
 | 
			
		||||
} rt_asset_settings;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
vy_result vyParseAssetSettings(const char *text,
 | 
			
		||||
rt_result rtParseAssetSettings(const char *text,
 | 
			
		||||
                               size_t length,
 | 
			
		||||
                               const char *file_path,
 | 
			
		||||
                               vy_asset_settings *settings);
 | 
			
		||||
                               rt_asset_settings *settings);
 | 
			
		||||
 | 
			
		||||
vy_result vyLoadAssetSettings(const char *asset_path, vy_asset_settings *settings);
 | 
			
		||||
rt_result rtLoadAssetSettings(const char *asset_path, rt_asset_settings *settings);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,13 +1,13 @@
 | 
			
		||||
#ifndef VY_ASSETC_COMPILED_H
 | 
			
		||||
#define VY_ASSETC_COMPILED_H
 | 
			
		||||
#ifndef RT_ASSETC_COMPILED_H
 | 
			
		||||
#define RT_ASSETC_COMPILED_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
 | 
			
		||||
vy_uid vyGetUID(const char *name);
 | 
			
		||||
rt_uid rtGetUID(const char *name);
 | 
			
		||||
 | 
			
		||||
void vyStoreOutput(vy_uid uid, const void *data, size_t size);
 | 
			
		||||
void rtStoreOutput(rt_uid uid, const void *data, size_t size);
 | 
			
		||||
 | 
			
		||||
vy_result vyWriteCompiledFiles(void);
 | 
			
		||||
rt_result rtWriteCompiledFiles(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
#include "dependency_tracking.h"
 | 
			
		||||
 | 
			
		||||
#define VY_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_DEPENDENCY_FILE_STRUCTURES
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
#include "runtime/asset_dependencies.h"
 | 
			
		||||
@ -24,11 +24,11 @@
 | 
			
		||||
 | 
			
		||||
/* 64 byte cache line - 8 (next index + count) / 4 (u32) = 14 */
 | 
			
		||||
#define BUCKET_ENTRY_COUNT 14
 | 
			
		||||
typedef struct vy_dep_list_bucket_s {
 | 
			
		||||
typedef struct rt_dep_list_bucket_s {
 | 
			
		||||
    uint32_t next;
 | 
			
		||||
    uint32_t count;
 | 
			
		||||
    vy_uid entries[BUCKET_ENTRY_COUNT];
 | 
			
		||||
} vy_dep_list_bucket;
 | 
			
		||||
    rt_uid entries[BUCKET_ENTRY_COUNT];
 | 
			
		||||
} rt_dep_list_bucket;
 | 
			
		||||
 | 
			
		||||
typedef union {
 | 
			
		||||
    /* Indices of the first buckets */
 | 
			
		||||
@ -37,47 +37,47 @@ typedef union {
 | 
			
		||||
        uint32_t dependents;
 | 
			
		||||
    };
 | 
			
		||||
    uint32_t lists[2];
 | 
			
		||||
} vy_dep_list;
 | 
			
		||||
} rt_dep_list;
 | 
			
		||||
 | 
			
		||||
static vy_mutex *_guard;
 | 
			
		||||
static rt_mutex *_guard;
 | 
			
		||||
 | 
			
		||||
static vy_dep_list_bucket *_buckets;
 | 
			
		||||
static rt_dep_list_bucket *_buckets;
 | 
			
		||||
static uint32_t _bucket_count;
 | 
			
		||||
static uint32_t _bucket_capacity;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define MAP_SIZE 2048
 | 
			
		||||
static vy_uid _uids[MAP_SIZE];
 | 
			
		||||
static vy_dep_list _lists[MAP_SIZE];
 | 
			
		||||
static rt_uid _uids[MAP_SIZE];
 | 
			
		||||
static rt_dep_list _lists[MAP_SIZE];
 | 
			
		||||
 | 
			
		||||
vy_result vyInitDependencyTracking(void) {
 | 
			
		||||
    _guard = vyCreateMutex();
 | 
			
		||||
rt_result rtInitDependencyTracking(void) {
 | 
			
		||||
    _guard = rtCreateMutex();
 | 
			
		||||
    if (!_guard)
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
 | 
			
		||||
    _buckets = malloc(sizeof(vy_dep_list_bucket) * 256);
 | 
			
		||||
    _buckets = malloc(sizeof(rt_dep_list_bucket) * 256);
 | 
			
		||||
    if (!_buckets)
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    _bucket_capacity = 256;
 | 
			
		||||
    _bucket_count    = 1;
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t AllocNewBucket(void) {
 | 
			
		||||
    if (_bucket_count == _bucket_capacity) {
 | 
			
		||||
        void *t = realloc(_buckets, (size_t)_bucket_capacity * 2 * sizeof(vy_dep_list_bucket));
 | 
			
		||||
        void *t = realloc(_buckets, (size_t)_bucket_capacity * 2 * sizeof(rt_dep_list_bucket));
 | 
			
		||||
        if (!t)
 | 
			
		||||
            return 0;
 | 
			
		||||
        _buckets = t;
 | 
			
		||||
        _bucket_capacity *= 2;
 | 
			
		||||
    }
 | 
			
		||||
    memset(&_buckets[_bucket_count], 0, sizeof(vy_dep_list_bucket));
 | 
			
		||||
    memset(&_buckets[_bucket_count], 0, sizeof(rt_dep_list_bucket));
 | 
			
		||||
    return _bucket_count++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result InsertIntoList(vy_uid list_asset, vy_uid uid, int list_index) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
static rt_result InsertIntoList(rt_uid list_asset, rt_uid uid, int list_index) {
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    bool inserted = false;
 | 
			
		||||
    for (uint32_t i = 0; i < MAP_SIZE; i++) {
 | 
			
		||||
        uint32_t at = (list_asset + i) % MAP_SIZE;
 | 
			
		||||
@ -88,13 +88,13 @@ static vy_result InsertIntoList(vy_uid list_asset, vy_uid uid, int list_index) {
 | 
			
		||||
            if (_lists[at].lists[list_index] == 0) {
 | 
			
		||||
                _lists[at].lists[list_index] = AllocNewBucket();
 | 
			
		||||
                if (!_lists[at].lists[list_index]) {
 | 
			
		||||
                    vyUnlockMutex(_guard);
 | 
			
		||||
                    return VY_UNKNOWN_ERROR;
 | 
			
		||||
                    rtUnlockMutex(_guard);
 | 
			
		||||
                    return RT_UNKNOWN_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Advance to the end of the list */
 | 
			
		||||
            vy_dep_list_bucket *bucket = &_buckets[_lists[at].lists[list_index]];
 | 
			
		||||
            rt_dep_list_bucket *bucket = &_buckets[_lists[at].lists[list_index]];
 | 
			
		||||
            while (bucket->next != END_OF_LIST) {
 | 
			
		||||
                bucket = &_buckets[bucket->next];
 | 
			
		||||
            }
 | 
			
		||||
@ -103,8 +103,8 @@ static vy_result InsertIntoList(vy_uid list_asset, vy_uid uid, int list_index) {
 | 
			
		||||
            if (bucket->count == BUCKET_ENTRY_COUNT) {
 | 
			
		||||
                bucket->next = AllocNewBucket();
 | 
			
		||||
                if (!bucket->next) {
 | 
			
		||||
                    vyUnlockMutex(_guard);
 | 
			
		||||
                    return VY_UNKNOWN_ERROR;
 | 
			
		||||
                    rtUnlockMutex(_guard);
 | 
			
		||||
                    return RT_UNKNOWN_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
                bucket = &_buckets[bucket->next];
 | 
			
		||||
            }
 | 
			
		||||
@ -116,64 +116,64 @@ static vy_result InsertIntoList(vy_uid list_asset, vy_uid uid, int list_index) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
    assert(inserted);
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyAddAssetDependency(vy_uid dependent, vy_uid dependency) {
 | 
			
		||||
    vy_result res = InsertIntoList(dependent, dependency, 0);
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
rt_result rtAddAssetDependency(rt_uid dependent, rt_uid dependency) {
 | 
			
		||||
    rt_result res = InsertIntoList(dependent, dependency, 0);
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    res = InsertIntoList(dependency, dependent, 1);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vySaveAssetDependencies(void) {
 | 
			
		||||
    assert(vyIsMainThread());
 | 
			
		||||
    vy_dependency_file_header header = {.num_lists = 0, .data_size = 0};
 | 
			
		||||
rt_result rtSaveAssetDependencies(void) {
 | 
			
		||||
    assert(rtIsMainThread());
 | 
			
		||||
    rt_dependency_file_header header = {.num_lists = 0, .data_size = 0};
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < MAP_SIZE; ++i) {
 | 
			
		||||
        if (_uids[i] != VY_INVALID_UID) {
 | 
			
		||||
        if (_uids[i] != RT_INVALID_UID) {
 | 
			
		||||
            if (!_lists[i].dependencies)
 | 
			
		||||
                continue;
 | 
			
		||||
            header.num_lists += 1;
 | 
			
		||||
 | 
			
		||||
            /* Determine the list size */
 | 
			
		||||
            vy_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies];
 | 
			
		||||
            rt_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies];
 | 
			
		||||
            uint32_t total_list_size   = bucket->count;
 | 
			
		||||
            while (bucket->next != END_OF_LIST) {
 | 
			
		||||
                bucket = &_buckets[bucket->next];
 | 
			
		||||
                total_list_size += bucket->count;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            header.data_size += total_list_size * sizeof(vy_uid) + sizeof(vy_dependency_file_list_header);
 | 
			
		||||
            header.data_size += total_list_size * sizeof(rt_uid) + sizeof(rt_dependency_file_list_header);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    FILE *f = fopen("data/deps.bin", "wb");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to open 'deps.bin' for writing.");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to open 'deps.bin' for writing.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if (fwrite(&header, sizeof(header), 1, f) != 1) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write to 'deps.bin'.");
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write to 'deps.bin'.");
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *buffer       = NULL;
 | 
			
		||||
    size_t buffer_size = 0;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i < MAP_SIZE; ++i) {
 | 
			
		||||
        if (_uids[i] != VY_INVALID_UID) {
 | 
			
		||||
        if (_uids[i] != RT_INVALID_UID) {
 | 
			
		||||
            if (!_lists[i].dependencies)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            /* Determine the list size */
 | 
			
		||||
            vy_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies];
 | 
			
		||||
            rt_dep_list_bucket *bucket = &_buckets[_lists[i].dependencies];
 | 
			
		||||
            uint32_t total_list_size = bucket->count;
 | 
			
		||||
            while (bucket->next != END_OF_LIST) {
 | 
			
		||||
                bucket = &_buckets[bucket->next];
 | 
			
		||||
@ -182,21 +182,21 @@ vy_result vySaveAssetDependencies(void) {
 | 
			
		||||
 | 
			
		||||
            /* Allocate */
 | 
			
		||||
            size_t required_size =
 | 
			
		||||
                total_list_size * sizeof(vy_uid) + sizeof(vy_dependency_file_list_header);
 | 
			
		||||
                total_list_size * sizeof(rt_uid) + sizeof(rt_dependency_file_list_header);
 | 
			
		||||
            if (required_size > buffer_size) {
 | 
			
		||||
                void *t = realloc(buffer, required_size);
 | 
			
		||||
                if (!t) {
 | 
			
		||||
                    free(buffer);
 | 
			
		||||
                    fclose(f);
 | 
			
		||||
                    return VY_UNKNOWN_ERROR;
 | 
			
		||||
                    return RT_UNKNOWN_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
                buffer = t;
 | 
			
		||||
                buffer_size = required_size;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Fill header */
 | 
			
		||||
            vy_dependency_file_list_header *list_header = buffer;
 | 
			
		||||
            vy_uid *list                                = (vy_uid *)(list_header + 1);
 | 
			
		||||
            rt_dependency_file_list_header *list_header = buffer;
 | 
			
		||||
            rt_uid *list                                = (rt_uid *)(list_header + 1);
 | 
			
		||||
            list_header->uid                            = _uids[i];
 | 
			
		||||
            list_header->num_entries                    = total_list_size;
 | 
			
		||||
 | 
			
		||||
@ -204,19 +204,19 @@ vy_result vySaveAssetDependencies(void) {
 | 
			
		||||
            uint32_t at = 0;
 | 
			
		||||
            bucket = &_buckets[_lists[i].dependencies];
 | 
			
		||||
            do {
 | 
			
		||||
                memcpy(&list[at], bucket->entries, sizeof(vy_uid) * bucket->count);
 | 
			
		||||
                memcpy(&list[at], bucket->entries, sizeof(rt_uid) * bucket->count);
 | 
			
		||||
                at += bucket->count;
 | 
			
		||||
                bucket = &_buckets[bucket->next];
 | 
			
		||||
            } while (bucket != &_buckets[END_OF_LIST]);
 | 
			
		||||
 | 
			
		||||
            XXH64_hash_t hash = XXH3_64bits(list, sizeof(vy_uid) * total_list_size);
 | 
			
		||||
            XXH64_hash_t hash = XXH3_64bits(list, sizeof(rt_uid) * total_list_size);
 | 
			
		||||
            XXH64_canonicalFromHash(&list_header->checksum, hash);
 | 
			
		||||
 | 
			
		||||
            if (fwrite(buffer, required_size, 1, f) != 1) {
 | 
			
		||||
                vyReportError("ASSETC", "Failed to write to 'deps.bin'.");
 | 
			
		||||
                rtReportError("ASSETC", "Failed to write to 'deps.bin'.");
 | 
			
		||||
                fclose(f);
 | 
			
		||||
                free(buffer);
 | 
			
		||||
                return VY_UNKNOWN_ERROR;
 | 
			
		||||
                return RT_UNKNOWN_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -224,5 +224,5 @@ vy_result vySaveAssetDependencies(void) {
 | 
			
		||||
    fclose(f);
 | 
			
		||||
    free(buffer);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +1,14 @@
 | 
			
		||||
#ifndef VY_ASSETC_DEPENDENCY_TRACKING_H
 | 
			
		||||
#define VY_ASSETC_DEPENDENCY_TRACKING_H
 | 
			
		||||
#ifndef RT_ASSETC_DEPENDENCY_TRACKING_H
 | 
			
		||||
#define RT_ASSETC_DEPENDENCY_TRACKING_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
vy_result vyInitDependencyTracking(void);
 | 
			
		||||
rt_result rtInitDependencyTracking(void);
 | 
			
		||||
 | 
			
		||||
vy_result vyAddAssetDependency(vy_uid dependent, vy_uid dependency);
 | 
			
		||||
rt_result rtAddAssetDependency(rt_uid dependent, rt_uid dependency);
 | 
			
		||||
 | 
			
		||||
vy_result vySaveAssetDependencies(void);
 | 
			
		||||
rt_result rtSaveAssetDependencies(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ static bool IsWhitespace(char c) {
 | 
			
		||||
    return c == ' ' || c == '\t' || c == '\n' || c == '\r';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void SkipWhitespace(vy_parse_state *state) {
 | 
			
		||||
static void SkipWhitespace(rt_parse_state *state) {
 | 
			
		||||
    while (state->at < state->length && IsWhitespace(state->text[state->at])) {
 | 
			
		||||
        if (state->text[state->at] == '\n')
 | 
			
		||||
            ++state->line;
 | 
			
		||||
@ -25,8 +25,8 @@ static void SkipWhitespace(vy_parse_state *state) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
			
		||||
    vy_text_span name;
 | 
			
		||||
static bool ParseAttribute(rt_parse_state *state, rt_text_span *_name) {
 | 
			
		||||
    rt_text_span name;
 | 
			
		||||
    name.start  = &state->text[state->at];
 | 
			
		||||
    name.length = 0;
 | 
			
		||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at])) {
 | 
			
		||||
@ -34,7 +34,7 @@ static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
			
		||||
            ++state->at;
 | 
			
		||||
            ++name.length;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "%s:%d Unexpected character %c",
 | 
			
		||||
                          state->file,
 | 
			
		||||
                          state->line,
 | 
			
		||||
@ -46,8 +46,8 @@ static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
			
		||||
    vy_text_span value;
 | 
			
		||||
static bool ParseValue(rt_parse_state *state, rt_text_span *_value) {
 | 
			
		||||
    rt_text_span value;
 | 
			
		||||
    value.start  = &state->text[state->at];
 | 
			
		||||
    value.length = 0;
 | 
			
		||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at]) &&
 | 
			
		||||
@ -56,7 +56,7 @@ static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
			
		||||
            ++state->at;
 | 
			
		||||
            ++value.length;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "%s:%d Unexpected character %c",
 | 
			
		||||
                          state->file,
 | 
			
		||||
                          state->line,
 | 
			
		||||
@ -73,18 +73,18 @@ static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
			
		||||
#define BLOCK_END        "END"
 | 
			
		||||
#define BLOCK_END_LENGTH 3
 | 
			
		||||
 | 
			
		||||
VY_INLINE static bool IsBlockBegin(vy_parse_state *state) {
 | 
			
		||||
RT_INLINE static bool IsBlockBegin(rt_parse_state *state) {
 | 
			
		||||
    return (state->length - state->at >= BLOCK_BEGIN_LENGTH) &&
 | 
			
		||||
           (memcmp(&state->text[state->at], BLOCK_BEGIN, BLOCK_BEGIN_LENGTH) == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_INLINE static bool IsBlockEnd(vy_parse_state *state) {
 | 
			
		||||
RT_INLINE static bool IsBlockEnd(rt_parse_state *state) {
 | 
			
		||||
    return (state->length - state->at >= BLOCK_END_LENGTH) &&
 | 
			
		||||
           (memcmp(&state->text[state->at], BLOCK_END, BLOCK_END_LENGTH) == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseBlock(vy_parse_state *state, vy_text_span *p_value) {
 | 
			
		||||
    vy_text_span value;
 | 
			
		||||
static bool ParseBlock(rt_parse_state *state, rt_text_span *p_value) {
 | 
			
		||||
    rt_text_span value;
 | 
			
		||||
    value.start = &state->text[state->at];
 | 
			
		||||
    value.length = 0;
 | 
			
		||||
    while (state->at < state->length) {
 | 
			
		||||
@ -99,10 +99,10 @@ static bool ParseBlock(vy_parse_state *state, vy_text_span *p_value) {
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index);
 | 
			
		||||
static bool ParseStmtList(rt_parse_state *state, unsigned int *list_index);
 | 
			
		||||
 | 
			
		||||
static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    vy_parsed_stmt stmt;
 | 
			
		||||
static bool ParseStmt(rt_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    rt_parsed_stmt stmt;
 | 
			
		||||
    stmt.next = UINT_MAX; /* end of list */
 | 
			
		||||
 | 
			
		||||
    SkipWhitespace(state);
 | 
			
		||||
@ -111,7 +111,7 @@ static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    SkipWhitespace(state);
 | 
			
		||||
 | 
			
		||||
    if (state->at == state->length) {
 | 
			
		||||
        vyReportError("GFX", "%s:%d Expected either a value or '{'", state->file, state->line);
 | 
			
		||||
        rtReportError("GFX", "%s:%d Expected either a value or '{'", state->file, state->line);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -119,7 +119,7 @@ static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
        /* Consume '{' */
 | 
			
		||||
        ++state->at;
 | 
			
		||||
 | 
			
		||||
        stmt.form = VY_STMT_FORM_LIST;
 | 
			
		||||
        stmt.form = RT_STMT_FORM_LIST;
 | 
			
		||||
        if (!ParseStmtList(state, &stmt.list_index))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
@ -130,14 +130,14 @@ static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
        /* Consume BEGIN */
 | 
			
		||||
        state->at += BLOCK_BEGIN_LENGTH;
 | 
			
		||||
 | 
			
		||||
        stmt.form = VY_STMT_FORM_BLOCK;
 | 
			
		||||
        stmt.form = RT_STMT_FORM_BLOCK;
 | 
			
		||||
        if (!ParseBlock(state, &stmt.block))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        /* Consume END */
 | 
			
		||||
        state->at += BLOCK_END_LENGTH;
 | 
			
		||||
    } else {
 | 
			
		||||
        stmt.form = VY_STMT_FORM_VALUE;
 | 
			
		||||
        stmt.form = RT_STMT_FORM_VALUE;
 | 
			
		||||
        if (!ParseValue(state, &stmt.value))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
@ -151,9 +151,9 @@ static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    /* Add statement to array */
 | 
			
		||||
    if (state->statement_count == state->statement_capacity) {
 | 
			
		||||
        unsigned int cap     = (state->statement_capacity > 0) ? state->statement_capacity * 2 : 64;
 | 
			
		||||
        vy_parsed_stmt *temp = realloc(state->statements, sizeof(vy_parsed_stmt) * cap);
 | 
			
		||||
        rt_parsed_stmt *temp = realloc(state->statements, sizeof(rt_parsed_stmt) * cap);
 | 
			
		||||
        if (!temp) {
 | 
			
		||||
            vyReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
			
		||||
            rtReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        state->statements         = temp;
 | 
			
		||||
@ -165,8 +165,8 @@ static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
			
		||||
    vy_parsed_stmt_list list;
 | 
			
		||||
static bool ParseStmtList(rt_parse_state *state, unsigned int *list_index) {
 | 
			
		||||
    rt_parsed_stmt_list list;
 | 
			
		||||
    list.first = UINT_MAX;
 | 
			
		||||
    list.count = 0;
 | 
			
		||||
 | 
			
		||||
@ -190,10 +190,10 @@ static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
			
		||||
    if (state->statement_list_count == state->statement_list_capacity) {
 | 
			
		||||
        unsigned int cap =
 | 
			
		||||
            (state->statement_list_capacity > 0) ? state->statement_list_capacity * 2 : 64;
 | 
			
		||||
        vy_parsed_stmt_list *temp =
 | 
			
		||||
            realloc(state->statement_lists, sizeof(vy_parsed_stmt_list) * cap);
 | 
			
		||||
        rt_parsed_stmt_list *temp =
 | 
			
		||||
            realloc(state->statement_lists, sizeof(rt_parsed_stmt_list) * cap);
 | 
			
		||||
        if (!temp) {
 | 
			
		||||
            vyReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
			
		||||
            rtReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        state->statement_lists         = temp;
 | 
			
		||||
@ -204,14 +204,14 @@ static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const vy_parsed_stmt * vyFindStatement(const vy_parse_state *state, unsigned int list_index, const char *attribute) {
 | 
			
		||||
const rt_parsed_stmt * rtFindStatement(const rt_parse_state *state, unsigned int list_index, const char *attribute) {
 | 
			
		||||
    if (list_index >= state->statement_list_count)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
    const rt_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
    unsigned int stmt_index         = list->first;
 | 
			
		||||
    for (unsigned int i = 0; i < list->count; ++i) {
 | 
			
		||||
        const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        if (vyCompareSpanToString(stmt->attribute, attribute) == 0)
 | 
			
		||||
        const rt_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        if (rtCompareSpanToString(stmt->attribute, attribute) == 0)
 | 
			
		||||
            return stmt;
 | 
			
		||||
        stmt_index = stmt->next;
 | 
			
		||||
    }
 | 
			
		||||
@ -219,13 +219,13 @@ const vy_parsed_stmt * vyFindStatement(const vy_parse_state *state, unsigned int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
vy_result vyParseDescription(const char *text,
 | 
			
		||||
rt_result rtParseDescription(const char *text,
 | 
			
		||||
                             size_t length,
 | 
			
		||||
                             const char *file_path,
 | 
			
		||||
                             unsigned int *_root_list,
 | 
			
		||||
                             vy_parse_state *_state) {
 | 
			
		||||
                             rt_parse_state *_state) {
 | 
			
		||||
 | 
			
		||||
    vy_parse_state state = {.text                    = text,
 | 
			
		||||
    rt_parse_state state = {.text                    = text,
 | 
			
		||||
                            .at                      = 0,
 | 
			
		||||
                            .length                  = length,
 | 
			
		||||
                            .line                    = 1,
 | 
			
		||||
@ -242,11 +242,11 @@ vy_result vyParseDescription(const char *text,
 | 
			
		||||
    *_root_list = root_list;
 | 
			
		||||
    *_state     = state;
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void vyReleaseParseState(vy_parse_state *state) {
 | 
			
		||||
void rtReleaseParseState(rt_parse_state *state) {
 | 
			
		||||
    free(state->statements);
 | 
			
		||||
    free(state->statement_lists);
 | 
			
		||||
}
 | 
			
		||||
@ -1,30 +1,30 @@
 | 
			
		||||
#ifndef VY_ASSETC_DESCRIPTION_PARSER_H
 | 
			
		||||
#define VY_ASSETC_DESCRIPTION_PARSER_H
 | 
			
		||||
#ifndef RT_ASSETC_DESCRIPTION_PARSER_H
 | 
			
		||||
#define RT_ASSETC_DESCRIPTION_PARSER_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_STMT_FORM_VALUE,
 | 
			
		||||
    VY_STMT_FORM_LIST,
 | 
			
		||||
    VY_STMT_FORM_BLOCK,
 | 
			
		||||
} vy_stmt_form;
 | 
			
		||||
    RT_STMT_FORM_VALUE,
 | 
			
		||||
    RT_STMT_FORM_LIST,
 | 
			
		||||
    RT_STMT_FORM_BLOCK,
 | 
			
		||||
} rt_stmt_form;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    unsigned int first;
 | 
			
		||||
    unsigned int count;
 | 
			
		||||
} vy_parsed_stmt_list;
 | 
			
		||||
} rt_parsed_stmt_list;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_stmt_form form;
 | 
			
		||||
    vy_text_span attribute;
 | 
			
		||||
    rt_stmt_form form;
 | 
			
		||||
    rt_text_span attribute;
 | 
			
		||||
    union {
 | 
			
		||||
        vy_text_span value;
 | 
			
		||||
        vy_text_span block;
 | 
			
		||||
        rt_text_span value;
 | 
			
		||||
        rt_text_span block;
 | 
			
		||||
        unsigned int list_index;
 | 
			
		||||
    };
 | 
			
		||||
    /* For lists */
 | 
			
		||||
    unsigned int next;
 | 
			
		||||
} vy_parsed_stmt;
 | 
			
		||||
} rt_parsed_stmt;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *file;
 | 
			
		||||
@ -33,23 +33,23 @@ typedef struct {
 | 
			
		||||
    size_t length;
 | 
			
		||||
    int line;
 | 
			
		||||
 | 
			
		||||
    vy_parsed_stmt *statements;
 | 
			
		||||
    rt_parsed_stmt *statements;
 | 
			
		||||
    unsigned int statement_count;
 | 
			
		||||
    unsigned int statement_capacity;
 | 
			
		||||
 | 
			
		||||
    vy_parsed_stmt_list *statement_lists;
 | 
			
		||||
    rt_parsed_stmt_list *statement_lists;
 | 
			
		||||
    unsigned int statement_list_count;
 | 
			
		||||
    unsigned int statement_list_capacity;
 | 
			
		||||
} vy_parse_state;
 | 
			
		||||
} rt_parse_state;
 | 
			
		||||
 | 
			
		||||
vy_result vyParseDescription(const char *text,
 | 
			
		||||
rt_result rtParseDescription(const char *text,
 | 
			
		||||
                             size_t length,
 | 
			
		||||
                             const char *file_path,
 | 
			
		||||
                             unsigned int *root_list,
 | 
			
		||||
                             vy_parse_state *state);
 | 
			
		||||
                             rt_parse_state *state);
 | 
			
		||||
 | 
			
		||||
const vy_parsed_stmt *vyFindStatement(const vy_parse_state *state, unsigned int list_index, const char *attribute);
 | 
			
		||||
const rt_parsed_stmt *rtFindStatement(const rt_parse_state *state, unsigned int list_index, const char *attribute);
 | 
			
		||||
 | 
			
		||||
void vyReleaseParseState(vy_parse_state *state);
 | 
			
		||||
void rtReleaseParseState(rt_parse_state *state);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -11,32 +11,32 @@
 | 
			
		||||
typedef struct {
 | 
			
		||||
    char path_scratch[1024];
 | 
			
		||||
    unsigned int path_end;
 | 
			
		||||
} vy_discovery_data;
 | 
			
		||||
} rt_discovery_data;
 | 
			
		||||
 | 
			
		||||
static vy_result LoadCompressedAsset(vy_uid uid, void **buffer, size_t size) {
 | 
			
		||||
static rt_result LoadCompressedAsset(rt_uid uid, void **buffer, size_t size) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result DirectoryHandler(const char *name, vyIterateDirElementType type, void *user) {
 | 
			
		||||
    vy_discovery_data *data = user;
 | 
			
		||||
static rt_result DirectoryHandler(const char *name, rtIterateDirElementType type, void *user) {
 | 
			
		||||
    rt_discovery_data *data = user;
 | 
			
		||||
 | 
			
		||||
    size_t name_len = strlen(name);
 | 
			
		||||
 | 
			
		||||
    if (type == VY_DIR_ELEMENT_TYPE_FILE) {
 | 
			
		||||
    if (type == RT_DIR_ELEMENT_TYPE_FILE) {
 | 
			
		||||
        /* Skip files we don't want to process */
 | 
			
		||||
        if (name_len >= 3) {
 | 
			
		||||
            if (memcmp(&name[name_len - 3], ".as", 3) == 0)
 | 
			
		||||
                return VY_SUCCESS;
 | 
			
		||||
                return RT_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
        if (name_len >= 4) {
 | 
			
		||||
            if (memcmp(&name[name_len - 4], ".pkg", 4) == 0)
 | 
			
		||||
                return VY_SUCCESS;
 | 
			
		||||
                return RT_SUCCESS;
 | 
			
		||||
            else if (memcmp(&name[name_len - 4], ".bin", 4) == 0)
 | 
			
		||||
                return VY_SUCCESS;
 | 
			
		||||
                return RT_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
        if (strcmp(name, "packages.txt") == 0)
 | 
			
		||||
            return VY_SUCCESS;
 | 
			
		||||
            return RT_SUCCESS;
 | 
			
		||||
        if (name[0] == '.') {
 | 
			
		||||
            return VY_SUCCESS;
 | 
			
		||||
            return RT_SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Check if we know that file */
 | 
			
		||||
@ -49,49 +49,49 @@ static vy_result DirectoryHandler(const char *name, vyIterateDirElementType type
 | 
			
		||||
            data->path_scratch[name_len] = '\0';
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vy_file_id fid = vyAddFile(data->path_scratch);
 | 
			
		||||
        if (vyLookupUID(fid) != VY_INVALID_UID) {
 | 
			
		||||
            vy_assetmeta meta = {0};
 | 
			
		||||
            if (!vyGetAssetMeta(fid, &meta) || (meta.last_changed >= meta.compiled_ts)) {
 | 
			
		||||
        rt_file_id fid = rtAddFile(data->path_scratch);
 | 
			
		||||
        if (rtLookupUID(fid) != RT_INVALID_UID) {
 | 
			
		||||
            rt_assetmeta meta = {0};
 | 
			
		||||
            if (!rtGetAssetMeta(fid, &meta) || (meta.last_changed >= meta.compiled_ts)) {
 | 
			
		||||
                /* The file (may have) changed */
 | 
			
		||||
                vy_result res = vyAddFileToProcessingQueue(fid, meta.processing_flags);
 | 
			
		||||
                if (res != VY_SUCCESS)
 | 
			
		||||
                rt_result res = rtAddFileToProcessingQueue(fid, meta.processing_flags);
 | 
			
		||||
                if (res != RT_SUCCESS)
 | 
			
		||||
                    return res;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                /* The file is unchanged, we just need to add it to the output again. */
 | 
			
		||||
                vyLog("ASSETC", "File %s is unchanged.", data->path_scratch);
 | 
			
		||||
                rtLog("ASSETC", "File %s is unchanged.", data->path_scratch);
 | 
			
		||||
 | 
			
		||||
                vy_asset_settings settings = {0};
 | 
			
		||||
                if (vyLoadAssetSettings(data->path_scratch, &settings) != VY_SUCCESS) {
 | 
			
		||||
                    vyLog("ASSETC", "Failed to load settings for %s", data->path_scratch);
 | 
			
		||||
                    return VY_UNKNOWN_ERROR;
 | 
			
		||||
                rt_asset_settings settings = {0};
 | 
			
		||||
                if (rtLoadAssetSettings(data->path_scratch, &settings) != RT_SUCCESS) {
 | 
			
		||||
                    rtLog("ASSETC", "Failed to load settings for %s", data->path_scratch);
 | 
			
		||||
                    return RT_UNKNOWN_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* We need to load the processed data and add it to the package */
 | 
			
		||||
                vy_uid uid = vyLookupUID(fid);
 | 
			
		||||
                if (uid == VY_INVALID_UID) {
 | 
			
		||||
                    vyLog("ASSETC", "Failed to lookup UID of known asset %s", data->path_scratch);
 | 
			
		||||
                    return VY_UNKNOWN_ERROR;
 | 
			
		||||
                rt_uid uid = rtLookupUID(fid);
 | 
			
		||||
                if (uid == RT_INVALID_UID) {
 | 
			
		||||
                    rtLog("ASSETC", "Failed to lookup UID of known asset %s", data->path_scratch);
 | 
			
		||||
                    return RT_UNKNOWN_ERROR;
 | 
			
		||||
                }
 | 
			
		||||
                vyAddUnchangedAssetToPackage(settings.package, uid);
 | 
			
		||||
                rtAddUnchangedAssetToPackage(settings.package, uid);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            /* Process it */
 | 
			
		||||
            vy_asset_settings settings = {0};
 | 
			
		||||
            if (vyLoadAssetSettings(data->path_scratch, &settings) != VY_SUCCESS) {
 | 
			
		||||
                vyLog("ASSETC", "Failed to load settings for %s", data->path_scratch);
 | 
			
		||||
            rt_asset_settings settings = {0};
 | 
			
		||||
            if (rtLoadAssetSettings(data->path_scratch, &settings) != RT_SUCCESS) {
 | 
			
		||||
                rtLog("ASSETC", "Failed to load settings for %s", data->path_scratch);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            vy_result res = vyAddFileToProcessingQueue(fid, settings.processing_flags);
 | 
			
		||||
            if (res != VY_SUCCESS)
 | 
			
		||||
            rt_result res = rtAddFileToProcessingQueue(fid, settings.processing_flags);
 | 
			
		||||
            if (res != RT_SUCCESS)
 | 
			
		||||
                return res;
 | 
			
		||||
        }
 | 
			
		||||
    } else if (type == VY_DIR_ELEMENT_TYPE_DIRECTORY) {
 | 
			
		||||
    } else if (type == RT_DIR_ELEMENT_TYPE_DIRECTORY) {
 | 
			
		||||
        if (strcmp(name, ".") == 0)
 | 
			
		||||
            return VY_SUCCESS;
 | 
			
		||||
            return RT_SUCCESS;
 | 
			
		||||
        if (strcmp(name, "..") == 0)
 | 
			
		||||
            return VY_SUCCESS;
 | 
			
		||||
            return RT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
        unsigned int path_end_before = data->path_end;
 | 
			
		||||
        if (data->path_end > 0)
 | 
			
		||||
@ -100,20 +100,20 @@ static vy_result DirectoryHandler(const char *name, vyIterateDirElementType type
 | 
			
		||||
        data->path_scratch[data->path_end + name_len] = '\0';
 | 
			
		||||
        data->path_end += (unsigned int)name_len;
 | 
			
		||||
 | 
			
		||||
        vy_result res = vyIterateDirectory(data->path_scratch, user, DirectoryHandler);
 | 
			
		||||
        if (res != VY_SUCCESS)
 | 
			
		||||
        rt_result res = rtIterateDirectory(data->path_scratch, user, DirectoryHandler);
 | 
			
		||||
        if (res != RT_SUCCESS)
 | 
			
		||||
            return res;
 | 
			
		||||
 | 
			
		||||
        data->path_end = path_end_before;
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyDiscoverAssets(void) {
 | 
			
		||||
void rtDiscoverAssets(void) {
 | 
			
		||||
 | 
			
		||||
    vy_discovery_data data;
 | 
			
		||||
    rt_discovery_data data;
 | 
			
		||||
    memcpy(data.path_scratch, "assets", sizeof("assets"));
 | 
			
		||||
    data.path_end = sizeof("assets") - 1;
 | 
			
		||||
    
 | 
			
		||||
    vyIterateDirectory("assets", &data, DirectoryHandler);
 | 
			
		||||
    rtIterateDirectory("assets", &data, DirectoryHandler);
 | 
			
		||||
}
 | 
			
		||||
@ -1,28 +1,28 @@
 | 
			
		||||
#ifndef VY_ASSETC_OPTIONS_H
 | 
			
		||||
#define VY_ASSETC_OPTIONS_H
 | 
			
		||||
#ifndef RT_ASSETC_OPTIONS_H
 | 
			
		||||
#define RT_ASSETC_OPTIONS_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    /* No optimization */
 | 
			
		||||
    VY_ASSET_OPTIMIZATION_NONE,
 | 
			
		||||
    RT_ASSET_OPTIMIZATION_NONE,
 | 
			
		||||
 | 
			
		||||
    /* Create small assets */
 | 
			
		||||
    VY_ASSET_OPTIMIZATION_SPACE,
 | 
			
		||||
    RT_ASSET_OPTIMIZATION_SPACE,
 | 
			
		||||
 | 
			
		||||
    /* Create assets for fast execution */
 | 
			
		||||
    VY_ASSET_OPTIMIZATION_PERFORMANCE,
 | 
			
		||||
} vy_asset_optimization_level;
 | 
			
		||||
    RT_ASSET_OPTIMIZATION_PERFORMANCE,
 | 
			
		||||
} rt_asset_optimization_level;
 | 
			
		||||
 | 
			
		||||
/* Options parsed from command line arguments */
 | 
			
		||||
typedef struct {
 | 
			
		||||
    const char *root_directory;
 | 
			
		||||
    vy_renderer_backend_code renderer_backend;
 | 
			
		||||
    vy_asset_optimization_level optimization;
 | 
			
		||||
} vy_assetc_options;
 | 
			
		||||
    rt_renderer_backend_code renderer_backend;
 | 
			
		||||
    rt_asset_optimization_level optimization;
 | 
			
		||||
} rt_assetc_options;
 | 
			
		||||
 | 
			
		||||
#ifndef VY_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
			
		||||
extern vy_assetc_options g_assetc_options;
 | 
			
		||||
#ifndef RT_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
			
		||||
extern rt_assetc_options g_assetc_options;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
#include "processing.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
#define VY_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_PACKAGE_FILE_STRUCTURES
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
#include "runtime/file_tab.h"
 | 
			
		||||
@ -19,30 +19,30 @@
 | 
			
		||||
#include "lz4/lz4.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid uid;
 | 
			
		||||
    rt_uid uid;
 | 
			
		||||
    size_t disk_size;
 | 
			
		||||
} vy_package_entry;
 | 
			
		||||
} rt_package_entry;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    char *name;
 | 
			
		||||
    unsigned int num_entries;
 | 
			
		||||
    unsigned int entry_capacity;
 | 
			
		||||
    vy_package_entry *entries;
 | 
			
		||||
} vy_package;
 | 
			
		||||
    rt_package_entry *entries;
 | 
			
		||||
} rt_package;
 | 
			
		||||
 | 
			
		||||
#define MAX_PACKAGES 1024
 | 
			
		||||
 | 
			
		||||
vy_package _packages[MAX_PACKAGES];
 | 
			
		||||
rt_package _packages[MAX_PACKAGES];
 | 
			
		||||
unsigned int _package_count = 0;
 | 
			
		||||
 | 
			
		||||
vy_mutex *_guard;
 | 
			
		||||
rt_mutex *_guard;
 | 
			
		||||
 | 
			
		||||
unsigned int vyAddPackageFile(vy_text_span name) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
unsigned int rtAddPackageFile(rt_text_span name) {
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < _package_count; ++i) {
 | 
			
		||||
        if (vyCompareSpanToString(name, _packages[i].name + 5) == 0) {
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
        if (rtCompareSpanToString(name, _packages[i].name + 5) == 0) {
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@ -50,11 +50,11 @@ unsigned int vyAddPackageFile(vy_text_span name) {
 | 
			
		||||
    /* Create a new package */
 | 
			
		||||
    _packages[_package_count].name = malloc(name.length + 1 + 5);
 | 
			
		||||
    if (!_packages[_package_count].name) {
 | 
			
		||||
        vyReportError("ASSETC",
 | 
			
		||||
        rtReportError("ASSETC",
 | 
			
		||||
                      "Failed to allocate storage for new package %*.s",
 | 
			
		||||
                      name.length,
 | 
			
		||||
                      name.start);
 | 
			
		||||
        vyUnlockMutex(_guard);
 | 
			
		||||
        rtUnlockMutex(_guard);
 | 
			
		||||
        return UINT_MAX;
 | 
			
		||||
    }
 | 
			
		||||
    memcpy(_packages[_package_count].name, "data/", 5);
 | 
			
		||||
@ -63,42 +63,42 @@ unsigned int vyAddPackageFile(vy_text_span name) {
 | 
			
		||||
 | 
			
		||||
    unsigned int index = _package_count++;
 | 
			
		||||
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
    return index;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyInitPackages(void) {
 | 
			
		||||
    _guard = vyCreateMutex();
 | 
			
		||||
void rtInitPackages(void) {
 | 
			
		||||
    _guard = rtCreateMutex();
 | 
			
		||||
    /* Create the default package (0) */
 | 
			
		||||
    vyAddPackageFile((vy_text_span){.start = "default.pkg", .length = 12});
 | 
			
		||||
    rtAddPackageFile((rt_text_span){.start = "default.pkg", .length = 12});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
                                  vy_uid uid,
 | 
			
		||||
                                  rt_uid uid,
 | 
			
		||||
                                  void *buffer,
 | 
			
		||||
                                  size_t size,
 | 
			
		||||
                                  bool needs_compression) {
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    if (package >= _package_count) {
 | 
			
		||||
        vyReportError("ASSETC", "Trying to add an asset to a non-existing package.");
 | 
			
		||||
        vyUnlockMutex(_guard);
 | 
			
		||||
        rtReportError("ASSETC", "Trying to add an asset to a non-existing package.");
 | 
			
		||||
        rtUnlockMutex(_guard);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vy_package *pkg = &_packages[package];
 | 
			
		||||
    rt_package *pkg = &_packages[package];
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < pkg->num_entries; ++i) {
 | 
			
		||||
        if (pkg->entries[i].uid == uid) {
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pkg->num_entries == pkg->entry_capacity) {
 | 
			
		||||
        unsigned int new_cap = (pkg->entry_capacity > 0) ? 2 * pkg->entry_capacity : 256;
 | 
			
		||||
        vy_package_entry *n  = realloc(pkg->entries, new_cap * sizeof(vy_package_entry));
 | 
			
		||||
        rt_package_entry *n  = realloc(pkg->entries, new_cap * sizeof(rt_package_entry));
 | 
			
		||||
        if (!n) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to grow storage for package %u.", package);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to grow storage for package %u.", package);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        pkg->entry_capacity = new_cap;
 | 
			
		||||
@ -110,7 +110,7 @@ static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
    if (needs_compression) {
 | 
			
		||||
        FILE *tmp_f = fopen(tmp_path, "wb");
 | 
			
		||||
        if (!tmp_f) {
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -118,7 +118,7 @@ static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
        void *compressed_buffer = malloc(required_size);
 | 
			
		||||
        if (!compressed_buffer) {
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -127,23 +127,23 @@ static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
        if (compressed_bytes == 0) {
 | 
			
		||||
            free(compressed_buffer);
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            vyReportError("ASSETC", "Failed to compress asset %x of package %s", uid, pkg->name);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to compress asset %x of package %s", uid, pkg->name);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vy_package_asset_header header;
 | 
			
		||||
        rt_package_asset_header header;
 | 
			
		||||
        XXH64_hash_t checksum = XXH3_64bits_withSeed(buffer, (size_t)compressed_bytes, 0);
 | 
			
		||||
        XXH64_canonicalFromHash(&header.checksum, checksum);
 | 
			
		||||
        header.decompressed_size = (uint32_t)size;
 | 
			
		||||
 | 
			
		||||
        if (fwrite(&header, sizeof(header), 1, tmp_f) != 1) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to write to actemp/%u.bin", uid);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to write to actemp/%u.bin", uid);
 | 
			
		||||
            free(compressed_buffer);
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (fwrite(buffer, compressed_bytes, 1, tmp_f) != 1) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to write to actemp/%u.bin", uid);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to write to actemp/%u.bin", uid);
 | 
			
		||||
            free(compressed_buffer);
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            return;
 | 
			
		||||
@ -151,11 +151,11 @@ static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
        fclose(tmp_f);
 | 
			
		||||
 | 
			
		||||
        pkg->entries[pkg->num_entries].disk_size =
 | 
			
		||||
            (size_t)compressed_bytes + sizeof(vy_package_asset_header);
 | 
			
		||||
            (size_t)compressed_bytes + sizeof(rt_package_asset_header);
 | 
			
		||||
    } else {
 | 
			
		||||
        pkg->entries[pkg->num_entries].disk_size = vyGetFileSize(tmp_path);
 | 
			
		||||
        pkg->entries[pkg->num_entries].disk_size = rtGetFileSize(tmp_path);
 | 
			
		||||
        if (pkg->entries[pkg->num_entries].disk_size == 0) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to determine size of actemp/%u.bin", uid);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to determine size of actemp/%u.bin", uid);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
@ -163,21 +163,21 @@ static void AddAssetToPackageImpl(unsigned int package,
 | 
			
		||||
    ++pkg->num_entries;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyAddAssetToPackage(unsigned int package, vy_uid uid, void *buffer, size_t size) {
 | 
			
		||||
void rtAddAssetToPackage(unsigned int package, rt_uid uid, void *buffer, size_t size) {
 | 
			
		||||
    AddAssetToPackageImpl(package, uid, buffer, size, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyAddUnchangedAssetToPackage(unsigned int package, vy_uid uid) {
 | 
			
		||||
void rtAddUnchangedAssetToPackage(unsigned int package, rt_uid uid) {
 | 
			
		||||
    AddAssetToPackageImpl(package, uid, NULL, 0, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result SavePackage(vy_package *pkg) {
 | 
			
		||||
static rt_result SavePackage(rt_package *pkg) {
 | 
			
		||||
    if (pkg->num_entries == 0) {
 | 
			
		||||
        vyLog("ASSETC", "Package %s has no entries.", pkg->name);
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        rtLog("ASSETC", "Package %s has no entries.", pkg->name);
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t current_buffer_size = 0;
 | 
			
		||||
@ -185,12 +185,12 @@ static vy_result SavePackage(vy_package *pkg) {
 | 
			
		||||
 | 
			
		||||
    size_t offset_in_file = 0;
 | 
			
		||||
 | 
			
		||||
    vy_file_id package_fid = vyAddFile(pkg->name);
 | 
			
		||||
    rt_file_id package_fid = rtAddFile(pkg->name);
 | 
			
		||||
 | 
			
		||||
    FILE *f = fopen(pkg->name, "wb");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to open %s for writing.", pkg->name);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to open %s for writing.", pkg->name);
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < pkg->num_entries; ++i) {
 | 
			
		||||
@ -198,42 +198,42 @@ static vy_result SavePackage(vy_package *pkg) {
 | 
			
		||||
        snprintf(tmp_path, 256, "actemp/%u.bin", pkg->entries[i].uid);
 | 
			
		||||
        FILE *tmp_f = fopen(tmp_path, "rb");
 | 
			
		||||
        if (!tmp_f) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to open %s for reading.", tmp_path);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to open %s for reading.", tmp_path);
 | 
			
		||||
            fclose(f);
 | 
			
		||||
            free(buffer);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (current_buffer_size < pkg->entries[i].disk_size) {
 | 
			
		||||
            void *tmp = realloc(buffer, pkg->entries[i].disk_size);
 | 
			
		||||
            if (!tmp) {
 | 
			
		||||
                vyReportError("ASSETC", "Failed to allocate buffer (%zu bytes) for reading %s.", pkg->entries[i].disk_size, tmp_path);
 | 
			
		||||
                rtReportError("ASSETC", "Failed to allocate buffer (%zu bytes) for reading %s.", pkg->entries[i].disk_size, tmp_path);
 | 
			
		||||
                fclose(f);
 | 
			
		||||
                fclose(tmp_f);
 | 
			
		||||
                free(buffer);
 | 
			
		||||
                return VY_UNKNOWN_ERROR;
 | 
			
		||||
                return RT_UNKNOWN_ERROR;
 | 
			
		||||
            }
 | 
			
		||||
            buffer = tmp;
 | 
			
		||||
            current_buffer_size = pkg->entries[i].disk_size;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (fread(buffer, pkg->entries[i].disk_size, 1, tmp_f) != 1) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to read %s.", tmp_path);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to read %s.", tmp_path);
 | 
			
		||||
            fclose(f);
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            free(buffer);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (fwrite(buffer, pkg->entries[i].disk_size, 1, f) != 1) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to write (%zu bytes) to %s.", pkg->entries[i].disk_size, pkg->name);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to write (%zu bytes) to %s.", pkg->entries[i].disk_size, pkg->name);
 | 
			
		||||
            fclose(f);
 | 
			
		||||
            fclose(tmp_f);
 | 
			
		||||
            free(buffer);
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        vyAddUIDTabEntry(package_fid,
 | 
			
		||||
        rtAddUIDTabEntry(package_fid,
 | 
			
		||||
                         pkg->entries[i].uid,
 | 
			
		||||
                         offset_in_file,
 | 
			
		||||
                         pkg->entries[i].disk_size);
 | 
			
		||||
@ -245,18 +245,18 @@ static vy_result SavePackage(vy_package *pkg) {
 | 
			
		||||
    free(buffer);
 | 
			
		||||
    fclose(f);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vySavePackages(void) {
 | 
			
		||||
    assert(vyIsMainThread());
 | 
			
		||||
rt_result rtSavePackages(void) {
 | 
			
		||||
    assert(rtIsMainThread());
 | 
			
		||||
 | 
			
		||||
    /* Save a .txt file with one line per package.
 | 
			
		||||
     * Enables us to re-init the file-tab in future runs. */
 | 
			
		||||
    FILE *f = fopen("data/packages.txt", "w");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write to 'packages.txt'");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write to 'packages.txt'");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    for (unsigned int i = 0; i < _package_count; ++i) {
 | 
			
		||||
        if (_packages[i].num_entries == 0)
 | 
			
		||||
@ -266,9 +266,9 @@ vy_result vySavePackages(void) {
 | 
			
		||||
    fclose(f);
 | 
			
		||||
 | 
			
		||||
    for (unsigned int i = 0; i < _package_count; ++i) {
 | 
			
		||||
        vy_result res = SavePackage(&_packages[i]);
 | 
			
		||||
        if (res != VY_SUCCESS)
 | 
			
		||||
        rt_result res = SavePackage(&_packages[i]);
 | 
			
		||||
        if (res != RT_SUCCESS)
 | 
			
		||||
            return res;
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -1,16 +1,16 @@
 | 
			
		||||
#ifndef VY_ASSETC_PACKAGES_H
 | 
			
		||||
#define VY_ASSETC_PACKAGES_H
 | 
			
		||||
#ifndef RT_ASSETC_PACKAGES_H
 | 
			
		||||
#define RT_ASSETC_PACKAGES_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/runtime.h"
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
 | 
			
		||||
void vyInitPackages(void);
 | 
			
		||||
void rtInitPackages(void);
 | 
			
		||||
 | 
			
		||||
unsigned int vyAddPackageFile(vy_text_span name);
 | 
			
		||||
unsigned int rtAddPackageFile(rt_text_span name);
 | 
			
		||||
 | 
			
		||||
void vyAddAssetToPackage(unsigned int package, vy_uid uid, void *buffer, size_t size);
 | 
			
		||||
void vyAddUnchangedAssetToPackage(unsigned int package, vy_uid uid);
 | 
			
		||||
void rtAddAssetToPackage(unsigned int package, rt_uid uid, void *buffer, size_t size);
 | 
			
		||||
void rtAddUnchangedAssetToPackage(unsigned int package, rt_uid uid);
 | 
			
		||||
 | 
			
		||||
vy_result vySavePackages(void);
 | 
			
		||||
rt_result rtSavePackages(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -22,13 +22,13 @@
 | 
			
		||||
#include "dependency_tracking.h"
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_attribute_binding *uniform_bindings;
 | 
			
		||||
    vy_attribute_binding *storage_bindings;
 | 
			
		||||
    vy_attribute_binding *texture_bindings;
 | 
			
		||||
    rt_attribute_binding *uniform_bindings;
 | 
			
		||||
    rt_attribute_binding *storage_bindings;
 | 
			
		||||
    rt_attribute_binding *texture_bindings;
 | 
			
		||||
 | 
			
		||||
    vy_uid vertex_shader;
 | 
			
		||||
    vy_uid fragment_shader;
 | 
			
		||||
    vy_uid compute_shader;
 | 
			
		||||
    rt_uid vertex_shader;
 | 
			
		||||
    rt_uid fragment_shader;
 | 
			
		||||
    rt_uid compute_shader;
 | 
			
		||||
 | 
			
		||||
    /* TODO Fixed function settings */
 | 
			
		||||
 | 
			
		||||
@ -37,20 +37,20 @@ typedef struct {
 | 
			
		||||
    uint16_t uniform_binding_count;
 | 
			
		||||
    uint16_t storage_binding_count;
 | 
			
		||||
    uint16_t texture_binding_count;
 | 
			
		||||
} vy_parsed_pipeline_data;
 | 
			
		||||
} rt_parsed_pipeline_data;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
DbgPrintShaderFile(const vy_parse_state *state, unsigned int list_index, unsigned int indent) {
 | 
			
		||||
DbgPrintShaderFile(const rt_parse_state *state, unsigned int list_index, unsigned int indent) {
 | 
			
		||||
    assert(list_index < state->statement_list_count);
 | 
			
		||||
    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
    const rt_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
			
		||||
 | 
			
		||||
    unsigned int stmt_index = list->first;
 | 
			
		||||
    for (unsigned int i = 0; i < list->count; ++i) {
 | 
			
		||||
        const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        const rt_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
        for (unsigned int j = 0; j < indent; ++j)
 | 
			
		||||
            printf(" ");
 | 
			
		||||
        printf("%.*s: ", stmt->attribute.length, stmt->attribute.start);
 | 
			
		||||
        if (stmt->form == VY_STMT_FORM_VALUE) {
 | 
			
		||||
        if (stmt->form == RT_STMT_FORM_VALUE) {
 | 
			
		||||
            printf("%.*s\n", stmt->value.length, stmt->value.start);
 | 
			
		||||
        } else {
 | 
			
		||||
            printf("{\n");
 | 
			
		||||
@ -62,7 +62,7 @@ DbgPrintShaderFile(const vy_parse_state *state, unsigned int list_index, unsigne
 | 
			
		||||
    assert(stmt_index == UINT_MAX || stmt_index == 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
			
		||||
static bool ParseBindingIndex(rt_text_span span, unsigned int *index) {
 | 
			
		||||
    if (span.length == 0)
 | 
			
		||||
        return false;
 | 
			
		||||
    int at           = (int)span.length - 1;
 | 
			
		||||
@ -73,7 +73,7 @@ static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
			
		||||
            unsigned int digit = (unsigned int)(span.start[at] - '0');
 | 
			
		||||
            n += digit * exp;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX", "Unexpected non-digit character in binding index");
 | 
			
		||||
            rtReportError("GFX", "Unexpected non-digit character in binding index");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        --at;
 | 
			
		||||
@ -83,54 +83,54 @@ static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_attribute_value ParseBindingValue(vy_text_span span) {
 | 
			
		||||
    if (vyCompareSpanToString(span, "MATERIAL_ALBEDO") == 0) {
 | 
			
		||||
        return VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO;
 | 
			
		||||
    } else if (vyCompareSpanToString(span, "MATERIAL_NORMAL") == 0) {
 | 
			
		||||
        return VY_ATTRIBUTE_VALUE_MATERIAL_NORMAL;
 | 
			
		||||
static rt_attribute_value ParseBindingValue(rt_text_span span) {
 | 
			
		||||
    if (rtCompareSpanToString(span, "MATERIAL_ALBEDO") == 0) {
 | 
			
		||||
        return RT_ATTRIBUTE_VALUE_MATERIAL_ALBEDO;
 | 
			
		||||
    } else if (rtCompareSpanToString(span, "MATERIAL_NORMAL") == 0) {
 | 
			
		||||
        return RT_ATTRIBUTE_VALUE_MATERIAL_NORMAL;
 | 
			
		||||
    }
 | 
			
		||||
    vyReportError("GFX", "Unsupported binding value %*.s", span.length, span.start);
 | 
			
		||||
    return VY_ATTRIBUTE_VALUE_UNDEFINED;
 | 
			
		||||
    rtReportError("GFX", "Unsupported binding value %*.s", span.length, span.start);
 | 
			
		||||
    return RT_ATTRIBUTE_VALUE_UNDEFINED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool ParseBindings(vy_parse_state *state,
 | 
			
		||||
static bool ParseBindings(rt_parse_state *state,
 | 
			
		||||
                          unsigned int root_list,
 | 
			
		||||
                          const char *name,
 | 
			
		||||
                          const char *file_path,
 | 
			
		||||
                          vy_attribute_binding **p_bindings,
 | 
			
		||||
                          rt_attribute_binding **p_bindings,
 | 
			
		||||
                          uint16_t *p_binding_count) {
 | 
			
		||||
    const vy_parsed_stmt *bindings = vyFindStatement(state, root_list, name);
 | 
			
		||||
    const rt_parsed_stmt *bindings = rtFindStatement(state, root_list, name);
 | 
			
		||||
    if (bindings) {
 | 
			
		||||
        if (bindings->form != VY_STMT_FORM_LIST) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
        if (bindings->form != RT_STMT_FORM_LIST) {
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "Expected list of bindings as the value of "
 | 
			
		||||
                          "\"%s\" in %s",
 | 
			
		||||
                          name,
 | 
			
		||||
                          file_path);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        const vy_parsed_stmt_list *binding_list = &state->statement_lists[bindings->list_index];
 | 
			
		||||
        vy_attribute_binding *shader_bindings =
 | 
			
		||||
            vyAllocBuffer(sizeof(vy_attribute_binding) * binding_list->count);
 | 
			
		||||
        const rt_parsed_stmt_list *binding_list = &state->statement_lists[bindings->list_index];
 | 
			
		||||
        rt_attribute_binding *shader_bindings =
 | 
			
		||||
            rtAllocBuffer(sizeof(rt_attribute_binding) * binding_list->count);
 | 
			
		||||
        if (!bindings) {
 | 
			
		||||
            vyReportError("GFX", "Out of memory");
 | 
			
		||||
            rtReportError("GFX", "Out of memory");
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        unsigned int binding_count = binding_list->count;
 | 
			
		||||
 | 
			
		||||
        unsigned int stmt_index = binding_list->first;
 | 
			
		||||
        for (unsigned int i = 0; i < binding_list->count; ++i) {
 | 
			
		||||
            const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
            const rt_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
			
		||||
            if (!ParseBindingIndex(stmt->attribute, &shader_bindings[i].index)) {
 | 
			
		||||
                vyReleaseBuffer(shader_bindings,
 | 
			
		||||
                                sizeof(vy_attribute_binding) * binding_list->count);
 | 
			
		||||
                rtReleaseBuffer(shader_bindings,
 | 
			
		||||
                                sizeof(rt_attribute_binding) * binding_list->count);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            shader_bindings[i].value = ParseBindingValue(stmt->value);
 | 
			
		||||
            if (shader_bindings[i].value == VY_ATTRIBUTE_VALUE_UNDEFINED) {
 | 
			
		||||
                vyReleaseBuffer(shader_bindings,
 | 
			
		||||
                                sizeof(vy_attribute_binding) * binding_list->count);
 | 
			
		||||
            if (shader_bindings[i].value == RT_ATTRIBUTE_VALUE_UNDEFINED) {
 | 
			
		||||
                rtReleaseBuffer(shader_bindings,
 | 
			
		||||
                                sizeof(rt_attribute_binding) * binding_list->count);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            stmt_index = stmt->next;
 | 
			
		||||
@ -146,60 +146,60 @@ static bool ParseBindings(vy_parse_state *state,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result ParseShader(vy_parse_state *state,
 | 
			
		||||
static rt_result ParseShader(rt_parse_state *state,
 | 
			
		||||
                             unsigned int root_list,
 | 
			
		||||
                             const char *name,
 | 
			
		||||
                             const char *file_path,
 | 
			
		||||
                             uint32_t processing_flags,
 | 
			
		||||
                             vy_uid *p_shader_uid) {
 | 
			
		||||
    const vy_parsed_stmt *stmt = vyFindStatement(state, root_list, name);
 | 
			
		||||
                             rt_uid *p_shader_uid) {
 | 
			
		||||
    const rt_parsed_stmt *stmt = rtFindStatement(state, root_list, name);
 | 
			
		||||
    if (stmt) {
 | 
			
		||||
        if (stmt->form != VY_STMT_FORM_LIST) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
        if (stmt->form != RT_STMT_FORM_LIST) {
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "Expected a list as the value of "
 | 
			
		||||
                          "\"%s\" in %s",
 | 
			
		||||
                          name,
 | 
			
		||||
                          file_path);
 | 
			
		||||
            return VY_PROCESSING_FAILED;
 | 
			
		||||
            return RT_PROCESSING_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        const vy_parsed_stmt_list *shader_list = &state->statement_lists[stmt->list_index];
 | 
			
		||||
        const rt_parsed_stmt_list *shader_list = &state->statement_lists[stmt->list_index];
 | 
			
		||||
 | 
			
		||||
        unsigned int stmt_index = shader_list->first;
 | 
			
		||||
        for (unsigned int i = 0; i < shader_list->count; ++i) {
 | 
			
		||||
            const vy_parsed_stmt *shader = &state->statements[stmt_index];
 | 
			
		||||
            if (shader->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
                vyReportError("GFX",
 | 
			
		||||
            const rt_parsed_stmt *shader = &state->statements[stmt_index];
 | 
			
		||||
            if (shader->form != RT_STMT_FORM_VALUE) {
 | 
			
		||||
                rtReportError("GFX",
 | 
			
		||||
                              "Expected a list as the value of "
 | 
			
		||||
                              "\"%s.%*s\" in %s",
 | 
			
		||||
                              name,
 | 
			
		||||
                              (int)shader->attribute.length,
 | 
			
		||||
                              shader->attribute.start,
 | 
			
		||||
                              file_path);
 | 
			
		||||
                return VY_PROCESSING_FAILED;
 | 
			
		||||
                return RT_PROCESSING_FAILED;
 | 
			
		||||
            }
 | 
			
		||||
            vy_renderer_backend_code backend = VY_INVALID_RENDERER_BACKEND_CODE;
 | 
			
		||||
            if (vyCompareSpanToString(shader->attribute, "vk") == 0) {
 | 
			
		||||
                backend = VY_RENDERER_BACKEND_CODE_VK;
 | 
			
		||||
            rt_renderer_backend_code backend = RT_INVALID_RENDERER_BACKEND_CODE;
 | 
			
		||||
            if (rtCompareSpanToString(shader->attribute, "vk") == 0) {
 | 
			
		||||
                backend = RT_RENDERER_BACKEND_CODE_VK;
 | 
			
		||||
            } else {
 | 
			
		||||
                vyReportError("GFX",
 | 
			
		||||
                rtReportError("GFX",
 | 
			
		||||
                              "Invalid renderer backend"
 | 
			
		||||
                              "\"%*s\" in %s of file %s",
 | 
			
		||||
                              (int)shader->attribute.length,
 | 
			
		||||
                              shader->attribute.start,
 | 
			
		||||
                              name,
 | 
			
		||||
                              file_path);
 | 
			
		||||
                return VY_PROCESSING_FAILED;
 | 
			
		||||
                return RT_PROCESSING_FAILED;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (backend == g_assetc_options.renderer_backend) {
 | 
			
		||||
                vy_file_id shader_file = vyAddFileFromSpan(shader->value);
 | 
			
		||||
                vy_uid uid             = vyLookupUID(shader_file);
 | 
			
		||||
                if (uid == VY_INVALID_UID) {
 | 
			
		||||
                rt_file_id shader_file = rtAddFileFromSpan(shader->value);
 | 
			
		||||
                rt_uid uid             = rtLookupUID(shader_file);
 | 
			
		||||
                if (uid == RT_INVALID_UID) {
 | 
			
		||||
                    /* Add the shader file to processing and wait until its done
 | 
			
		||||
                     */
 | 
			
		||||
                    if (vyAddFileToProcessingQueue(shader_file, processing_flags) != VY_SUCCESS)
 | 
			
		||||
                        return VY_PROCESSING_FAILED;
 | 
			
		||||
                    return VY_PROCESSING_TRY_AGAIN;
 | 
			
		||||
                    if (rtAddFileToProcessingQueue(shader_file, processing_flags) != RT_SUCCESS)
 | 
			
		||||
                        return RT_PROCESSING_FAILED;
 | 
			
		||||
                    return RT_PROCESSING_TRY_AGAIN;
 | 
			
		||||
                }
 | 
			
		||||
                *p_shader_uid = uid;
 | 
			
		||||
 | 
			
		||||
@ -208,44 +208,44 @@ static vy_result ParseShader(vy_parse_state *state,
 | 
			
		||||
            }
 | 
			
		||||
            stmt_index = shader->next;
 | 
			
		||||
        }
 | 
			
		||||
        return VY_SUCCESS;
 | 
			
		||||
        return RT_SUCCESS;
 | 
			
		||||
    }
 | 
			
		||||
    return VY_PROCESSING_FAILED;
 | 
			
		||||
    return RT_PROCESSING_FAILED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static uint32_t
 | 
			
		||||
ParseOptimizationLevel(vy_parse_state *state, unsigned int root_list, const char *file_path) {
 | 
			
		||||
ParseOptimizationLevel(rt_parse_state *state, unsigned int root_list, const char *file_path) {
 | 
			
		||||
    uint32_t optimization_level;
 | 
			
		||||
    switch (g_assetc_options.optimization) { 
 | 
			
		||||
    case VY_ASSET_OPTIMIZATION_PERFORMANCE:
 | 
			
		||||
        optimization_level = VY_SHADER_FLAG_OPTIMIZE_SPEED;
 | 
			
		||||
    case RT_ASSET_OPTIMIZATION_PERFORMANCE:
 | 
			
		||||
        optimization_level = RT_SHADER_FLAG_OPTIMIZE_SPEED;
 | 
			
		||||
        break;
 | 
			
		||||
    case VY_ASSET_OPTIMIZATION_SPACE:
 | 
			
		||||
        optimization_level = VY_SHADER_FLAG_OPTIMIZE_SIZE;
 | 
			
		||||
    case RT_ASSET_OPTIMIZATION_SPACE:
 | 
			
		||||
        optimization_level = RT_SHADER_FLAG_OPTIMIZE_SIZE;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        optimization_level = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vy_parsed_stmt *stmt = vyFindStatement(state, root_list, "optimization");
 | 
			
		||||
    const rt_parsed_stmt *stmt = rtFindStatement(state, root_list, "optimization");
 | 
			
		||||
 | 
			
		||||
    if (stmt) {
 | 
			
		||||
        if (stmt->form != VY_STMT_FORM_VALUE) {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
        if (stmt->form != RT_STMT_FORM_VALUE) {
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "Expected a simple statement for"
 | 
			
		||||
                          "\"optimization\" in %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
            return optimization_level;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (vyCompareSpanToString(stmt->value, "speed") == 0) {
 | 
			
		||||
            optimization_level = VY_SHADER_FLAG_OPTIMIZE_SPEED;
 | 
			
		||||
        } else if (vyCompareSpanToString(stmt->value, "size") == 0) {
 | 
			
		||||
            optimization_level = VY_SHADER_FLAG_OPTIMIZE_SIZE;
 | 
			
		||||
        } else if (vyCompareSpanToString(stmt->value, "none") == 0) {
 | 
			
		||||
        if (rtCompareSpanToString(stmt->value, "speed") == 0) {
 | 
			
		||||
            optimization_level = RT_SHADER_FLAG_OPTIMIZE_SPEED;
 | 
			
		||||
        } else if (rtCompareSpanToString(stmt->value, "size") == 0) {
 | 
			
		||||
            optimization_level = RT_SHADER_FLAG_OPTIMIZE_SIZE;
 | 
			
		||||
        } else if (rtCompareSpanToString(stmt->value, "none") == 0) {
 | 
			
		||||
            optimization_level = 0;
 | 
			
		||||
        } else {
 | 
			
		||||
            vyReportError("GFX",
 | 
			
		||||
            rtReportError("GFX",
 | 
			
		||||
                          "Expected one of 'speed', 'size' and 'none' for \"optimization\" in %s",
 | 
			
		||||
                          file_path);
 | 
			
		||||
        }
 | 
			
		||||
@ -254,18 +254,18 @@ ParseOptimizationLevel(vy_parse_state *state, unsigned int root_list, const char
 | 
			
		||||
    return optimization_level;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result
 | 
			
		||||
ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pipeline_data *pipeline) {
 | 
			
		||||
static rt_result
 | 
			
		||||
ParsePipelineFile(rt_file_id fid, const char *text, size_t length, rt_parsed_pipeline_data *pipeline) {
 | 
			
		||||
    /* This is the grammar for pipeline files:
 | 
			
		||||
     * <stmt-list> ::= <stmt>*
 | 
			
		||||
     * <stmt> ::= <attribute> ( ( <value> ';' ) | ( '{' <stmt-list> '}' ) )
 | 
			
		||||
     * <attribute> ::= [:alnum:]*
 | 
			
		||||
     * <value>:: = [:alnum:]* */
 | 
			
		||||
    const char *file_path = vyGetFilePath(fid);
 | 
			
		||||
    vy_parse_state state;
 | 
			
		||||
    const char *file_path = rtGetFilePath(fid);
 | 
			
		||||
    rt_parse_state state;
 | 
			
		||||
    unsigned int root_list;
 | 
			
		||||
    vy_result result = vyParseDescription(text, length, file_path, &root_list, &state);
 | 
			
		||||
    if (result != VY_SUCCESS) {
 | 
			
		||||
    rt_result result = rtParseDescription(text, length, file_path, &root_list, &state);
 | 
			
		||||
    if (result != RT_SUCCESS) {
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -277,27 +277,27 @@ ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pip
 | 
			
		||||
                    root_list,
 | 
			
		||||
                    "vertex",
 | 
			
		||||
                    file_path,
 | 
			
		||||
                    VY_SHADER_FLAG_VERTEX | optimization,
 | 
			
		||||
                    &pipeline->vertex_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
			
		||||
                    RT_SHADER_FLAG_VERTEX | optimization,
 | 
			
		||||
                    &pipeline->vertex_shader) == RT_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = RT_PROCESSING_TRY_AGAIN;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    if (ParseShader(&state,
 | 
			
		||||
                    root_list,
 | 
			
		||||
                    "fragment",
 | 
			
		||||
                    file_path,
 | 
			
		||||
                    VY_SHADER_FLAG_FRAGMENT | optimization,
 | 
			
		||||
                    &pipeline->fragment_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
			
		||||
                    RT_SHADER_FLAG_FRAGMENT | optimization,
 | 
			
		||||
                    &pipeline->fragment_shader) == RT_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = RT_PROCESSING_TRY_AGAIN;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
    if (ParseShader(&state,
 | 
			
		||||
                    root_list,
 | 
			
		||||
                    "compute",
 | 
			
		||||
                    file_path,
 | 
			
		||||
                    VY_SHADER_FLAG_COMPUTE | optimization,
 | 
			
		||||
                    &pipeline->compute_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
			
		||||
                    RT_SHADER_FLAG_COMPUTE | optimization,
 | 
			
		||||
                    &pipeline->compute_shader) == RT_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
        result = RT_PROCESSING_TRY_AGAIN;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -315,7 +315,7 @@ ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pip
 | 
			
		||||
                       file_path,
 | 
			
		||||
                       &pipeline->texture_bindings,
 | 
			
		||||
                       &pipeline->texture_binding_count)) {
 | 
			
		||||
        result = VY_AIO_STATE_FAILED;
 | 
			
		||||
        result = RT_AIO_STATE_FAILED;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -325,7 +325,7 @@ ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pip
 | 
			
		||||
                       file_path,
 | 
			
		||||
                       &pipeline->uniform_bindings,
 | 
			
		||||
                       &pipeline->uniform_binding_count)) {
 | 
			
		||||
        result = VY_AIO_STATE_FAILED;
 | 
			
		||||
        result = RT_AIO_STATE_FAILED;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -335,7 +335,7 @@ ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pip
 | 
			
		||||
                       file_path,
 | 
			
		||||
                       &pipeline->storage_bindings,
 | 
			
		||||
                       &pipeline->storage_binding_count)) {
 | 
			
		||||
        result = VY_AIO_STATE_FAILED;
 | 
			
		||||
        result = RT_AIO_STATE_FAILED;
 | 
			
		||||
        goto out;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -345,29 +345,29 @@ out:
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyProcessPipelineFile(vy_file_id file,
 | 
			
		||||
rt_result rtProcessPipelineFile(rt_file_id file,
 | 
			
		||||
                                void *buffer,
 | 
			
		||||
                                size_t size,
 | 
			
		||||
                                uint32_t flags,
 | 
			
		||||
                                vy_processor_output *output) {
 | 
			
		||||
    VY_UNUSED(flags);
 | 
			
		||||
    vy_parsed_pipeline_data tmp;
 | 
			
		||||
                                rt_processor_output *output) {
 | 
			
		||||
    RT_UNUSED(flags);
 | 
			
		||||
    rt_parsed_pipeline_data tmp;
 | 
			
		||||
    memset(&tmp, 0, sizeof(tmp));
 | 
			
		||||
 | 
			
		||||
    vy_result result = ParsePipelineFile(file, buffer, size, &tmp);
 | 
			
		||||
    if (result == VY_SUCCESS) {
 | 
			
		||||
    rt_result result = ParsePipelineFile(file, buffer, size, &tmp);
 | 
			
		||||
    if (result == RT_SUCCESS) {
 | 
			
		||||
        /* parsed_pipeline_data contains arrays of bindings.
 | 
			
		||||
         * We need to convert these to a flat buffer that can be written to a file */
 | 
			
		||||
 | 
			
		||||
        size_t outbuffer_size =
 | 
			
		||||
            sizeof(vy_pipeline_info) +
 | 
			
		||||
            sizeof(vy_attribute_binding) *
 | 
			
		||||
            sizeof(rt_pipeline_info) +
 | 
			
		||||
            sizeof(rt_attribute_binding) *
 | 
			
		||||
                (tmp.storage_binding_count + tmp.texture_binding_count + tmp.uniform_binding_count);
 | 
			
		||||
        void *out_buffer = vyAllocBuffer(outbuffer_size);
 | 
			
		||||
        void *out_buffer = rtAllocBuffer(outbuffer_size);
 | 
			
		||||
        if (!buffer) {
 | 
			
		||||
            return VY_PROCESSING_FAILED;
 | 
			
		||||
            return RT_PROCESSING_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        vy_pipeline_info *info      = out_buffer;
 | 
			
		||||
        rt_pipeline_info *info      = out_buffer;
 | 
			
		||||
        info->vertex_shader         = tmp.vertex_shader;
 | 
			
		||||
        info->fragment_shader       = tmp.fragment_shader;
 | 
			
		||||
        info->compute_shader        = tmp.compute_shader;
 | 
			
		||||
@ -375,49 +375,49 @@ vy_result vyProcessPipelineFile(vy_file_id file,
 | 
			
		||||
        info->uniform_binding_count = tmp.uniform_binding_count;
 | 
			
		||||
        info->storage_binding_count = tmp.storage_binding_count;
 | 
			
		||||
 | 
			
		||||
        vy_attribute_binding *texture_bindings = NULL;
 | 
			
		||||
        rt_attribute_binding *texture_bindings = NULL;
 | 
			
		||||
        if (tmp.texture_binding_count > 0) {
 | 
			
		||||
            texture_bindings = (vy_attribute_binding *)(info + 1);
 | 
			
		||||
            texture_bindings = (rt_attribute_binding *)(info + 1);
 | 
			
		||||
            memcpy(texture_bindings,
 | 
			
		||||
                   tmp.texture_bindings,
 | 
			
		||||
                   sizeof(vy_attribute_binding) * tmp.texture_binding_count);
 | 
			
		||||
                   sizeof(rt_attribute_binding) * tmp.texture_binding_count);
 | 
			
		||||
        }
 | 
			
		||||
        vy_attribute_binding *uniform_bindings = NULL;
 | 
			
		||||
        rt_attribute_binding *uniform_bindings = NULL;
 | 
			
		||||
        if (tmp.uniform_binding_count > 0) {
 | 
			
		||||
            uniform_bindings = texture_bindings + tmp.texture_binding_count;
 | 
			
		||||
            memcpy(uniform_bindings,
 | 
			
		||||
                   tmp.uniform_bindings,
 | 
			
		||||
                   sizeof(vy_attribute_binding) * tmp.uniform_binding_count);
 | 
			
		||||
                   sizeof(rt_attribute_binding) * tmp.uniform_binding_count);
 | 
			
		||||
        }
 | 
			
		||||
        vy_attribute_binding *storage_bindings = NULL;
 | 
			
		||||
        rt_attribute_binding *storage_bindings = NULL;
 | 
			
		||||
        if (tmp.storage_binding_count > 0) {
 | 
			
		||||
            storage_bindings = uniform_bindings + tmp.uniform_binding_count;
 | 
			
		||||
            memcpy(storage_bindings,
 | 
			
		||||
                   tmp.storage_bindings,
 | 
			
		||||
                   sizeof(vy_attribute_binding) * tmp.storage_binding_count);
 | 
			
		||||
                   sizeof(rt_attribute_binding) * tmp.storage_binding_count);
 | 
			
		||||
        }
 | 
			
		||||
        vySetRelptr(&info->texture_bindings, texture_bindings);
 | 
			
		||||
        vySetRelptr(&info->uniform_bindings, uniform_bindings);
 | 
			
		||||
        vySetRelptr(&info->storage_bindings, storage_bindings);
 | 
			
		||||
        rtSetRelptr(&info->texture_bindings, texture_bindings);
 | 
			
		||||
        rtSetRelptr(&info->uniform_bindings, uniform_bindings);
 | 
			
		||||
        rtSetRelptr(&info->storage_bindings, storage_bindings);
 | 
			
		||||
 | 
			
		||||
        vyReleaseBuffer(tmp.texture_bindings,
 | 
			
		||||
                        sizeof(vy_attribute_binding) * tmp.texture_binding_count);
 | 
			
		||||
        vyReleaseBuffer(tmp.storage_bindings,
 | 
			
		||||
                        sizeof(vy_attribute_binding) * tmp.storage_binding_count);
 | 
			
		||||
        vyReleaseBuffer(tmp.uniform_bindings,
 | 
			
		||||
                        sizeof(vy_attribute_binding) * tmp.uniform_binding_count);
 | 
			
		||||
        rtReleaseBuffer(tmp.texture_bindings,
 | 
			
		||||
                        sizeof(rt_attribute_binding) * tmp.texture_binding_count);
 | 
			
		||||
        rtReleaseBuffer(tmp.storage_bindings,
 | 
			
		||||
                        sizeof(rt_attribute_binding) * tmp.storage_binding_count);
 | 
			
		||||
        rtReleaseBuffer(tmp.uniform_bindings,
 | 
			
		||||
                        sizeof(rt_attribute_binding) * tmp.uniform_binding_count);
 | 
			
		||||
 | 
			
		||||
        output->data      = out_buffer;
 | 
			
		||||
        output->size      = outbuffer_size;
 | 
			
		||||
        output->asset_uid = vyCalculateUID(vyGetFilePath(file));
 | 
			
		||||
        output->asset_uid = rtCalculateUID(rtGetFilePath(file));
 | 
			
		||||
 | 
			
		||||
        /* Store dependencies to shaders */
 | 
			
		||||
        if (info->vertex_shader != VY_INVALID_UID)
 | 
			
		||||
            result = vyAddAssetDependency(output->asset_uid, info->vertex_shader);
 | 
			
		||||
        if (info->fragment_shader != VY_INVALID_UID)
 | 
			
		||||
            result = vyAddAssetDependency(output->asset_uid, info->fragment_shader);
 | 
			
		||||
        if (info->compute_shader != VY_INVALID_UID)
 | 
			
		||||
            result = vyAddAssetDependency(output->asset_uid, info->compute_shader);
 | 
			
		||||
        if (info->vertex_shader != RT_INVALID_UID)
 | 
			
		||||
            result = rtAddAssetDependency(output->asset_uid, info->vertex_shader);
 | 
			
		||||
        if (info->fragment_shader != RT_INVALID_UID)
 | 
			
		||||
            result = rtAddAssetDependency(output->asset_uid, info->fragment_shader);
 | 
			
		||||
        if (info->compute_shader != RT_INVALID_UID)
 | 
			
		||||
            result = rtAddAssetDependency(output->asset_uid, info->compute_shader);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
@ -1,46 +1,46 @@
 | 
			
		||||
#ifndef VY_ASSETC_PROCESSING_H
 | 
			
		||||
#define VY_ASSETC_PROCESSING_H
 | 
			
		||||
#ifndef RT_ASSETC_PROCESSING_H
 | 
			
		||||
#define RT_ASSETC_PROCESSING_H
 | 
			
		||||
 | 
			
		||||
#include "runtime/assets.h"
 | 
			
		||||
#include "runtime/file_tab.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_PROCESSING_FAILED = VY_CUSTOM_ERROR_START,
 | 
			
		||||
    RT_PROCESSING_FAILED = RT_CUSTOM_ERROR_START,
 | 
			
		||||
    /* Used if the processing depends on other files beeing processed first. */
 | 
			
		||||
    VY_PROCESSING_TRY_AGAIN,
 | 
			
		||||
    RT_PROCESSING_TRY_AGAIN,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id output_file;
 | 
			
		||||
    rt_file_id output_file;
 | 
			
		||||
 | 
			
		||||
} vy_asset_options;
 | 
			
		||||
} rt_asset_options;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_uid asset_uid;
 | 
			
		||||
    rt_uid asset_uid;
 | 
			
		||||
 | 
			
		||||
    /* Allocated via the vyAllocBuffer API */
 | 
			
		||||
    /* Allocated via the rtAllocBuffer API */
 | 
			
		||||
    void *data;
 | 
			
		||||
    size_t size;
 | 
			
		||||
} vy_processor_output;
 | 
			
		||||
} rt_processor_output;
 | 
			
		||||
 | 
			
		||||
typedef vy_result vy_processor_fn(vy_file_id file,
 | 
			
		||||
typedef rt_result rt_processor_fn(rt_file_id file,
 | 
			
		||||
                                  void *buffer,
 | 
			
		||||
                                  size_t size,
 | 
			
		||||
                                  uint32_t flags,
 | 
			
		||||
                                  vy_processor_output *output);
 | 
			
		||||
                                  rt_processor_output *output);
 | 
			
		||||
 | 
			
		||||
vy_result vyAddAssetProcessor(const char *file_extension, vy_processor_fn fn);
 | 
			
		||||
rt_result rtAddAssetProcessor(const char *file_extension, rt_processor_fn fn);
 | 
			
		||||
 | 
			
		||||
/* Flags are file type specific */
 | 
			
		||||
vy_result vyAddFileToProcessingQueue(vy_file_id file, uint32_t flags);
 | 
			
		||||
rt_result rtAddFileToProcessingQueue(rt_file_id file, uint32_t flags);
 | 
			
		||||
 | 
			
		||||
vy_result vyStartProcessing(void);
 | 
			
		||||
void vyStopProcessing(void);
 | 
			
		||||
rt_result rtStartProcessing(void);
 | 
			
		||||
void rtStopProcessing(void);
 | 
			
		||||
 | 
			
		||||
vy_uid vyCalculateUID(const char *name);
 | 
			
		||||
vy_result vyWriteUIDTab(void);
 | 
			
		||||
vy_result vyAddUIDTabEntry(vy_file_id package_fid, vy_uid uid, uint64_t offset, uint64_t size);
 | 
			
		||||
rt_uid rtCalculateUID(const char *name);
 | 
			
		||||
rt_result rtWriteUIDTab(void);
 | 
			
		||||
rt_result rtAddUIDTabEntry(rt_file_id package_fid, rt_uid uid, uint64_t offset, uint64_t size);
 | 
			
		||||
 | 
			
		||||
void vyWaitUntilProcessingIsFinished(void);
 | 
			
		||||
void rtWaitUntilProcessingIsFinished(void);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -1,19 +1,19 @@
 | 
			
		||||
#ifndef VY_ASSETC_PROCESSING_FLAGS_H
 | 
			
		||||
#define VY_ASSETC_PROCESSING_FLAGS_H
 | 
			
		||||
#ifndef RT_ASSETC_PROCESSING_FLAGS_H
 | 
			
		||||
#define RT_ASSETC_PROCESSING_FLAGS_H
 | 
			
		||||
 | 
			
		||||
/* Shader processing flags */
 | 
			
		||||
enum {
 | 
			
		||||
    /* Type is encoded in the lower bits */
 | 
			
		||||
    VY_SHADER_FLAG_VERTEX   = 0x01,
 | 
			
		||||
    VY_SHADER_FLAG_FRAGMENT = 0x02,
 | 
			
		||||
    VY_SHADER_FLAG_COMPUTE  = 0x03,
 | 
			
		||||
    RT_SHADER_FLAG_VERTEX   = 0x01,
 | 
			
		||||
    RT_SHADER_FLAG_FRAGMENT = 0x02,
 | 
			
		||||
    RT_SHADER_FLAG_COMPUTE  = 0x03,
 | 
			
		||||
 | 
			
		||||
    VY_SHADER_FLAG_TYPE_MASK =
 | 
			
		||||
        VY_SHADER_FLAG_VERTEX | VY_SHADER_FLAG_FRAGMENT | VY_SHADER_FLAG_COMPUTE,
 | 
			
		||||
    RT_SHADER_FLAG_TYPE_MASK =
 | 
			
		||||
        RT_SHADER_FLAG_VERTEX | RT_SHADER_FLAG_FRAGMENT | RT_SHADER_FLAG_COMPUTE,
 | 
			
		||||
 | 
			
		||||
    VY_SHADER_FLAG_OPTIMIZE_SPEED = 0x04,
 | 
			
		||||
    VY_SHADER_FLAG_OPTIMIZE_SIZE  = 0x08,
 | 
			
		||||
    VY_SHADER_FLAG_OPTIMIZE_MASK  = VY_SHADER_FLAG_OPTIMIZE_SPEED | VY_SHADER_FLAG_OPTIMIZE_SIZE,
 | 
			
		||||
    RT_SHADER_FLAG_OPTIMIZE_SPEED = 0x04,
 | 
			
		||||
    RT_SHADER_FLAG_OPTIMIZE_SIZE  = 0x08,
 | 
			
		||||
    RT_SHADER_FLAG_OPTIMIZE_MASK  = RT_SHADER_FLAG_OPTIMIZE_SPEED | RT_SHADER_FLAG_OPTIMIZE_SIZE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,26 +17,26 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_id fid;
 | 
			
		||||
    rt_file_id fid;
 | 
			
		||||
 | 
			
		||||
    uint32_t flags;
 | 
			
		||||
 | 
			
		||||
    /* How many times has this file been added? */
 | 
			
		||||
    unsigned int turn;
 | 
			
		||||
} vy_file_processing_queue_entry;
 | 
			
		||||
} rt_file_processing_queue_entry;
 | 
			
		||||
 | 
			
		||||
#define QUEUE_LENGTH 1024
 | 
			
		||||
typedef struct {
 | 
			
		||||
    vy_file_processing_queue_entry entries[QUEUE_LENGTH];
 | 
			
		||||
    rt_file_processing_queue_entry entries[QUEUE_LENGTH];
 | 
			
		||||
    unsigned int head;
 | 
			
		||||
    unsigned int tail;
 | 
			
		||||
} vy_file_processing_queue;
 | 
			
		||||
} rt_file_processing_queue;
 | 
			
		||||
 | 
			
		||||
static vy_file_processing_queue _queues[2];
 | 
			
		||||
static vy_file_processing_queue *_processing_queue;
 | 
			
		||||
static vy_file_processing_queue *_retry_queue;
 | 
			
		||||
static rt_file_processing_queue _queues[2];
 | 
			
		||||
static rt_file_processing_queue *_processing_queue;
 | 
			
		||||
static rt_file_processing_queue *_retry_queue;
 | 
			
		||||
 | 
			
		||||
static vy_mutex *_guard;
 | 
			
		||||
static rt_mutex *_guard;
 | 
			
		||||
static bool _keep_running;
 | 
			
		||||
 | 
			
		||||
/* A single file could have a lot of dependencies. */
 | 
			
		||||
@ -47,20 +47,20 @@ static bool _keep_running;
 | 
			
		||||
#define FORCE_SINGLE_THREAD 1
 | 
			
		||||
 | 
			
		||||
static unsigned int _num_processing_threads = 0;
 | 
			
		||||
static vy_thread *_processing_threads[MAX_PROCESSING_THREADS];
 | 
			
		||||
static rt_thread *_processing_threads[MAX_PROCESSING_THREADS];
 | 
			
		||||
 | 
			
		||||
static unsigned int _processing_thread_count = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static vy_result vyAddFileToProcessingQueueImpl(vy_file_processing_queue *queue,
 | 
			
		||||
                                                vy_file_id file,
 | 
			
		||||
static rt_result rtAddFileToProcessingQueueImpl(rt_file_processing_queue *queue,
 | 
			
		||||
                                                rt_file_id file,
 | 
			
		||||
                                                uint32_t flags,
 | 
			
		||||
                                                unsigned int turn) {
 | 
			
		||||
    vy_result result = VY_SUCCESS;
 | 
			
		||||
    rt_result result = RT_SUCCESS;
 | 
			
		||||
 | 
			
		||||
    vyLog("ASSETC", "Adding %s to processing queue.", vyGetFilePath(file));
 | 
			
		||||
    rtLog("ASSETC", "Adding %s to processing queue.", rtGetFilePath(file));
 | 
			
		||||
 | 
			
		||||
    vy_file_processing_queue_entry entry = {
 | 
			
		||||
    rt_file_processing_queue_entry entry = {
 | 
			
		||||
        .fid           = file,
 | 
			
		||||
        .flags         = flags,
 | 
			
		||||
        .turn          = turn,
 | 
			
		||||
@ -70,42 +70,42 @@ static vy_result vyAddFileToProcessingQueueImpl(vy_file_processing_queue *queue,
 | 
			
		||||
        queue->entries[slot]    = entry;
 | 
			
		||||
        queue->head                      = (queue->head + 1) % QUEUE_LENGTH;
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("ASSETC", "The processing queue is full!");
 | 
			
		||||
        rtReportError("ASSETC", "The processing queue is full!");
 | 
			
		||||
        result = 1;
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyAddFileToProcessingQueue(vy_file_id file, uint32_t flags) {
 | 
			
		||||
rt_result rtAddFileToProcessingQueue(rt_file_id file, uint32_t flags) {
 | 
			
		||||
    assert(_guard != NULL);
 | 
			
		||||
 | 
			
		||||
    vyLockMutex(_guard);
 | 
			
		||||
    vy_result res = vyAddFileToProcessingQueueImpl(_processing_queue, file, flags, 1);
 | 
			
		||||
    vyUnlockMutex(_guard);
 | 
			
		||||
    rtLockMutex(_guard);
 | 
			
		||||
    rt_result res = rtAddFileToProcessingQueueImpl(_processing_queue, file, flags, 1);
 | 
			
		||||
    rtUnlockMutex(_guard);
 | 
			
		||||
    return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define MAX_PROCESSORS 256
 | 
			
		||||
static vy_processor_fn *_processor_fns[MAX_PROCESSORS];
 | 
			
		||||
static rt_processor_fn *_processor_fns[MAX_PROCESSORS];
 | 
			
		||||
static const char *_processor_exts[MAX_PROCESSORS];
 | 
			
		||||
static unsigned int _processor_count;
 | 
			
		||||
 | 
			
		||||
vy_result vyAddAssetProcessor(const char *file_extension, vy_processor_fn fn) {
 | 
			
		||||
rt_result rtAddAssetProcessor(const char *file_extension, rt_processor_fn fn) {
 | 
			
		||||
    /* Should only be called from main thread */
 | 
			
		||||
    if (_processor_count == MAX_PROCESSORS) {
 | 
			
		||||
        vyReportError("ASSETC", "Too many asset processor functions!");
 | 
			
		||||
        rtReportError("ASSETC", "Too many asset processor functions!");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    _processor_fns[_processor_count]  = fn;
 | 
			
		||||
    _processor_exts[_processor_count] = file_extension;
 | 
			
		||||
    ++_processor_count;
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void PopAndSwapSubmittedData(unsigned int at,
 | 
			
		||||
                                    unsigned int *count,
 | 
			
		||||
                                    vy_file_processing_queue_entry *queue_entries,
 | 
			
		||||
                                    vy_aio_handle *handles,
 | 
			
		||||
                                    rt_file_processing_queue_entry *queue_entries,
 | 
			
		||||
                                    rt_aio_handle *handles,
 | 
			
		||||
                                    void **buffers,
 | 
			
		||||
                                    size_t *sizes) {
 | 
			
		||||
    if (at < *count - 1) {
 | 
			
		||||
@ -117,9 +117,9 @@ static void PopAndSwapSubmittedData(unsigned int at,
 | 
			
		||||
    *count = *count - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static vy_result ProcessLoadedFile(vy_file_processing_queue_entry entry, void *buffer, size_t size) {
 | 
			
		||||
static rt_result ProcessLoadedFile(rt_file_processing_queue_entry entry, void *buffer, size_t size) {
 | 
			
		||||
    /* Search for a matching processor function */
 | 
			
		||||
    const char *path = vyGetFilePath(entry.fid);
 | 
			
		||||
    const char *path = rtGetFilePath(entry.fid);
 | 
			
		||||
    size_t path_len  = strlen(path);
 | 
			
		||||
    for (unsigned int i = 0; i < _processor_count; ++i) {
 | 
			
		||||
        size_t ext_len = strlen(_processor_exts[i]);
 | 
			
		||||
@ -132,97 +132,97 @@ static vy_result ProcessLoadedFile(vy_file_processing_queue_entry entry, void *b
 | 
			
		||||
            /* Load the corresponding .as file.
 | 
			
		||||
             * TODO: Using malloc here is probably relatively slow.
 | 
			
		||||
             */
 | 
			
		||||
            vy_result res;
 | 
			
		||||
            rt_result res;
 | 
			
		||||
 | 
			
		||||
            vy_asset_settings settings;
 | 
			
		||||
            if ((res = vyLoadAssetSettings(path, &settings)) != VY_SUCCESS) {
 | 
			
		||||
            rt_asset_settings settings;
 | 
			
		||||
            if ((res = rtLoadAssetSettings(path, &settings)) != RT_SUCCESS) {
 | 
			
		||||
                return res;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /* Process the asset */
 | 
			
		||||
            vy_processor_output out;
 | 
			
		||||
            rt_processor_output out;
 | 
			
		||||
            res = _processor_fns[i](entry.fid, buffer, size, entry.flags, &out);
 | 
			
		||||
            if (res == VY_SUCCESS) {
 | 
			
		||||
            if (res == RT_SUCCESS) {
 | 
			
		||||
                /* Add the output to the appropriate package file */
 | 
			
		||||
                vy_assetmeta meta;
 | 
			
		||||
                meta.compiled_ts  = vyGetCurrentTimestamp();
 | 
			
		||||
                meta.last_changed = vyGetFileModificationTimestamp(entry.fid);
 | 
			
		||||
                rt_assetmeta meta;
 | 
			
		||||
                meta.compiled_ts  = rtGetCurrentTimestamp();
 | 
			
		||||
                meta.last_changed = rtGetFileModificationTimestamp(entry.fid);
 | 
			
		||||
                meta.processing_flags = entry.flags;
 | 
			
		||||
                vyAddUIDMapping(entry.fid, out.asset_uid, &meta);
 | 
			
		||||
                rtAddUIDMapping(entry.fid, out.asset_uid, &meta);
 | 
			
		||||
 | 
			
		||||
                vyAddAssetToPackage(settings.package, out.asset_uid, out.data, out.size);
 | 
			
		||||
            } else if (res == VY_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
                rtAddAssetToPackage(settings.package, out.asset_uid, out.data, out.size);
 | 
			
		||||
            } else if (res == RT_PROCESSING_TRY_AGAIN) {
 | 
			
		||||
                if (entry.turn < MAX_TURNS) {
 | 
			
		||||
                    vyLockMutex(_guard);
 | 
			
		||||
                    vyAddFileToProcessingQueueImpl(_retry_queue, entry.fid, entry.flags, entry.turn + 1);
 | 
			
		||||
                    vyUnlockMutex(_guard);
 | 
			
		||||
                    rtLockMutex(_guard);
 | 
			
		||||
                    rtAddFileToProcessingQueueImpl(_retry_queue, entry.fid, entry.flags, entry.turn + 1);
 | 
			
		||||
                    rtUnlockMutex(_guard);
 | 
			
		||||
                } else {
 | 
			
		||||
                    vyLog("ASSETC",
 | 
			
		||||
                    rtLog("ASSETC",
 | 
			
		||||
                          "File '%s' took too many turns to process: %u",
 | 
			
		||||
                          path,
 | 
			
		||||
                          entry.turn);
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                vyLog("ASSETC", "Failed to process file: %s  (Result %u)", path, res);
 | 
			
		||||
                rtLog("ASSETC", "Failed to process file: %s  (Result %u)", path, res);
 | 
			
		||||
            }
 | 
			
		||||
            return res;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyLog("ASSETC", "No asset processor for file: %s", path);
 | 
			
		||||
    return VY_UNKNOWN_ERROR;
 | 
			
		||||
    rtLog("ASSETC", "No asset processor for file: %s", path);
 | 
			
		||||
    return RT_UNKNOWN_ERROR;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void ProcessingThread(void *_param) {
 | 
			
		||||
    VY_UNUSED(_param);
 | 
			
		||||
    RT_UNUSED(_param);
 | 
			
		||||
 | 
			
		||||
    vy_file_processing_queue_entry submitted_entries[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    vy_aio_handle submitted_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    void *submitted_buffers[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    size_t submitted_sizes[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    rt_file_processing_queue_entry submitted_entries[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    rt_aio_handle submitted_handles[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    void *submitted_buffers[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    size_t submitted_sizes[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
    unsigned int submitted_outstanding = 0;
 | 
			
		||||
 | 
			
		||||
    while (_keep_running) {
 | 
			
		||||
        vy_load_batch load_batch;
 | 
			
		||||
        vy_file_processing_queue_entry load_entries[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        void *load_buffers[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        size_t load_sizes[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        rt_load_batch load_batch;
 | 
			
		||||
        rt_file_processing_queue_entry load_entries[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        void *load_buffers[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        size_t load_sizes[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        load_batch.num_loads = 0;
 | 
			
		||||
 | 
			
		||||
        bool got_entry = false;
 | 
			
		||||
        do {
 | 
			
		||||
            got_entry = false;
 | 
			
		||||
            vy_file_processing_queue_entry entry = {0};
 | 
			
		||||
            vyLockMutex(_guard);
 | 
			
		||||
            rt_file_processing_queue_entry entry = {0};
 | 
			
		||||
            rtLockMutex(_guard);
 | 
			
		||||
            if (_processing_queue->head != _processing_queue->tail) {
 | 
			
		||||
                entry                  = _processing_queue->entries[_processing_queue->tail];
 | 
			
		||||
                _processing_queue->tail = (_processing_queue->tail + 1) % QUEUE_LENGTH;
 | 
			
		||||
                got_entry              = true;
 | 
			
		||||
            } else if (load_batch.num_loads == 0) {
 | 
			
		||||
                /* Switch the queues -> Retry all the entries that returned VY_PROCESSING_TRY_AGAIN */
 | 
			
		||||
                /* Switch the queues -> Retry all the entries that returned RT_PROCESSING_TRY_AGAIN */
 | 
			
		||||
                if (_retry_queue->head != _retry_queue->tail) {
 | 
			
		||||
                    vy_file_processing_queue *tmp = _retry_queue;
 | 
			
		||||
                    rt_file_processing_queue *tmp = _retry_queue;
 | 
			
		||||
                    _retry_queue                  = _processing_queue;
 | 
			
		||||
                    _processing_queue             = tmp;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
            
 | 
			
		||||
            /* Retry, if we did not get an entry */
 | 
			
		||||
            if (!got_entry)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            const char *path = vyGetFilePath(entry.fid);
 | 
			
		||||
            const char *path = rtGetFilePath(entry.fid);
 | 
			
		||||
            if (!path) {
 | 
			
		||||
                vyLog("ASSETC", "Invalid file id: %#x", entry.fid);
 | 
			
		||||
                rtLog("ASSETC", "Invalid file id: %#x", entry.fid);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            vyLog("ASSETC", "Processing %s", path);
 | 
			
		||||
            rtLog("ASSETC", "Processing %s", path);
 | 
			
		||||
 | 
			
		||||
            size_t fsz = vyGetFileSize(path);
 | 
			
		||||
            void *dest = vyAllocBuffer(fsz);
 | 
			
		||||
            size_t fsz = rtGetFileSize(path);
 | 
			
		||||
            void *dest = rtAllocBuffer(fsz);
 | 
			
		||||
            if (!dest) {
 | 
			
		||||
                vyLog("ASSETC", "Ran out of memory for loading the file: %s", path);
 | 
			
		||||
                rtLog("ASSETC", "Ran out of memory for loading the file: %s", path);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            memset(dest, 0, fsz);
 | 
			
		||||
@ -235,34 +235,34 @@ static void ProcessingThread(void *_param) {
 | 
			
		||||
            load_batch.loads[load_batch.num_loads].offset    = 0;
 | 
			
		||||
            load_entries[load_batch.num_loads]               = entry;
 | 
			
		||||
            ++load_batch.num_loads;
 | 
			
		||||
        } while (got_entry && load_batch.num_loads < VY_LOAD_BATCH_MAX_SIZE);
 | 
			
		||||
        } while (got_entry && load_batch.num_loads < RT_LOAD_BATCH_MAX_SIZE);
 | 
			
		||||
 | 
			
		||||
        vy_aio_handle load_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        rt_aio_handle load_handles[RT_LOAD_BATCH_MAX_SIZE];
 | 
			
		||||
        if (load_batch.num_loads > 0) {
 | 
			
		||||
            vy_result submit_result = vySubmitLoadBatch(&load_batch, load_handles);
 | 
			
		||||
            if (submit_result != VY_SUCCESS) {
 | 
			
		||||
                vyLog("ASSETC", "SubmitLoadBatch failed: %u", submit_result);
 | 
			
		||||
            rt_result submit_result = rtSubmitLoadBatch(&load_batch, load_handles);
 | 
			
		||||
            if (submit_result != RT_SUCCESS) {
 | 
			
		||||
                rtLog("ASSETC", "SubmitLoadBatch failed: %u", submit_result);
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Process the previously submitted loads */
 | 
			
		||||
        while (submitted_outstanding > 0) {
 | 
			
		||||
            vyLockMutex(_guard);
 | 
			
		||||
            rtLockMutex(_guard);
 | 
			
		||||
            _processing_thread_count += 1;
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
 | 
			
		||||
            for (unsigned int i = 0; i < submitted_outstanding; ++i) {
 | 
			
		||||
                vy_aio_state state = vyGetAIOState(submitted_handles[i]);
 | 
			
		||||
                rt_aio_state state = rtGetAIOState(submitted_handles[i]);
 | 
			
		||||
                switch (state) {
 | 
			
		||||
                case VY_AIO_STATE_PENDING:
 | 
			
		||||
                case RT_AIO_STATE_PENDING:
 | 
			
		||||
                    continue;
 | 
			
		||||
                case VY_AIO_STATE_FAILED:
 | 
			
		||||
                    vyLog("ASSETC",
 | 
			
		||||
                case RT_AIO_STATE_FAILED:
 | 
			
		||||
                    rtLog("ASSETC",
 | 
			
		||||
                          "Loading file %s failed.",
 | 
			
		||||
                          vyGetFilePath(submitted_entries[i].fid));
 | 
			
		||||
                    vyReleaseAIO(submitted_handles[i]);
 | 
			
		||||
                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                          rtGetFilePath(submitted_entries[i].fid));
 | 
			
		||||
                    rtReleaseAIO(submitted_handles[i]);
 | 
			
		||||
                    rtReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                    PopAndSwapSubmittedData(i,
 | 
			
		||||
                                            &submitted_outstanding,
 | 
			
		||||
                                            submitted_entries,
 | 
			
		||||
@ -271,11 +271,11 @@ static void ProcessingThread(void *_param) {
 | 
			
		||||
                                            submitted_sizes);
 | 
			
		||||
                    --i;
 | 
			
		||||
                    break;
 | 
			
		||||
                case VY_AIO_STATE_INVALID:
 | 
			
		||||
                    vyLog("ASSETC",
 | 
			
		||||
                case RT_AIO_STATE_INVALID:
 | 
			
		||||
                    rtLog("ASSETC",
 | 
			
		||||
                          "Got invalid AIO handle for file: %s",
 | 
			
		||||
                          vyGetFilePath(submitted_entries[i].fid));
 | 
			
		||||
                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                          rtGetFilePath(submitted_entries[i].fid));
 | 
			
		||||
                    rtReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                    PopAndSwapSubmittedData(i,
 | 
			
		||||
                                            &submitted_outstanding,
 | 
			
		||||
                                            submitted_entries,
 | 
			
		||||
@ -284,12 +284,12 @@ static void ProcessingThread(void *_param) {
 | 
			
		||||
                                            submitted_sizes);
 | 
			
		||||
                    --i;
 | 
			
		||||
                    break;
 | 
			
		||||
                case VY_AIO_STATE_FINISHED:
 | 
			
		||||
                case RT_AIO_STATE_FINISHED:
 | 
			
		||||
                    ProcessLoadedFile(submitted_entries[i],
 | 
			
		||||
                                      submitted_buffers[i],
 | 
			
		||||
                                      submitted_sizes[i]);
 | 
			
		||||
                    vyReleaseAIO(submitted_handles[i]);
 | 
			
		||||
                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                    rtReleaseAIO(submitted_handles[i]);
 | 
			
		||||
                    rtReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
			
		||||
                    PopAndSwapSubmittedData(i,
 | 
			
		||||
                                            &submitted_outstanding,
 | 
			
		||||
                                            submitted_entries,
 | 
			
		||||
@ -300,9 +300,9 @@ static void ProcessingThread(void *_param) {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            vyLockMutex(_guard);
 | 
			
		||||
            rtLockMutex(_guard);
 | 
			
		||||
            _processing_thread_count -= 1;
 | 
			
		||||
            vyUnlockMutex(_guard);
 | 
			
		||||
            rtUnlockMutex(_guard);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Start new round */
 | 
			
		||||
@ -318,12 +318,12 @@ static void ProcessingThread(void *_param) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyStartProcessing(void) {
 | 
			
		||||
rt_result rtStartProcessing(void) {
 | 
			
		||||
    if (!_guard)
 | 
			
		||||
        _guard = vyCreateMutex();
 | 
			
		||||
        _guard = rtCreateMutex();
 | 
			
		||||
 | 
			
		||||
#if !FORCE_SINGLE_THREAD
 | 
			
		||||
    _num_processing_threads     = vyGetCPUCoreCount();
 | 
			
		||||
    _num_processing_threads     = rtGetCPUCoreCount();
 | 
			
		||||
    if (_num_processing_threads > MAX_PROCESSING_THREADS)
 | 
			
		||||
        _num_processing_threads = MAX_PROCESSING_THREADS;
 | 
			
		||||
#else
 | 
			
		||||
@ -335,20 +335,20 @@ vy_result vyStartProcessing(void) {
 | 
			
		||||
 | 
			
		||||
    _keep_running               = true;
 | 
			
		||||
    for (unsigned int i = 0; i < _num_processing_threads; ++i) {
 | 
			
		||||
        _processing_threads[i] = vySpawnThread(ProcessingThread, NULL, "Processor");
 | 
			
		||||
        _processing_threads[i] = rtSpawnThread(ProcessingThread, NULL, "Processor");
 | 
			
		||||
        if (!_processing_threads[i]) {
 | 
			
		||||
            vyReportError("ASSETC", "Failed to spawn processing thread %u!", i);
 | 
			
		||||
            rtReportError("ASSETC", "Failed to spawn processing thread %u!", i);
 | 
			
		||||
            _keep_running = false;
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vyStopProcessing(void) {
 | 
			
		||||
void rtStopProcessing(void) {
 | 
			
		||||
    _keep_running = false;
 | 
			
		||||
    for (unsigned int i = 0; i < _num_processing_threads; ++i)
 | 
			
		||||
        vyJoinThread(_processing_threads[i]);
 | 
			
		||||
        rtJoinThread(_processing_threads[i]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -360,7 +360,7 @@ void vyStopProcessing(void) {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void vyWaitUntilProcessingIsFinished(void) {
 | 
			
		||||
void rtWaitUntilProcessingIsFinished(void) {
 | 
			
		||||
    unsigned int done_counter = 0;
 | 
			
		||||
    while (done_counter < 3) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
@ -368,11 +368,11 @@ void vyWaitUntilProcessingIsFinished(void) {
 | 
			
		||||
#else
 | 
			
		||||
        sleep(1);
 | 
			
		||||
#endif
 | 
			
		||||
        vyLockMutex(_guard);
 | 
			
		||||
        rtLockMutex(_guard);
 | 
			
		||||
        volatile bool done = _processing_queue->head == _processing_queue->tail &&
 | 
			
		||||
                             _retry_queue->head == _retry_queue->tail &&
 | 
			
		||||
                             _processing_thread_count == 0;
 | 
			
		||||
        vyUnlockMutex(_guard);
 | 
			
		||||
        rtUnlockMutex(_guard);
 | 
			
		||||
        if (done)
 | 
			
		||||
            ++done_counter;
 | 
			
		||||
        else
 | 
			
		||||
 | 
			
		||||
@ -21,27 +21,27 @@ static shaderc_include_result *ResolveInclude(void *user_data,
 | 
			
		||||
static void ReleaseIncludeResult(void *user_data, shaderc_include_result *result) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
rt_result rtProcessShaderFile(rt_file_id file,
 | 
			
		||||
                              void *buffer,
 | 
			
		||||
                              size_t size,
 | 
			
		||||
                              uint32_t flags,
 | 
			
		||||
                              vy_processor_output *output) {
 | 
			
		||||
                              rt_processor_output *output) {
 | 
			
		||||
    /* If we determine that shader compilation takes too long, we can instead
 | 
			
		||||
     * keep the compiler around */
 | 
			
		||||
 | 
			
		||||
    shaderc_compiler_t compiler = shaderc_compiler_initialize();
 | 
			
		||||
    if (!compiler) {
 | 
			
		||||
        vyLog("ASSETC", "Failed to initialize the shaderc compiler.");
 | 
			
		||||
        return VY_PROCESSING_FAILED;
 | 
			
		||||
        rtLog("ASSETC", "Failed to initialize the shaderc compiler.");
 | 
			
		||||
        return RT_PROCESSING_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const char *path = vyGetFilePath(file);
 | 
			
		||||
    const char *path = rtGetFilePath(file);
 | 
			
		||||
 | 
			
		||||
    shaderc_compile_options_t options = shaderc_compile_options_initialize();
 | 
			
		||||
    if (!options) {
 | 
			
		||||
        vyLog("ASSETC", "Failed to initialize shader compile options.");
 | 
			
		||||
        rtLog("ASSETC", "Failed to initialize shader compile options.");
 | 
			
		||||
        shaderc_compiler_release(compiler);
 | 
			
		||||
        return VY_PROCESSING_FAILED;
 | 
			
		||||
        return RT_PROCESSING_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    shaderc_compile_options_set_include_callbacks(options,
 | 
			
		||||
@ -49,32 +49,32 @@ vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
                                                  ReleaseIncludeResult,
 | 
			
		||||
                                                  NULL);
 | 
			
		||||
 | 
			
		||||
    uint32_t optimize_from_flags = flags & VY_SHADER_FLAG_OPTIMIZE_MASK;
 | 
			
		||||
    if (optimize_from_flags == VY_SHADER_FLAG_OPTIMIZE_SPEED)
 | 
			
		||||
    uint32_t optimize_from_flags = flags & RT_SHADER_FLAG_OPTIMIZE_MASK;
 | 
			
		||||
    if (optimize_from_flags == RT_SHADER_FLAG_OPTIMIZE_SPEED)
 | 
			
		||||
        shaderc_compile_options_set_optimization_level(options,
 | 
			
		||||
                                                       shaderc_optimization_level_performance);
 | 
			
		||||
    else if (optimize_from_flags == VY_SHADER_FLAG_OPTIMIZE_SIZE)
 | 
			
		||||
    else if (optimize_from_flags == RT_SHADER_FLAG_OPTIMIZE_SIZE)
 | 
			
		||||
        shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_size);
 | 
			
		||||
    else
 | 
			
		||||
        shaderc_compile_options_set_optimization_level(options, shaderc_optimization_level_zero);
 | 
			
		||||
 | 
			
		||||
    uint32_t type_from_flags = flags & VY_SHADER_FLAG_TYPE_MASK;
 | 
			
		||||
    uint32_t type_from_flags = flags & RT_SHADER_FLAG_TYPE_MASK;
 | 
			
		||||
    shaderc_shader_kind shaderc_kind;
 | 
			
		||||
    switch (type_from_flags) {
 | 
			
		||||
    case VY_SHADER_FLAG_VERTEX:
 | 
			
		||||
    case RT_SHADER_FLAG_VERTEX:
 | 
			
		||||
        shaderc_kind = shaderc_glsl_vertex_shader;
 | 
			
		||||
        break;
 | 
			
		||||
    case VY_SHADER_FLAG_FRAGMENT:
 | 
			
		||||
    case RT_SHADER_FLAG_FRAGMENT:
 | 
			
		||||
        shaderc_kind = shaderc_glsl_fragment_shader;
 | 
			
		||||
        break;
 | 
			
		||||
    case VY_SHADER_FLAG_COMPUTE:
 | 
			
		||||
    case RT_SHADER_FLAG_COMPUTE:
 | 
			
		||||
        shaderc_kind = shaderc_glsl_compute_shader;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        vyLog("ASSETC", "Invalid shader stage flag %u", type_from_flags);
 | 
			
		||||
        rtLog("ASSETC", "Invalid shader stage flag %u", type_from_flags);
 | 
			
		||||
        shaderc_compile_options_release(options);
 | 
			
		||||
        shaderc_compiler_release(compiler);
 | 
			
		||||
        return VY_PROCESSING_FAILED;
 | 
			
		||||
        return RT_PROCESSING_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler,
 | 
			
		||||
@ -89,7 +89,7 @@ vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
    shaderc_compilation_status status = shaderc_result_get_compilation_status(result);
 | 
			
		||||
    if (status != shaderc_compilation_status_success || shaderc_result_get_num_errors(result) > 0) {
 | 
			
		||||
 | 
			
		||||
        vyLog("ASSETC",
 | 
			
		||||
        rtLog("ASSETC",
 | 
			
		||||
              "Compilation of %s failed: %s",
 | 
			
		||||
              path,
 | 
			
		||||
              shaderc_result_get_error_message(result));
 | 
			
		||||
@ -97,17 +97,17 @@ vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
        shaderc_result_release(result);
 | 
			
		||||
        shaderc_compile_options_release(options);
 | 
			
		||||
        shaderc_compiler_release(compiler);
 | 
			
		||||
        return VY_PROCESSING_FAILED;
 | 
			
		||||
        return RT_PROCESSING_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    size_t output_size = shaderc_result_get_length(result);
 | 
			
		||||
    output->data       = vyAllocBuffer(output_size);
 | 
			
		||||
    output->data       = rtAllocBuffer(output_size);
 | 
			
		||||
    if (!output->data) {
 | 
			
		||||
        shaderc_result_release(result);
 | 
			
		||||
        shaderc_compile_options_release(options);
 | 
			
		||||
        shaderc_compiler_release(compiler);
 | 
			
		||||
        vyLog("ASSETC", "Failed to allocate %zu bytes for shader compilation output.", output_size);
 | 
			
		||||
        return VY_PROCESSING_FAILED;
 | 
			
		||||
        rtLog("ASSETC", "Failed to allocate %zu bytes for shader compilation output.", output_size);
 | 
			
		||||
        return RT_PROCESSING_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
    const uint32_t *spv_bytes = (uint32_t *)shaderc_result_get_bytes(result);
 | 
			
		||||
    memcpy(output->data, spv_bytes, output_size);
 | 
			
		||||
@ -117,7 +117,7 @@ vy_result vyProcessShaderFile(vy_file_id file,
 | 
			
		||||
    shaderc_compile_options_release(options);
 | 
			
		||||
    shaderc_compiler_release(compiler);
 | 
			
		||||
 | 
			
		||||
    output->asset_uid = vyCalculateUID(path);
 | 
			
		||||
    output->asset_uid = rtCalculateUID(path);
 | 
			
		||||
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
#include "processing.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
#define VY_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#define RT_DEFINE_UIDTAB_FILE_STRUCTURES
 | 
			
		||||
#include "runtime/threading.h"
 | 
			
		||||
#include "runtime/uidtab.h"
 | 
			
		||||
 | 
			
		||||
@ -11,25 +11,25 @@
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
 | 
			
		||||
static vy_uidtab_entry *_entries;
 | 
			
		||||
static rt_uidtab_entry *_entries;
 | 
			
		||||
static size_t _entry_capacity;
 | 
			
		||||
static size_t _entry_count;
 | 
			
		||||
 | 
			
		||||
vy_uid vyCalculateUID(const char *name) {
 | 
			
		||||
    assert(sizeof(XXH32_hash_t) == sizeof(vy_uid));
 | 
			
		||||
rt_uid rtCalculateUID(const char *name) {
 | 
			
		||||
    assert(sizeof(XXH32_hash_t) == sizeof(rt_uid));
 | 
			
		||||
 | 
			
		||||
    size_t len = strlen(name);
 | 
			
		||||
    return (vy_uid)XXH32(name, len, 0);
 | 
			
		||||
    return (rt_uid)XXH32(name, len, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyAddUIDTabEntry(vy_file_id package_fid, vy_uid uid, uint64_t offset, uint64_t size) {
 | 
			
		||||
    assert(vyIsMainThread());
 | 
			
		||||
rt_result rtAddUIDTabEntry(rt_file_id package_fid, rt_uid uid, uint64_t offset, uint64_t size) {
 | 
			
		||||
    assert(rtIsMainThread());
 | 
			
		||||
    
 | 
			
		||||
    if (_entry_count == _entry_capacity) {
 | 
			
		||||
        size_t new_cap = (_entry_capacity > 0) ? _entry_capacity * 2 : 256;
 | 
			
		||||
        void *t        = realloc(_entries, sizeof(vy_uidtab_entry) * new_cap);
 | 
			
		||||
        void *t        = realloc(_entries, sizeof(rt_uidtab_entry) * new_cap);
 | 
			
		||||
        if (!t)
 | 
			
		||||
            return VY_UNKNOWN_ERROR;
 | 
			
		||||
            return RT_UNKNOWN_ERROR;
 | 
			
		||||
        _entry_capacity = new_cap;
 | 
			
		||||
        _entries        = t;
 | 
			
		||||
    }
 | 
			
		||||
@ -38,32 +38,32 @@ vy_result vyAddUIDTabEntry(vy_file_id package_fid, vy_uid uid, uint64_t offset,
 | 
			
		||||
    _entries[_entry_count].size   = size;
 | 
			
		||||
    _entries[_entry_count].uid    = uid;
 | 
			
		||||
    _entry_count++;
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyWriteUIDTab(void) {
 | 
			
		||||
    vy_uidtab_header header;
 | 
			
		||||
    XXH64_hash_t checksum = XXH3_64bits(_entries, sizeof(vy_uidtab_entry) * _entry_count);
 | 
			
		||||
rt_result rtWriteUIDTab(void) {
 | 
			
		||||
    rt_uidtab_header header;
 | 
			
		||||
    XXH64_hash_t checksum = XXH3_64bits(_entries, sizeof(rt_uidtab_entry) * _entry_count);
 | 
			
		||||
    XXH64_canonicalFromHash(&header.checksum, checksum);
 | 
			
		||||
    header.num_entries = (uint32_t)_entry_count;
 | 
			
		||||
    
 | 
			
		||||
    FILE *f = fopen("data/uidtab.bin", "wb");
 | 
			
		||||
    if (!f) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to open 'uidtab.bin' for writing.");
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        rtReportError("ASSETC", "Failed to open 'uidtab.bin' for writing.");
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (fwrite(&header, sizeof(header), 1, f) != 1) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write header to 'uidtab.bin'");
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write header to 'uidtab.bin'");
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
    if (fwrite(_entries, sizeof(vy_uidtab_entry), _entry_count, f) != _entry_count) {
 | 
			
		||||
        vyReportError("ASSETC", "Failed to write entries to 'uidtab.bin'");
 | 
			
		||||
    if (fwrite(_entries, sizeof(rt_uidtab_entry), _entry_count, f) != _entry_count) {
 | 
			
		||||
        rtReportError("ASSETC", "Failed to write entries to 'uidtab.bin'");
 | 
			
		||||
        fclose(f);
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fclose(f);
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
    return RT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
size_t vyGetFileSize(const char *path) {
 | 
			
		||||
size_t rtGetFileSize(const char *path) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    WCHAR wpath[MAX_PATH];
 | 
			
		||||
    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
 | 
			
		||||
@ -16,7 +16,7 @@ size_t vyGetFileSize(const char *path) {
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void vySetWorkingDirectory(const char *path) {
 | 
			
		||||
void rtSetWorkingDirectory(const char *path) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    WCHAR wpath[MAX_PATH];
 | 
			
		||||
    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
 | 
			
		||||
@ -24,7 +24,7 @@ void vySetWorkingDirectory(const char *path) {
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t vyGetCurrentTimestamp(void) {
 | 
			
		||||
uint64_t rtGetCurrentTimestamp(void) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    FILETIME ft;
 | 
			
		||||
    GetSystemTimeAsFileTime(&ft);
 | 
			
		||||
@ -34,11 +34,11 @@ uint64_t vyGetCurrentTimestamp(void) {
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
uint64_t vyGetFileModificationTimestamp(vy_file_id fid) {
 | 
			
		||||
uint64_t rtGetFileModificationTimestamp(rt_file_id fid) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    const char *path = vyGetFilePath(fid);
 | 
			
		||||
    const char *path = rtGetFilePath(fid);
 | 
			
		||||
    if (!path) {
 | 
			
		||||
        vyLog("ASSETC", "Tried to get modification timestamp of unknown file.");
 | 
			
		||||
        rtLog("ASSETC", "Tried to get modification timestamp of unknown file.");
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    WCHAR wpath[MAX_PATH];
 | 
			
		||||
@ -52,34 +52,34 @@ uint64_t vyGetFileModificationTimestamp(vy_file_id fid) {
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyIterateDirectory(const char *path, void *user, vy_iterate_directory_cb_func iterate_cb) {
 | 
			
		||||
rt_result rtIterateDirectory(const char *path, void *user, rt_iterate_directory_cb_func iterate_cb) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    vy_result res;
 | 
			
		||||
    rt_result res;
 | 
			
		||||
    WCHAR wpath[MAX_PATH];
 | 
			
		||||
    char wildcard_path[MAX_PATH];
 | 
			
		||||
    strncpy(wildcard_path, path, MAX_PATH);
 | 
			
		||||
    strncat(wildcard_path, "\\*", MAX_PATH - strlen(path));
 | 
			
		||||
 | 
			
		||||
    res = vyUTF8ToWStr(wildcard_path, wpath, MAX_PATH);
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    res = rtUTF8ToWStr(wildcard_path, wpath, MAX_PATH);
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
 | 
			
		||||
    WIN32_FIND_DATAW find;
 | 
			
		||||
    HANDLE h = FindFirstFileW(wpath, &find);
 | 
			
		||||
    if (h == INVALID_HANDLE_VALUE)
 | 
			
		||||
        return VY_UNKNOWN_ERROR;
 | 
			
		||||
        return RT_UNKNOWN_ERROR;
 | 
			
		||||
    do {
 | 
			
		||||
        char utf8_file[MAX_PATH];
 | 
			
		||||
        res = vyWStrToUTF8(find.cFileName, utf8_file, MAX_PATH);
 | 
			
		||||
        if (res != VY_SUCCESS)
 | 
			
		||||
        res = rtWStrToUTF8(find.cFileName, utf8_file, MAX_PATH);
 | 
			
		||||
        if (res != RT_SUCCESS)
 | 
			
		||||
            break;
 | 
			
		||||
        vyIterateDirElementType type;
 | 
			
		||||
        rtIterateDirElementType type;
 | 
			
		||||
        if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
 | 
			
		||||
            type = VY_DIR_ELEMENT_TYPE_DIRECTORY;
 | 
			
		||||
            type = RT_DIR_ELEMENT_TYPE_DIRECTORY;
 | 
			
		||||
        else
 | 
			
		||||
            type = VY_DIR_ELEMENT_TYPE_FILE;
 | 
			
		||||
            type = RT_DIR_ELEMENT_TYPE_FILE;
 | 
			
		||||
        res = iterate_cb(utf8_file, type, user);
 | 
			
		||||
        if (res != VY_SUCCESS)
 | 
			
		||||
        if (res != RT_SUCCESS)
 | 
			
		||||
            break;
 | 
			
		||||
    } while (FindNextFileW(h, &find) != 0);
 | 
			
		||||
 | 
			
		||||
@ -88,14 +88,14 @@ vy_result vyIterateDirectory(const char *path, void *user, vy_iterate_directory_
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
vy_result vyCreateDirectory(const char *path) {
 | 
			
		||||
rt_result rtCreateDirectory(const char *path) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
    WCHAR wpath[MAX_PATH];
 | 
			
		||||
    vy_result res = vyUTF8ToWStr(path, wpath, MAX_PATH);
 | 
			
		||||
    if (res != VY_SUCCESS)
 | 
			
		||||
    rt_result res = rtUTF8ToWStr(path, wpath, MAX_PATH);
 | 
			
		||||
    if (res != RT_SUCCESS)
 | 
			
		||||
        return res;
 | 
			
		||||
    if (!CreateDirectoryW(wpath, NULL))
 | 
			
		||||
        res = VY_UNKNOWN_ERROR;
 | 
			
		||||
        res = RT_UNKNOWN_ERROR;
 | 
			
		||||
    return res;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
@ -1,27 +1,27 @@
 | 
			
		||||
#ifndef VY_ASSETC_UTILS_H
 | 
			
		||||
#define VY_ASSETC_UTILS_H
 | 
			
		||||
#ifndef RT_ASSETC_UTILS_H
 | 
			
		||||
#define RT_ASSETC_UTILS_H
 | 
			
		||||
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include "runtime/file_tab.h"
 | 
			
		||||
 | 
			
		||||
size_t vyGetFileSize(const char *path);
 | 
			
		||||
size_t rtGetFileSize(const char *path);
 | 
			
		||||
 | 
			
		||||
void vySetWorkingDirectory(const char *path);
 | 
			
		||||
void rtSetWorkingDirectory(const char *path);
 | 
			
		||||
 | 
			
		||||
uint64_t vyGetCurrentTimestamp(void);
 | 
			
		||||
uint64_t rtGetCurrentTimestamp(void);
 | 
			
		||||
 | 
			
		||||
uint64_t vyGetFileModificationTimestamp(vy_file_id fid);
 | 
			
		||||
uint64_t rtGetFileModificationTimestamp(rt_file_id fid);
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    VY_DIR_ELEMENT_TYPE_FILE,
 | 
			
		||||
    VY_DIR_ELEMENT_TYPE_DIRECTORY,
 | 
			
		||||
} vyIterateDirElementType;
 | 
			
		||||
    RT_DIR_ELEMENT_TYPE_FILE,
 | 
			
		||||
    RT_DIR_ELEMENT_TYPE_DIRECTORY,
 | 
			
		||||
} rtIterateDirElementType;
 | 
			
		||||
 | 
			
		||||
typedef vy_result vy_iterate_directory_cb_func(const char *name, vyIterateDirElementType type, void *user);
 | 
			
		||||
typedef rt_result rt_iterate_directory_cb_func(const char *name, rtIterateDirElementType type, void *user);
 | 
			
		||||
 | 
			
		||||
vy_result vyIterateDirectory(const char *path, void *user, vy_iterate_directory_cb_func iterate_cb);
 | 
			
		||||
rt_result rtIterateDirectory(const char *path, void *user, rt_iterate_directory_cb_func iterate_cb);
 | 
			
		||||
 | 
			
		||||
vy_result vyCreateDirectory(const char *path);
 | 
			
		||||
rt_result rtCreateDirectory(const char *path);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user