Various improvements
- Support static linking - Buffer manager
This commit is contained in:
		
							parent
							
								
									b2037519cc
								
							
						
					
					
						commit
						11ec5a0cd2
					
				
							
								
								
									
										24
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								meson.build
									
									
									
									
									
								
							@ -1,5 +1,5 @@
 | 
			
		||||
project('voyage', 'c',
 | 
			
		||||
  default_options: ['buildtype=debugoptimized', 'b_sanitize=address', 'c_std=c17', 'warning_level=3'])
 | 
			
		||||
  default_options: ['buildtype=debug', 'b_sanitize=address', 'c_std=c17', 'warning_level=3'])
 | 
			
		||||
 | 
			
		||||
compiler = meson.get_compiler('c')
 | 
			
		||||
buildtype = get_option('buildtype')
 | 
			
		||||
@ -21,6 +21,10 @@ elif compiler.get_argument_syntax() == 'msvc'
 | 
			
		||||
  endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if get_option('default_library') == 'static'
 | 
			
		||||
    add_project_arguments(['-DVY_STATIC_LIB'], language : 'c')
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
# Debug specific flags
 | 
			
		||||
if buildtype == 'debug' or buildtype == 'debugoptimized'
 | 
			
		||||
  add_project_arguments([ '-DVY_DEBUG'], language : 'c')
 | 
			
		||||
