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',
|
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')
|
compiler = meson.get_compiler('c')
|
||||||
buildtype = get_option('buildtype')
|
buildtype = get_option('buildtype')
|
||||||
@ -21,6 +21,10 @@ elif compiler.get_argument_syntax() == 'msvc'
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if get_option('default_library') == 'static'
|
||||||
|
add_project_arguments(['-DVY_STATIC_LIB'], language : 'c')
|
||||||
|
endif
|
||||||
|
|
||||||
# Debug specific flags
|
# Debug specific flags
|
||||||
if buildtype == 'debug' or buildtype == 'debugoptimized'
|
if buildtype == 'debug' or buildtype == 'debugoptimized'
|
||||||
add_project_arguments([ '-DVY_DEBUG'], language : 'c')
|
add_project_arguments([ '-DVY_DEBUG'], language : 'c')
|
||||||
@ -51,6 +55,7 @@ runtime_lib = library('vyrt',
|
|||||||
'src/runtime/jobs.h',
|
'src/runtime/jobs.h',
|
||||||
'src/runtime/aio.h',
|
'src/runtime/aio.h',
|
||||||
'src/runtime/file_tab.h',
|
'src/runtime/file_tab.h',
|
||||||
|
'src/runtime/buffer_manager.h',
|
||||||
|
|
||||||
'src/runtime/error_report.c',
|
'src/runtime/error_report.c',
|
||||||
'src/runtime/gfx_main.c',
|
'src/runtime/gfx_main.c',
|
||||||
@ -65,6 +70,7 @@ runtime_lib = library('vyrt',
|
|||||||
'src/runtime/jobs.c',
|
'src/runtime/jobs.c',
|
||||||
'src/runtime/aio.c',
|
'src/runtime/aio.c',
|
||||||
'src/runtime/file_tab.c',
|
'src/runtime/file_tab.c',
|
||||||
|
'src/runtime/buffer_manager.c',
|
||||||
|
|
||||||
# Contrib Sources
|
# Contrib Sources
|
||||||
'contrib/xxhash/xxhash.c',
|
'contrib/xxhash/xxhash.c',
|
||||||
@ -72,6 +78,10 @@ runtime_lib = library('vyrt',
|
|||||||
include_directories : incdir,
|
include_directories : incdir,
|
||||||
c_pch : 'pch/rt_pch.h')
|
c_pch : 'pch/rt_pch.h')
|
||||||
|
|
||||||
|
|
||||||
|
# Renderer libraries
|
||||||
|
static_renderer_lib = 'NONE'
|
||||||
|
|
||||||
if vk_dep.found()
|
if vk_dep.found()
|
||||||
platform_defs = []
|
platform_defs = []
|
||||||
if get_option('use_xlib')
|
if get_option('use_xlib')
|
||||||
@ -98,12 +108,22 @@ if vk_dep.found()
|
|||||||
link_with : [runtime_lib],
|
link_with : [runtime_lib],
|
||||||
c_pch : 'pch/vk_pch.h',
|
c_pch : 'pch/vk_pch.h',
|
||||||
c_args : platform_defs)
|
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
|
endif
|
||||||
|
|
||||||
executable('voyage',
|
executable('voyage',
|
||||||
'src/game/voyage.c',
|
'src/game/voyage.c',
|
||||||
include_directories : incdir,
|
include_directories : incdir,
|
||||||
link_with : [runtime_lib],
|
link_with : game_link_libs,
|
||||||
win_subsystem : 'windows')
|
win_subsystem : 'windows')
|
||||||
|
|
||||||
|
|
||||||
|
@ -52,8 +52,7 @@ static void ReleasePipelineSlot(vy_gfx_pipeline_handle id) {
|
|||||||
_storage.generation_in_use[slot] &= ~0x1;
|
_storage.generation_in_use[slot] &= ~0x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VY_DLLEXPORT vy_gfx_pipeline_handle
|
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compute_pipeline_info *info) {
|
||||||
vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
|
|
||||||
#if 0
|
#if 0
|
||||||
char info_log[512];
|
char info_log[512];
|
||||||
|
|
||||||
@ -94,8 +93,7 @@ vyCompileComputePipeline(const vy_compute_pipeline_info *info) {
|
|||||||
return StorePipeline(pipeline);
|
return StorePipeline(pipeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
VY_DLLEXPORT vy_gfx_pipeline_handle
|
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileGraphicsPipeline)(const vy_graphics_pipeline_info *info) {
|
||||||
vyCompileGraphicsPipeline(const vy_graphics_pipeline_info *info) {
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
char info_log[512];
|
char info_log[512];
|
||||||
|
@ -85,7 +85,7 @@ DebugUtilsMessengerCb(VkDebugUtilsMessageSeverityFlagBitsEXT severity,
|
|||||||
extern vy_cvar r_VkPreferredSwapchainImages;
|
extern vy_cvar r_VkPreferredSwapchainImages;
|
||||||
extern vy_cvar r_VkPreferMailboxMode;
|
extern vy_cvar r_VkPreferMailboxMode;
|
||||||
|
|
||||||
VY_DLLEXPORT void vyRegisterCVars(void) {
|
void VY_RENDERER_API_FN(RegisterCVars)(void) {
|
||||||
vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
|
vyRegisterCVAR(&r_VkEnableAPIAllocTracking);
|
||||||
vyRegisterCVAR(&r_VkPhysDeviceName);
|
vyRegisterCVAR(&r_VkPhysDeviceName);
|
||||||
vyRegisterCVAR(&r_VkPreferredSwapchainImages);
|
vyRegisterCVAR(&r_VkPreferredSwapchainImages);
|
||||||
@ -470,7 +470,7 @@ static vy_result CreateDevice(void) {
|
|||||||
return VY_SUCCESS;
|
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");
|
vyLog("vk", "Init");
|
||||||
|
|
||||||
_tracking_alloc_cbs.pUserData = NULL;
|
_tracking_alloc_cbs.pUserData = NULL;
|
||||||
@ -503,7 +503,7 @@ VY_DLLEXPORT vy_result vyInit(const vy_renderer_init_info *info) {
|
|||||||
return VY_SUCCESS;
|
return VY_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
VY_DLLEXPORT void vyShutdown(void) {
|
void VY_RENDERER_API_FN(Shutdown)(void) {
|
||||||
vyLog("vk", "Shutdown");
|
vyLog("vk", "Shutdown");
|
||||||
vkDeviceWaitIdle(g_gpu.device);
|
vkDeviceWaitIdle(g_gpu.device);
|
||||||
vyDestroySwapchain();
|
vyDestroySwapchain();
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
#include "aio.h"
|
#include "aio.h"
|
||||||
#include "renderer_api.h"
|
#include "renderer_api.h"
|
||||||
|
#include "buffer_manager.h"
|
||||||
|
|
||||||
extern void __RegisterRuntimeCVars(void);
|
extern void __RegisterRuntimeCVars(void);
|
||||||
|
|
||||||
@ -37,6 +38,11 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
|||||||
|
|
||||||
/* TODO: Parse the cvar config file */
|
/* TODO: Parse the cvar config file */
|
||||||
|
|
||||||
|
if (vyInitBufferManager() != VY_SUCCESS) {
|
||||||
|
vyReportError("BUFFERMGR", "Init failed.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (vyInitFileTab(1024) != VY_SUCCESS) {
|
if (vyInitFileTab(1024) != VY_SUCCESS) {
|
||||||
vyReportError("FTAB", "Init failed.");
|
vyReportError("FTAB", "Init failed.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -131,6 +137,7 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
|
|||||||
vyShutdownAIO();
|
vyShutdownAIO();
|
||||||
vyShutdownAIO();
|
vyShutdownAIO();
|
||||||
vyShutdownFileTab();
|
vyShutdownFileTab();
|
||||||
|
vyShutdownBufferManager();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -180,6 +187,11 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
|
|||||||
__RegisterRuntimeCVars();
|
__RegisterRuntimeCVars();
|
||||||
vyRegisterRendererCVars();
|
vyRegisterRendererCVars();
|
||||||
|
|
||||||
|
if (vyInitBufferManager() != VY_SUCCESS) {
|
||||||
|
vyReportError("BUFFERMGR", "Init failed.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (vyInitFileTab(1024) != VY_SUCCESS) {
|
if (vyInitFileTab(1024) != VY_SUCCESS) {
|
||||||
vyReportError("FTAB", "Init failed.");
|
vyReportError("FTAB", "Init failed.");
|
||||||
return 1;
|
return 1;
|
||||||
@ -260,6 +272,7 @@ VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
|
|||||||
XCloseDisplay(dpy);
|
XCloseDisplay(dpy);
|
||||||
vyShutdownAIO();
|
vyShutdownAIO();
|
||||||
vyShutdownFileTab();
|
vyShutdownFileTab();
|
||||||
|
vyShutdownBufferManager();
|
||||||
|
|
||||||
return 0;
|
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_INT,
|
||||||
VY_CVAR_TYPE_FLOAT,
|
VY_CVAR_TYPE_FLOAT,
|
||||||
VY_CVAR_TYPE_STRING,
|
VY_CVAR_TYPE_STRING,
|
||||||
|
VY_CVAR_TYPE_SIZE,
|
||||||
} vy_cvar_type;
|
} vy_cvar_type;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -18,6 +19,7 @@ typedef struct
|
|||||||
int i;
|
int i;
|
||||||
float f;
|
float f;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
size_t sz;
|
||||||
};
|
};
|
||||||
vy_cvar_type type;
|
vy_cvar_type type;
|
||||||
} vy_cvar;
|
} vy_cvar;
|
||||||
@ -37,6 +39,11 @@ typedef struct
|
|||||||
.description = d, \
|
.description = d, \
|
||||||
.s = (v), \
|
.s = (v), \
|
||||||
.type = VY_CVAR_TYPE_STRING}
|
.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);
|
VY_DLLEXPORT void vyRegisterCVAR(vy_cvar *cvar);
|
||||||
|
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
|
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
|
||||||
|
return (vy_dynlib)GetModuleHandleW(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
|
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
|
||||||
wchar_t libname_w[MAX_PATH];
|
wchar_t libname_w[MAX_PATH];
|
||||||
MultiByteToWideChar(CP_UTF8,
|
MultiByteToWideChar(CP_UTF8,
|
||||||
@ -27,6 +31,10 @@ VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
|
|||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
|
||||||
|
return dlopen(NULL, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
}
|
||||||
|
|
||||||
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
|
VY_DLLEXPORT vy_dynlib vyOpenLib(const char *libname) {
|
||||||
return dlopen(libname, RTLD_NOW | RTLD_LOCAL);
|
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 vyOpenLib(const char *libname);
|
||||||
|
|
||||||
|
VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void);
|
||||||
|
|
||||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol);
|
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol);
|
||||||
|
|
||||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib);
|
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib);
|
||||||
|
@ -24,9 +24,21 @@ VY_CVAR_S(rt_Renderer,
|
|||||||
extern bool
|
extern bool
|
||||||
vyLoadShaders(const char **paths, vy_shader *shaders, unsigned int count);
|
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) {
|
static bool LoadRenderer(void) {
|
||||||
|
|
||||||
|
#if !defined(VY_STATIC_LIB)
|
||||||
#define RETRIEVE_SYMBOL(name, type) \
|
#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) { \
|
if (!g_renderer.name) { \
|
||||||
vyReportError( \
|
vyReportError( \
|
||||||
"GFX", \
|
"GFX", \
|
||||||
@ -49,7 +61,6 @@ static bool LoadRenderer(void) {
|
|||||||
RETRIEVE_SYMBOL(CompileComputePipeline, vy_compile_compute_pipeline_fn);
|
RETRIEVE_SYMBOL(CompileComputePipeline, vy_compile_compute_pipeline_fn);
|
||||||
RETRIEVE_SYMBOL(CompileGraphicsPipeline,
|
RETRIEVE_SYMBOL(CompileGraphicsPipeline,
|
||||||
vy_compile_graphics_pipeline_fn);
|
vy_compile_graphics_pipeline_fn);
|
||||||
return true;
|
|
||||||
} else {
|
} else {
|
||||||
vyReportError("GFX",
|
vyReportError("GFX",
|
||||||
"Unsupported renderer backend: (%s) %s",
|
"Unsupported renderer backend: (%s) %s",
|
||||||
@ -58,6 +69,14 @@ static bool LoadRenderer(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#undef RETRIEVE_SYMBOL
|
#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) {
|
VY_DLLEXPORT void vyRegisterRendererCVars(void) {
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
/* TODO(Kevin):
|
||||||
|
* This should move into a standalone tool.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
@ -54,6 +54,8 @@ typedef struct {
|
|||||||
vy_compile_graphics_pipeline_fn *CompileGraphicsPipeline;
|
vy_compile_graphics_pipeline_fn *CompileGraphicsPipeline;
|
||||||
} vy_renderer_api;
|
} vy_renderer_api;
|
||||||
|
|
||||||
|
#define VY_RENDERER_API_FN(name) VY_DLLEXPORT vyRen##name
|
||||||
|
|
||||||
#ifndef VY_DONT_DEFINE_RENDERER_GLOBAL
|
#ifndef VY_DONT_DEFINE_RENDERER_GLOBAL
|
||||||
extern vy_renderer_api g_renderer;
|
extern vy_renderer_api g_renderer;
|
||||||
#endif
|
#endif
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#if defined(_WIN32)
|
||||||
#define VY_DLLEXPORT __declspec(dllexport)
|
#define VY_DLLEXPORT __declspec(dllexport)
|
||||||
#else
|
#else
|
||||||
#define VY_DLLEXPORT
|
#define VY_DLLEXPORT
|
||||||
@ -14,6 +14,10 @@
|
|||||||
#define VY_UNUSED(x) ((void)sizeof((x)))
|
#define VY_UNUSED(x) ((void)sizeof((x)))
|
||||||
#define VY_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
|
#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;
|
typedef unsigned int vy_result;
|
||||||
#define VY_SUCCESS 0
|
#define VY_SUCCESS 0
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ extern vy_cvar rt_Renderer;
|
|||||||
extern vy_cvar rt_Fullscreen;
|
extern vy_cvar rt_Fullscreen;
|
||||||
extern vy_cvar rt_WindowWidth;
|
extern vy_cvar rt_WindowWidth;
|
||||||
extern vy_cvar rt_WindowHeight;
|
extern vy_cvar rt_WindowHeight;
|
||||||
|
extern vy_cvar rt_BufferManagerMemory;
|
||||||
|
|
||||||
void __RegisterRuntimeCVars(void)
|
void __RegisterRuntimeCVars(void)
|
||||||
{
|
{
|
||||||
@ -11,4 +12,5 @@ void __RegisterRuntimeCVars(void)
|
|||||||
vyRegisterCVAR(&rt_Fullscreen);
|
vyRegisterCVAR(&rt_Fullscreen);
|
||||||
vyRegisterCVAR(&rt_WindowWidth);
|
vyRegisterCVAR(&rt_WindowWidth);
|
||||||
vyRegisterCVAR(&rt_WindowHeight);
|
vyRegisterCVAR(&rt_WindowHeight);
|
||||||
|
vyRegisterCVAR(&rt_BufferManagerMemory);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user