@ -51,6 +55,7 @@ runtime_lib = library('vyrt',
 | 
			
		||||
  'src/runtime/jobs.h',
 | 
			
		||||
  'src/runtime/aio.h',
 | 
			
		||||
  'src/runtime/file_tab.h',
 | 
			
		||||
  'src/runtime/buffer_manager.h',
 | 
			
		||||
 | 
			
		||||
  'src/runtime/error_report.c',
 | 
			
		||||
  'src/runtime/gfx_main.c',
 | 
			
		||||
@ -65,6 +70,7 @@ runtime_lib = library('vyrt',
 | 
			
		||||
  'src/runtime/jobs.c',
 | 
			
		||||
  'src/runtime/aio.c',
 | 
			
		||||
  'src/runtime/file_tab.c',
 | 
			
		||||
  'src/runtime/buffer_manager.c',
 | 
			
		||||
 | 
			
		||||
  # Contrib Sources
 | 
			
		||||
  'contrib/xxhash/xxhash.c',
 | 
			
		||||
@ -72,6 +78,10 @@ runtime_lib = library('vyrt',
 | 
			
		||||
  include_directories : incdir,
 | 
			
		||||
  c_pch : 'pch/rt_pch.h')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Renderer libraries
 | 
			
		||||
static_renderer_lib = 'NONE'
 | 
			
		||||
 | 
			
		||||
if vk_dep.found()
 | 
			
		||||
  platform_defs = []
 | 
			
		||||
  if get_option('use_xlib')
 | 
			
		||||
@ -98,12 +108,22 @@ if vk_dep.found()
 | 
			
		||||
    link_with : [runtime_lib],
 | 
			
		||||
    c_pch : 'pch/vk_pch.h',
 | 
			
		||||
    c_args : platform_defs)
 | 
			
		||||
 | 
			
		||||
  static_renderer_lib = vk_renderer_lib
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
game_link_libs = []
 | 
			
		||||
if get_option('default_library') == 'static'
 | 
			
		||||
  game_link_libs = [runtime_lib, static_renderer_lib]
 | 
			
		||||
else
 | 
			
		||||
  game_link_libs = [runtime_lib]
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
executable('voyage',
 | 
			
		||||
  'src/game/voyage.c',
 | 
			
		||||
  include_directories : incdir,
 | 
			
		||||
  link_with : [runtime_lib],
 | 
			
		||||
  link_with : game_link_libs,
 | 
			
		||||
  win_subsystem : 'windows')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -52,8 +52,7 @@ static void ReleasePipelineSlot(vy_gfx_pipeline_handle id) {
 | 
			
		||||
        _storage.generation_in_use[slot] &= ~0x1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_gfx_pipeline_handle
 | 
			
		||||
vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
 | 
			
		||||
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compute_pipeline_info *info) {
 | 
			
		||||
#if 0
 | 
			
		||||
    char info_log[512];
 | 
			
		||||
 | 
			
		||||
@ -94,8 +93,7 @@ vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
 | 
			
		||||
    return StorePipeline(pipeline);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_gfx_pipeline_handle
 | 
			
		||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
 | 
			
		||||
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileGraphicsPipeline)(const vy_graphics_pipeline_info *info) {
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
    char info_log[512];
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
 | 
			
		||||
extern vy_cvar r_VkPreferredSwapchainImages;
 | 
			
		||||
extern vy_cvar r_VkPreferMailboxMode;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterCVars(void) {
 | 
			
		||||
void VY_RENDERER_API_FN(RegisterCVars)(void) {
 | 
			
		||||
    vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPhysDeviceName);
 | 
			
		||||
    vyRegisterCVAR(&r_VkPreferredSwapchainImages);
 | 
			
		||||
@ -470,7 +470,7 @@ static vy_result CreateDevice(void) {
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyInit(const vy_renderer_init_info *info) {
 | 
			
		||||
vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *info) {
 | 
			
		||||
    vyLog("vk", "Init");
 | 
			
		||||
 | 
			
		||||
    _tracking_alloc_cbs.pUserData       = NULL;
 | 
			
		||||
@ -503,7 +503,7 @@ VY_DLLEXPORT vy_result vyInit(const vy_renderer_init_info *info) {
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdown(void) {
 | 
			
		||||
void VY_RENDERER_API_FN(Shutdown)(void) {
 | 
			
		||||
    vyLog("vk", "Shutdown");
 | 
			
		||||
    vkDeviceWaitIdle(g_gpu.device);
 | 
			
		||||
    vyDestroySwapchain();
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@
 | 
			
		||||
#include "gfx.h"
 | 
			
		||||
#include "aio.h"
 | 
			
		||||
#include "renderer_api.h"
 | 
			
		||||
#include "buffer_manager.h"
 | 
			
		||||
 | 
			
		||||
extern void __RegisterRuntimeCVars(void);
 | 
			
		||||
 | 
			
		||||
@ -37,6 +38,11 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
			
		||||
 | 
			
		||||
    /* TODO: Parse the cvar config file */
 | 
			
		||||
 | 
			
		||||
    if (vyInitBufferManager() != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("BUFFERMGR", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vyInitFileTab(1024) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("FTAB", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
@ -131,6 +137,7 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
			
		||||
    vyShutdownAIO();
 | 
			
		||||
    vyShutdownAIO();
 | 
			
		||||
    vyShutdownFileTab();
 | 
			
		||||
    vyShutdownBufferManager();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
@ -180,6 +187,11 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
    __RegisterRuntimeCVars();
 | 
			
		||||
    vyRegisterRendererCVars();
 | 
			
		||||
 | 
			
		||||
    if (vyInitBufferManager() != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("BUFFERMGR", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (vyInitFileTab(1024) != VY_SUCCESS) {
 | 
			
		||||
        vyReportError("FTAB", "Init failed.");
 | 
			
		||||
        return 1;
 | 
			
		||||
@ -260,6 +272,7 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
			
		||||
    XCloseDisplay(dpy);
 | 
			
		||||
    vyShutdownAIO();
 | 
			
		||||
    vyShutdownFileTab();
 | 
			
		||||
    vyShutdownBufferManager();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										250
									
								
								src/runtime/buffer_manager.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								src/runtime/buffer_manager.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,250 @@
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
#include "threading.h"
 | 
			
		||||
#include "config.h"
 | 
			
		||||
#include "buffer_manager.h"
 | 
			
		||||
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
typedef struct vy_buffer_region_s {
 | 
			
		||||
    void *memory;
 | 
			
		||||
    int16_t *refcounts; // One per block
 | 
			
		||||
    uint32_t *bitmap;
 | 
			
		||||
    size_t block_count;
 | 
			
		||||
    vy_mutex *guard;
 | 
			
		||||
} vy_buffer_region;
 | 
			
		||||
 | 
			
		||||
/* Count leading zeroes.
 | 
			
		||||
 * Note that the return value of __builtin_clz(0) is undefined. */
 | 
			
		||||
#ifdef _MSC_VER
 | 
			
		||||
 | 
			
		||||
#include <intrin.h>
 | 
			
		||||
 | 
			
		||||
#define lzcnt32(x) __lzcnt((x))
 | 
			
		||||
#define popcnt32(x) __popcnt((x))
 | 
			
		||||
 | 
			
		||||
static __forceinline uint32_t tzcnt32(uint32_t x) {
 | 
			
		||||
    unsigned long i;
 | 
			
		||||
    _BitScanForward(&i, x);
 | 
			
		||||
    return (uint32_t)i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline bool IsLZCNTSupported(void) {
 | 
			
		||||
#define Type 0x80000001
 | 
			
		||||
    int info[4];
 | 
			
		||||
    __cpuid(info, Type);
 | 
			
		||||
    return (info[2] & (1 << 5)) != 0;
 | 
			
		||||
#undef Type
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#elif defined(__GNUC__)
 | 
			
		||||
#define lzcnt32(x) __builtin_clz((x))
 | 
			
		||||
#define tzcnt32(x)  __builtin_ctz((x))
 | 
			
		||||
#define popcnt32(x) __builtin_popcount((x))
 | 
			
		||||
 | 
			
		||||
#define IsLZCNTSupported() true
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/* NOTE(Kevin): Keep these sorted! */
 | 
			
		||||
static size_t _block_sizes[] = {VY_KB(512), VY_MB(1), VY_MB(4), VY_MB(8) };
 | 
			
		||||
#define NUM_BLOCK_SIZES (sizeof(_block_sizes) / sizeof(_block_sizes[0]))
 | 
			
		||||
static vy_buffer_region _regions[NUM_BLOCK_SIZES];
 | 
			
		||||
 | 
			
		||||
VY_CVAR_SZ(
 | 
			
		||||
    rt_BufferManagerMemory,
 | 
			
		||||
    "Total number of bytes allocated for the buffer manager. Default: 1GB", VY_GB(1));
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyInitBufferManager(void) {
 | 
			
		||||
    if ((rt_BufferManagerMemory.sz % NUM_BLOCK_SIZES) != 0)
 | 
			
		||||
        vyLog("BUFFERMGR",
 | 
			
		||||
              "Configured memory amount is not dividable by number of block "
 | 
			
		||||
              "sizes: %u MB/%u",
 | 
			
		||||
              rt_BufferManagerMemory.sz / (1024 * 1024),
 | 
			
		||||
              NUM_BLOCK_SIZES);
 | 
			
		||||
 | 
			
		||||
    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",
 | 
			
		||||
                  "Memory per block size is not dividable by block size: %u "
 | 
			
		||||
                  "MB/%u KB",
 | 
			
		||||
                  mem_per_size / (1024 * 1024),
 | 
			
		||||
                  _block_sizes[i] / 1024);
 | 
			
		||||
 | 
			
		||||
        size_t block_count = mem_per_size / _block_sizes[i];
 | 
			
		||||
        _regions[i].block_count = block_count;
 | 
			
		||||
        _regions[i].guard       = vyCreateMutex();
 | 
			
		||||
        if (!_regions[i].guard) {
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to create guard mutex %u", i);
 | 
			
		||||
            return VY_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;
 | 
			
		||||
        }
 | 
			
		||||
        _regions[i].bitmap = calloc((block_count + 31) / 32, sizeof(uint32_t));
 | 
			
		||||
        if (!_regions[i].bitmap) {
 | 
			
		||||
            vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
            free(_regions[i].memory);
 | 
			
		||||
            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
			
		||||
            return VY_BUFFER_MGR_OUT_OF_MEMORY;
 | 
			
		||||
        }
 | 
			
		||||
        _regions[i].refcounts = calloc(block_count, sizeof(uint16_t));
 | 
			
		||||
        if (!_regions[i].refcounts) {
 | 
			
		||||
            vyDestroyMutex(_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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return VY_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownBufferManager(void) {
 | 
			
		||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
			
		||||
        vyDestroyMutex(_regions[i].guard);
 | 
			
		||||
        free(_regions[i].memory);
 | 
			
		||||
        free(_regions[i].bitmap);
 | 
			
		||||
        free(_regions[i].refcounts);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
			
		||||
    assert(IsLZCNTSupported());
 | 
			
		||||
    
 | 
			
		||||
    // Determine the best block size to use
 | 
			
		||||
    size_t required_blocks = (size + _block_sizes[0] - 1) / _block_sizes[0];
 | 
			
		||||
    size_t best_fit        = 0;
 | 
			
		||||
    for (size_t i = 1; i < NUM_BLOCK_SIZES; ++i) {
 | 
			
		||||
        size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
			
		||||
        if (block_count < required_blocks && size >= _block_sizes[i]) {
 | 
			
		||||
            required_blocks = block_count;
 | 
			
		||||
            best_fit        = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void *result = NULL;
 | 
			
		||||
 | 
			
		||||
    vy_buffer_region *region = &_regions[best_fit];
 | 
			
		||||
    vyLockMutex(region->guard);
 | 
			
		||||
    size_t dword_count = (region->block_count + 31) / 32;
 | 
			
		||||
 | 
			
		||||
    if (required_blocks < 32) {
 | 
			
		||||
        /* Fast path for allocations that potentially fit into one dword */
 | 
			
		||||
        uint32_t in_use_mask = (1ull << required_blocks) - 1;
 | 
			
		||||
        size_t max_occupancy = 32 - required_blocks;
 | 
			
		||||
        for (size_t i = 0; i < dword_count; ++i) {
 | 
			
		||||
            size_t block_index = 0;
 | 
			
		||||
            if (region->bitmap[i] != 0 && popcnt32(region->bitmap[i]) < max_occupancy) {
 | 
			
		||||
                size_t free_high_blocks = lzcnt32(region->bitmap[i]);
 | 
			
		||||
                if (free_high_blocks >= required_blocks) {
 | 
			
		||||
                    /* High blocks are free */
 | 
			
		||||
                    size_t first_free = 32 - free_high_blocks;
 | 
			
		||||
                    region->bitmap[i] |= (in_use_mask << first_free);
 | 
			
		||||
                    block_index = i * 32 + first_free;
 | 
			
		||||
                    result      = (char *)region->memory +
 | 
			
		||||
                        block_index * _block_sizes[best_fit];
 | 
			
		||||
                } else if (tzcnt32(region->bitmap[i]) >= required_blocks) {
 | 
			
		||||
                    /* Low blocks are free */
 | 
			
		||||
                    region->bitmap[i] |= in_use_mask;
 | 
			
		||||
                    block_index = i * 32;
 | 
			
		||||
                    result      = (char *)region->memory +  block_index * _block_sizes[best_fit];
 | 
			
		||||
                } else {
 | 
			
		||||
                    /* Check if we can find a large enough range of free blocks.
 | 
			
		||||
                     * Start after the first set bit.
 | 
			
		||||
                     */
 | 
			
		||||
                    for (uint32_t j = tzcnt32(region->bitmap[i]) + 1; j < 32 - required_blocks; ++j) {
 | 
			
		||||
                        if ((region->bitmap[i] & in_use_mask << j) == 0) {
 | 
			
		||||
                            region->bitmap[i] |= (in_use_mask << j);
 | 
			
		||||
                            block_index = i * 32 + j;
 | 
			
		||||
                            result = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else if (region->bitmap[i] == 0) {
 | 
			
		||||
                /* All free */
 | 
			
		||||
                region->bitmap[i]  = in_use_mask;
 | 
			
		||||
                block_index = i * 32;
 | 
			
		||||
                result             = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
			
		||||
            } else if (i < dword_count - 1) {
 | 
			
		||||
                /* Check if we can use high blocks from this dword and low blocks from the next one */
 | 
			
		||||
                size_t high_blocks = lzcnt32(region->bitmap[i]);
 | 
			
		||||
                size_t low_blocks  = (region->bitmap[i + 1] != 0) ? tzcnt32(region->bitmap[i + 1]) : 32;
 | 
			
		||||
 | 
			
		||||
                if (high_blocks + low_blocks >= required_blocks) {
 | 
			
		||||
                    size_t high_mask = (1u << high_blocks) - 1;
 | 
			
		||||
                    size_t first_free = 32 - high_blocks;
 | 
			
		||||
                    size_t low_mask = (1u << (required_blocks - high_blocks)) - 1;
 | 
			
		||||
                    
 | 
			
		||||
                    region->bitmap[i] |= (high_mask << first_free);
 | 
			
		||||
                    region->bitmap[i + 1] |= low_mask;
 | 
			
		||||
                    block_index = i * 32 + first_free;
 | 
			
		||||
                    result             = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result) {
 | 
			
		||||
                for (size_t j = 0; j < required_blocks; ++j)
 | 
			
		||||
                    region->refcounts[block_index + j] = 1;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyUnlockMutex(region->guard);
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseBuffer(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;
 | 
			
		||||
        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
			
		||||
        if (begin_addr >= region_addr &&
 | 
			
		||||
                begin_addr + size <= region_addr + region_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);
 | 
			
		||||
            for (size_t j = 0; j < block_count; ++j) {
 | 
			
		||||
                size_t dword = (first_block + j) / 32;
 | 
			
		||||
                size_t bit   = (first_block + j) % 32;
 | 
			
		||||
 | 
			
		||||
                if (--_regions[i].refcounts[first_block + j] == 0)
 | 
			
		||||
                    _regions[i].bitmap[dword] &= ~(1u << bit);
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockMutex(_regions[i].guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyLog("BUFFERMGR", "Tried to release an invalid buffer");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyIncreaseBufferRefCount(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;
 | 
			
		||||
        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
			
		||||
        if (begin_addr >= region_addr &&
 | 
			
		||||
            begin_addr + size <= region_addr + region_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);
 | 
			
		||||
            for (size_t j = 0; j < block_count; ++j) {
 | 
			
		||||
                ++_regions[i].refcounts[first_block + j];
 | 
			
		||||
            }
 | 
			
		||||
            vyUnlockMutex(_regions[i].guard);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    vyLog("BUFFERMGR", "Tried to increase the refcount of an invalid buffer");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								src/runtime/buffer_manager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/runtime/buffer_manager.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
#ifndef VY_BUFFER_MANAGER_H
 | 
			
		||||
#define VY_BUFFER_MANAGER_H
 | 
			
		||||
 | 
			
		||||
#include "runtime.h"
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
    VY_BUFFER_MGR_OUT_OF_MEMORY = VY_SUCCESS + 1,
 | 
			
		||||
    VY_BUFFER_MGR_MUTEX_CREATION_FAILED,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_result vyInitBufferManager(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyShutdownBufferManager(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyAllocBuffer(size_t size);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyIncreaseBufferRefCount(const void *begin, size_t size);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@ -8,6 +8,7 @@ typedef enum
 | 
			
		||||
    VY_CVAR_TYPE_INT,
 | 
			
		||||
    VY_CVAR_TYPE_FLOAT,
 | 
			
		||||
    VY_CVAR_TYPE_STRING,
 | 
			
		||||
    VY_CVAR_TYPE_SIZE,
 | 
			
		||||
} vy_cvar_type;
 | 
			
		||||
 | 
			
		||||
typedef struct
 | 
			
		||||
@ -18,6 +19,7 @@ typedef struct
 | 
			
		||||
        int i;
 | 
			
		||||
        float f;
 | 
			
		||||
        const char *s;
 | 
			
		||||
        size_t sz;
 | 
			
		||||
    };
 | 
			
		||||
    vy_cvar_type type;
 | 
			
		||||
} vy_cvar;
 | 
			
		||||
@ -37,6 +39,11 @@ typedef struct
 | 
			
		||||
                 .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}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterCVAR(vy_cvar *cvar);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,10 @@
 | 
			
		||||
#define WIN32_LEAN_AND_MEAN
 | 
			
		||||
#include <Windows.h>
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
 | 
			
		||||
    return (vy_dynlib)GetModuleHandleW(NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
 | 
			
		||||
    wchar_t libname_w[MAX_PATH];
 | 
			
		||||
    MultiByteToWideChar(CP_UTF8,
 | 
			
		||||
@ -27,6 +31,10 @@ VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
			
		||||
#elif defined(__linux__)
 | 
			
		||||
#include <dlfcn.h>
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
 | 
			
		||||
    return dlopen(NULL, RTLD_NOW | RTLD_LOCAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
 | 
			
		||||
    return dlopen(libname, RTLD_NOW | RTLD_LOCAL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,8 @@ typedef void *vy_dynlib;
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol);
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib);
 | 
			
		||||
 | 
			
		||||
@ -24,9 +24,21 @@ VY_CVAR_S(rt_Renderer,
 | 
			
		||||
extern bool
 | 
			
		||||
vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count);
 | 
			
		||||
 | 
			
		||||
#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_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(
 | 
			
		||||
    const vy_compute_pipeline_info *);
 | 
			
		||||
extern vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileGraphicsPipeline)(
 | 
			
		||||
    const vy_graphics_pipeline_info *);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool LoadRenderer(void) {
 | 
			
		||||
 | 
			
		||||
#if !defined(VY_STATIC_LIB)
 | 
			
		||||
    #define RETRIEVE_SYMBOL(name, type)                                        \
 | 
			
		||||
    g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vy" #name);          \
 | 
			
		||||
        g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vyRen" #name);   \
 | 
			
		||||
        if (!g_renderer.name) {                                                \
 | 
			
		||||
            vyReportError(                                                     \
 | 
			
		||||
                "GFX",                                                         \
 | 
			
		||||
@ -49,7 +61,6 @@ static bool LoadRenderer(void) {
 | 
			
		||||
        RETRIEVE_SYMBOL(CompileComputePipeline, vy_compile_compute_pipeline_fn);
 | 
			
		||||
        RETRIEVE_SYMBOL(CompileGraphicsPipeline,
 | 
			
		||||
                        vy_compile_graphics_pipeline_fn);
 | 
			
		||||
        return true;
 | 
			
		||||
    } else {
 | 
			
		||||
        vyReportError("GFX",
 | 
			
		||||
                      "Unsupported renderer backend: (%s) %s",
 | 
			
		||||
@ -58,6 +69,14 @@ static bool LoadRenderer(void) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    #undef RETRIEVE_SYMBOL
 | 
			
		||||
#else
 | 
			
		||||
    g_renderer.RegisterCVars = &vyRenRegisterCVars;
 | 
			
		||||
    g_renderer.Init          = &vyRenInit;
 | 
			
		||||
    g_renderer.Shutdown      = &vyRenShutdown;
 | 
			
		||||
    g_renderer.CompileComputePipeline = &vyRenCompileComputePipeline;
 | 
			
		||||
    g_renderer.CompileGraphicsPipeline = &vyRenCompileGraphicsPipeline;
 | 
			
		||||
#endif
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VY_DLLEXPORT void vyRegisterRendererCVars(void) {
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,8 @@
 | 
			
		||||
/* TODO(Kevin):
 | 
			
		||||
 * This should move into a standalone tool.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
 | 
			
		||||
@ -54,6 +54,8 @@ typedef struct {
 | 
			
		||||
    vy_compile_graphics_pipeline_fn *CompileGraphicsPipeline;
 | 
			
		||||
} vy_renderer_api;
 | 
			
		||||
 | 
			
		||||
#define VY_RENDERER_API_FN(name) VY_DLLEXPORT vyRen##name
 | 
			
		||||
 | 
			
		||||
#ifndef VY_DONT_DEFINE_RENDERER_GLOBAL
 | 
			
		||||
extern vy_renderer_api g_renderer;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#if defined(_WIN32)
 | 
			
		||||
    #define VY_DLLEXPORT __declspec(dllexport)
 | 
			
		||||
#else
 | 
			
		||||
    #define VY_DLLEXPORT
 | 
			
		||||
@ -14,6 +14,10 @@
 | 
			
		||||
#define VY_UNUSED(x)      ((void)sizeof((x)))
 | 
			
		||||
#define VY_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)
 | 
			
		||||
 | 
			
		||||
typedef unsigned int vy_result;
 | 
			
		||||
#define VY_SUCCESS 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,7 @@ 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;
 | 
			
		||||
 | 
			
		||||
void __RegisterRuntimeCVars(void)
 | 
			
		||||
{
 | 
			
		||||
@ -11,4 +12,5 @@ void __RegisterRuntimeCVars(void)
 | 
			
		||||
    vyRegisterCVAR(&rt_Fullscreen);
 | 
			
		||||
    vyRegisterCVAR(&rt_WindowWidth);
 | 
			
		||||
    vyRegisterCVAR(&rt_WindowHeight);
 | 
			
		||||
    vyRegisterCVAR(&rt_BufferManagerMemory);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user