This commit is contained in:
Kevin Trogant 2024-02-29 16:49:57 +01:00
commit efd1f5f983
29 changed files with 315 additions and 90 deletions

View File

@ -16,8 +16,9 @@ buildtype = get_option('buildtype')
# Build options
if compiler.get_argument_syntax() == 'gcc'
add_project_arguments(
['-Wconversion', '-Wno-sign-conversion',
'-Wdouble-promotion', '-Wno-unused-function', '-Wno-unused-parameter'],
['-Wno-sign-conversion',
'-Wdouble-promotion', '-Wno-unused-function', '-Wno-unused-parameter',
'-fms-extensions'],
language : ['c', 'cpp']
)
elif compiler.get_argument_syntax() == 'msvc'
@ -45,6 +46,11 @@ if buildtype == 'debug' or buildtype == 'debugoptimized'
add_project_arguments([ '-DRT_DEBUG'], language : ['c', 'cpp'])
endif
# OS Specific flags
if host_machine.system() == 'linux'
add_project_arguments(['-D_GNU_SOURCE'], language : ['c', 'cpp'])
endif
fs = import('fs')
# Gather dependencies
@ -64,6 +70,7 @@ copy_util = find_program('scripts/copy_util.py')
engine_incdir = include_directories('src')
contrib_dir = meson.project_source_root() / 'contrib'
contrib_incdir = include_directories('contrib')
# Targets append to this, to enable us to run shared library builds from IDEs
engine_lib_paths = []

View File

@ -1,5 +0,0 @@
option('static_renderer', type : 'string', value : 'vk', description : 'Name of the renderer used for static builds')
option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux')
option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError')
option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.')
option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.')

6
meson_options.txt Normal file
View File

@ -0,0 +1,6 @@
option('static_renderer', type : 'string', value : 'vk', description : 'Name of the renderer used for static builds')
option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux')
option('error_report_debugbreak', type : 'boolean', value : true, description : 'Debugbreak in ReportError')
option('enable_dxc_shader_compiler', type : 'boolean', value : true, description : 'Enables building the dxc-based shader compiler.')
option('game_as_subdir', type : 'boolean', value : false, description : 'If true, adds the directory "src/game" to the build.')

18
scripts/download_dxc.sh Executable file
View File

@ -0,0 +1,18 @@
#!/bin/bash
fOutFile ile="dxc_2023_08_14.zip"
file="linux_dxc_2023_08_14.x86_64.tar.gz"
if [! -d contrib]; then
echo "Could not find 'contrib'. Make sure to run this script from the projects root directory."
exit 1;
fi
mkdir -p contrib/dxc
wget https://github.com/microsoft/DirectXShaderCompiler/releases/download/v1.7.2308/$file -O contrib/dxc/$file
tar xzf contrib/dxc/$file -C contrib/dxc
rm contrib/dxc/$file
# Match windows version
mv contrib/dxc/include contrib/dxc/inc
mv contrib/dxc/inc/dxc/*.h contrib/dxc/inc
rm -r contrib/dxc/inc/dxc

View File

@ -28,8 +28,11 @@ static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM
}
}
RT_DLLEXPORT int
rtWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow, rt_app_callbacks app_callbacks) {
RT_DLLEXPORT int rtWin32Entry(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
PWSTR pCmdLine,
int nCmdShow,
rt_app_callbacks app_callbacks) {
if (rtInitRuntime() != RT_SUCCESS)
return 1;
@ -117,7 +120,7 @@ rtWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int n
}
}
}
app_callbacks.Shutdown();
rtShutdownMainLoop();
@ -177,8 +180,8 @@ RT_DLLEXPORT int rtXlibEntry(int argc, char **argv, rt_app_callbacks app_callbac
return 1;
rtRegisterRendererCVars();
if (app_callbacks.RegisterCVars())
if (app_callbacks.RegisterCVars)
app_callbacks.RegisterCVars();
Display *dpy = XOpenDisplay(NULL);

View File

@ -67,14 +67,13 @@ extern RT_ASSET_PROCESSOR_FN(PipelineProcessor);
extern RT_ASSET_PROCESSOR_FN(FramegraphProcessor);
static rt_asset_processor _processors[] = {
{.file_ext = ".pipeline", .proc = PipelineProcessor},
{ .file_ext = ".pipeline", .proc = PipelineProcessor},
{.file_ext = ".framegraph", .proc = FramegraphProcessor},
};
static void ProcessorThreadEntry(void *);
static void CompilerThreadEntry(void *);
RT_DLLEXPORT void rtRegisterAssetCompilerCVars(void) {
rtRegisterCVAR(&rt_AssetDirectory);
rtRegisterCVAR(&rt_AssetDBSize);
@ -151,7 +150,6 @@ static int DiscoverAssets(void) {
#define MAX_DISCOVERY_DEPTH 64
#define MAX_FILENAME_LEN 260
static char directory_stack[MAX_DISCOVERY_DEPTH][MAX_FILENAME_LEN];
static unsigned int path_lens[MAX_DISCOVERY_DEPTH];
unsigned int top = 0;
memcpy(directory_stack[0],
@ -213,7 +211,7 @@ static int DiscoverAssets(void) {
unsigned int i = 0;
rtLockWrite(&_asset_db.lock);
while (i < (unsigned int)rt_AssetDBSize.i) {
unsigned int slot = (fid + i) % (unsigned int)rt_AssetDBSize.i;
unsigned int slot = ((unsigned int)fid + i) % (unsigned int)rt_AssetDBSize.i;
if (_asset_db.files[slot] == fid) {
break;
} else if (_asset_db.files[slot] == 0) {

View File

@ -2,17 +2,30 @@
// Required by dxcapi.h, does not work with WIN32_LEAN_AND_MEAN
#include <Windows.h>
#endif
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wconversion"
#endif
#include <dxcapi.h>
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#include <stdlib.h>
#include "processor.h"
#include "shader_compiler.h"
#ifdef __linux__
#define WCHAR wchar_t
#endif
extern "C" rt_shader_bytecode CompileVulkanShader(rt_shader_stage stage,
rt_shader_optimization_level optimization,
rt_text_span code,
const char *file_path,
rt_arena *arena) {
rt_shader_bytecode bc = {0};
rt_shader_bytecode bc;
memset(&bc, 0, sizeof(bc));
// NOTE(Kevin): This looks like some sort of autodetect?
// Maybe fix this to UTF8?
@ -22,7 +35,7 @@ extern "C" rt_shader_bytecode CompileVulkanShader(rt_shader_stage stage,
// Check if this is what we want.
// For example: 6_2 is what allows the usage of 16 bit types
LPCWSTR target_profile = nullptr;
LPCWSTR entry = nullptr;
LPCWSTR entry = nullptr;
switch (stage) {
case RT_SHADER_STAGE_VERTEX:
target_profile = L"vs_6_1";
@ -87,8 +100,8 @@ extern "C" rt_shader_bytecode CompileVulkanShader(rt_shader_stage stage,
// Gather arguments.
// TODO(kevin): Maybe add -Qstrip_debug & -Qstrip_reflect?
WCHAR wname[MAX_PATH];
rtUTF8ToWStr(file_path, wname, MAX_PATH);
WCHAR wname[RT_PATH_MAX];
rtUTF8ToWStr(file_path, wname, RT_PATH_MAX);
// clang-format off
LPCWSTR args[] = {
wname,
@ -147,4 +160,4 @@ extern "C" rt_shader_bytecode CompileVulkanShader(rt_shader_stage stage,
compiler->Release();
library->Release();
return bc;
}
}

View File

@ -374,9 +374,10 @@ RT_ASSET_PROCESSOR_FN(PipelineProcessor) {
for (unsigned int i = 0; i < effect.pass_count; ++i) {
rt_parsed_pipeline_data pipeline;
memcpy(&pipeline, &effect.pipelines[i], sizeof(pipeline));
rt_resource_id shader_resources[3] = {0};
result = rtCreateResources(pipeline.shader_count,
pipeline.shader_names,
(const char **)pipeline.shader_names,
pipeline.shaders,
shader_resources);
if (result != RT_SUCCESS)

View File

@ -32,7 +32,7 @@ static rt_result ParseFramegraph(const char *text,
if (!framegraph)
return RT_OUT_OF_MEMORY;
#pragma region Render Targets
/* ~~~~ Render Targets ~~~~ */
const rt_parsed_stmt *rt_list_stmt = rtFindStatement(&state, root_list, "render_targets");
if (!rt_list_stmt) {
rtLog("AC",
@ -189,9 +189,8 @@ static rt_result ParseFramegraph(const char *text,
render_targets[i] = rt;
}
#pragma endregion Render Targets
#pragma region Render Passes
/* ~~~~ Render Passes ~~~~ */
/* First count the total number of reads and writes */
uint32_t total_reads = 0, total_writes = 0;
const rt_parsed_stmt *pass_list_stmt = rtFindStatement(&state, root_list, "passes");
@ -590,11 +589,9 @@ static rt_result ParseFramegraph(const char *text,
}
}
}
#pragma region
#pragma region Names
/* Fill the render pass names */
char *names = rtArenaPush(arena, framegraph->names_size);
/* ~~~~ Names ~~~~ */
char *names = rtArenaPush(arena, framegraph->names_size);
rtSetRelptr(&framegraph->names, names);
char *names_at = names;
pass_stmt = &state.statements[pass_list->first];
@ -628,7 +625,6 @@ static rt_result ParseFramegraph(const char *text,
render_targets[i].name_len = 0;
}
}
#pragma region
*p_framegraph = framegraph;
return result;
@ -661,4 +657,4 @@ RT_ASSET_PROCESSOR_FN(FramegraphProcessor) {
out:
rtReleaseBuffer(asset.buffer, asset.size);
return result;
}
}

View File

@ -6,7 +6,7 @@ ac_cargs = []
# DXC for vulkan & directx shaders
if get_option('enable_dxc_shader_compiler')
# We package dxc binaries under contrib/dxc
dxc_include = include_directories(meson.project_source_root() / 'contrib' / 'dxc' / 'inc')
dxc_include = include_directories('../../contrib/dxc/inc')
dxc_libdir = 'NONE'
if host_machine.system() == 'windows'
dxc_libdir = meson.project_source_root() / 'contrib' / 'dxc' / 'lib' / 'x64'
@ -16,6 +16,20 @@ if get_option('enable_dxc_shader_compiler')
command : [copy_util, '@INPUT@', '@OUTPUT@'],
install : false,
build_by_default : true)
elif host_machine.system() == 'linux'
dxc_libdir = meson.project_source_root() / 'contrib' / 'dxc' / 'lib'
custom_target('copy libdxcompiler.so',
input : meson.project_source_root() / 'contrib' / 'dxc' / 'lib' / 'libdxcompiler.so',
output : 'libdxcompiler.so',
command : [copy_util, '@INPUT@', '@OUTPUT@'],
install : false,
build_by_default : true)
custom_target('copy libdxil.so',
input : meson.project_source_root() / 'contrib' / 'dxc' / 'lib' / 'libdxil.so',
output : 'libdxil.so',
command : [copy_util, '@INPUT@', '@OUTPUT@'],
install : false,
build_by_default : true)
endif
dxc_dep = declare_dependency(link_args : ['-L'+dxc_libdir, '-ldxcompiler'], include_directories : dxc_include)
ac_deps += dxc_dep

View File

@ -17,6 +17,10 @@
extern "C" {
#endif
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
typedef union {
float v[4];
struct {
@ -26,6 +30,9 @@ typedef union {
float a;
};
} rt_color;
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
/* NOTE(kevin): When you add a value here, you need to handle them in
* framegraph_processor.c : ParseFramegraph

View File

@ -318,7 +318,7 @@ CreateRenderTargets(rt_framegraph *graph, const rt_framegraph_info *info, rt_are
graph->render_targets[i].height = render_targets[i].height;
graph->render_targets[i].sample_count = render_targets[i].sample_count;
graph->render_targets[i].name = NULL;
const char *name = rtResolveConstRelptr(&render_targets[i].name);
if (name) {
size_t name_strlen = strlen(name);
@ -520,8 +520,8 @@ BeginGraphicsPass(rt_framegraph *framegraph, uint32_t pass_idx, rt_command_buffe
rt_render_target *rt = GetRenderTarget(framegraph, writes[0].render_target);
RT_ASSERT(rt != NULL, "Invalid render target in pass write.");
begin_info.render_area = (rt_rect2i){
.offset = { 0, 0},
.size = {.x = rt->width, .y = rt->height}
.offset = {{0, 0}},
.size = {{.x = rt->width, .y = rt->height}},
};
}
@ -913,4 +913,4 @@ RT_DLLEXPORT rt_render_pass_id rtCalculateRenderPassID(const char *name, size_t
if (id == 0)
id = ~id;
return id;
}
}

View File

@ -15,7 +15,10 @@
*/
rt_renderer_api g_renderer;
#ifndef RT_STATIC_LIB
static rt_dynlib _renderer_lib;
#endif
static bool _renderer_loaded = false;
RT_DLLEXPORT
@ -165,4 +168,4 @@ RT_DLLEXPORT void rtBeginGFXFrame(unsigned int frame_id) {
RT_DLLEXPORT void rtEndGFXFrame(unsigned int frame_id) {
g_renderer.EndFrame(frame_id);
}
}

View File

@ -3,9 +3,11 @@
#include "render_targets.h"
#include "swapchain.h"
#include "gfx/renderer_api.h"
#include "runtime/handles.h"
#include "runtime/mem_arena.h"
#include "gfx/renderer_api.h"
#include <string.h>
/* Retrieve the VkCommandBuffer as varname, or return */
#define GET_CMDBUF(varname, handle) \

View File

@ -122,7 +122,7 @@ rt_result RT_RENDERER_API_FN(CreateSemaphores)(uint32_t count,
sem->current_value[j] = 0;
}
p_semaphores[i].version = sem->version;
p_semaphores[i].version = (unsigned char)sem->version;
p_semaphores[i].index = (uint32_t)(sem - _semaphores);
}
return RT_SUCCESS;
@ -189,4 +189,4 @@ rt_gpu_semaphore_handle RT_RENDERER_API_FN(GetRenderFinishedSemaphore)(void) {
.version = 1,
.index = RENDER_FINISHED_SEMAPHORE_INDEX,
};
}
}

View File

@ -207,7 +207,7 @@ static rt_result CreateSurface(const rt_renderer_init_info *info) {
return RT_SUCCESS;
else
return 100;
#elif defined(RT_USE_XLIB_KHR)
#elif defined(RT_USE_XLIB)
g_gpu.native_window.display = info->display;
g_gpu.native_window.window = info->window;
VkXlibSurfaceCreateInfoKHR surface_info = {
@ -215,7 +215,7 @@ static rt_result CreateSurface(const rt_renderer_init_info *info) {
.dpy = info->display,
.window = info->window,
};
if (vkCreateXlibSurfaceKHR(g_gpu.instance, &surface_info, &g_gpu.alloc_cb, &g_gpu.surface) ==
if (vkCreateXlibSurfaceKHR(g_gpu.instance, &surface_info, g_gpu.alloc_cb, &g_gpu.surface) ==
VK_SUCCESS)
return RT_SUCCESS;
else

View File

@ -27,16 +27,16 @@ if vk_dep.found()
'swapchain.c',
# Contrib Sources
contrib_dir / 'volk/volk.h',
contrib_dir / 'volk/volk.c',
contrib_dir / 'vma/vk_mem_alloc.h',
'../../../contrib/volk/volk.h',
'../../../contrib/volk/volk.c',
'../../../contrib/vma/vk_mem_alloc.h',
'vma_impl.cpp',
dependencies : [m_dep, vk_inc_dep, windowing_dep],
include_directories : [engine_incdir, include_directories(contrib_dir)],
include_directories : [engine_incdir, contrib_incdir],
link_with : [runtime_lib],
c_pch : 'pch/vk_pch.h',
c_args : platform_defs,
cpp_pch : 'pch/vk_pch.h',
cpp_pch : 'pch/vk_pch.hpp',
cpp_args : platform_defs,
install : true)

View File

@ -0,0 +1,3 @@
extern "C" {
#include "vk_pch.h"
}

View File

@ -1,7 +1,21 @@
#ifdef _MSC_VER
#pragma warning(push, 0)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#pragma GCC diagnostic ignored "-Wmissing-braces"
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
#pragma GCC diagnostic ignored "-Wconversion"
#pragma GCC diagnostic ignored "-Wunused-variable"
#pragma GCC diagnostic ignored "-Wparentheses"
#endif
#include <volk/volk.h>
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_STATIC_VULKAN_FUNCTIONS 0
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 0
#define VMA_IMPLEMENTATION
#include <vma/vk_mem_alloc.h>
#pragma warning(pop)
#ifdef _MSC_VER
#pragma warning(pop)
#elif defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif

View File

@ -313,7 +313,7 @@ RT_DLLEXPORT rt_result rtSubmitWriteBatch(const rt_write_batch *batch, rt_aio_ha
return RT_SUCCESS;
}
RT_DLLEXPORT volatile rt_aio_state rtGetAIOState(rt_aio_handle handle) {
RT_DLLEXPORT rt_aio_state rtGetAIOState(rt_aio_handle handle) {
if (handle == RT_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity)
return RT_AIO_STATE_INVALID;
#ifdef _WIN32
@ -374,4 +374,4 @@ RT_DLLEXPORT rt_aio_state rtSubmitSingleLoadSync(rt_file_load load) {
rt_aio_state state = rtWaitForAIOCompletion(handle);
rtReleaseAIO(handle);
return state;
}
}

View File

@ -73,14 +73,13 @@ typedef enum {
RT_AIO_STATE_FAILED,
} rt_aio_state;
RT_DLLEXPORT volatile rt_aio_state rtGetAIOState(rt_aio_handle handle);
RT_DLLEXPORT 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. */
RT_DLLEXPORT rt_aio_state rtWaitForAIOCompletion(rt_aio_handle handle);
RT_DLLEXPORT rt_result rtSubmitLoadBatch(const rt_load_batch *batch, rt_aio_handle *handles);
/* Releases the internal storage for the operation.

View File

@ -78,7 +78,7 @@ extern rt_result InitBufferManager(void) {
if (!_memory) {
return RT_OUT_OF_MEMORY;
}
_bitmap = (uint32_t*)(_memory + budget);
_bitmap = (uint32_t *)(_memory + budget);
memset(_bitmap, 0, sizeof(uint32_t) * dword_count);
return RT_SUCCESS;
@ -94,23 +94,19 @@ RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
size_t alloc_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
size_t dword_count = (_block_count + 31) / 32;
void *result = NULL;
size_t first_block = 0;
rtLockMutex(_guard);
for (size_t i = 0; i < _block_count; ++i) {
size_t dword = i / 32;
if (_bitmap[dword] == 0 || tzcnt32(_bitmap[dword]) >= alloc_blocks) {
if (_bitmap[dword] == 0 || (size_t)tzcnt32(_bitmap[dword]) >= alloc_blocks) {
size_t mask = (1ull << alloc_blocks) - 1;
_bitmap[dword] |= mask;
result = _memory + i * BLOCK_SIZE;
first_block = i;
_bitmap[dword] |= (uint32_t)mask;
result = _memory + i * BLOCK_SIZE;
break;
}
else if (lzcnt32(_bitmap[dword]) >= alloc_blocks) {
} else if ((size_t)lzcnt32(_bitmap[dword]) >= alloc_blocks) {
size_t first = (_bitmap[dword] != 0) ? 32 - lzcnt32(_bitmap[dword]) : 0;
size_t mask = ((1ull << alloc_blocks) - 1) << first;
_bitmap[dword] |= mask;
result = _memory + (i + first) * BLOCK_SIZE;
first_block = i + first;
_bitmap[dword] |= (uint32_t)mask;
result = _memory + (i + first) * BLOCK_SIZE;
break;
} else if (_bitmap[dword] != UINT32_MAX) {
size_t first = 32 - lzcnt32(_bitmap[dword]);
@ -124,9 +120,8 @@ RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
continue;
_bitmap[dword] = UINT32_MAX;
size_t mask = (1ull << leftover) - 1;
_bitmap[dword + 1] |= mask;
result = _memory + (i + first) * BLOCK_SIZE;
first_block = i + first;
_bitmap[dword + 1] |= (uint32_t)mask;
result = _memory + (i + first) * BLOCK_SIZE;
break;
} else {
// Check each bit separately
@ -145,8 +140,7 @@ RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
size_t bitj = j % 32;
_bitmap[dwordj] |= (1u << bitj);
}
result = _memory + (i + first) * BLOCK_SIZE;
first_block = i + first;
result = _memory + (i + first) * BLOCK_SIZE;
}
}
} else {
@ -161,8 +155,8 @@ RT_DLLEXPORT void *rtAllocBuffer(size_t size) {
}
RT_DLLEXPORT void rtReleaseBuffer(const void *begin, size_t size) {
size_t alloc_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
uintptr_t off = (uintptr_t)begin - (uintptr_t)_memory;
size_t alloc_blocks = (size + BLOCK_SIZE - 1) / BLOCK_SIZE;
uintptr_t off = (uintptr_t)begin - (uintptr_t)_memory;
uintptr_t first_block = off / BLOCK_SIZE;
rtLockMutex(_guard);
for (size_t i = first_block; i < first_block + alloc_blocks; ++i) {

View File

@ -18,6 +18,7 @@
/* TODO(Kevin): Log to file, show error message box, ... */
#ifdef _WIN32
void Win32ErrorToString(DWORD last_error, char *out, int bufsize) {
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_ALLOCATE_BUFFER,
@ -28,6 +29,7 @@ void Win32ErrorToString(DWORD last_error, char *out, int bufsize) {
bufsize,
NULL);
}
#endif
static bool DisplayErrorBox(const char *text) {
#ifdef _WIN32
@ -81,4 +83,4 @@ RT_DLLEXPORT void rtLog(const char *subsystem, const char *fmt, ...) {
at += rtSPrint(&buf[at], RT_ARRAY_COUNT(buf) - at, "\n");
LogOut(buf);
}
}

View File

@ -14,7 +14,7 @@ struct rt_scandir_handle_s {
static rt_scandir_handle _dirs[256];
static unsigned int _next = 0;
static rt_mutex *_guard = NULL;
static rt_mutex *_guard = NULL;
RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
char wildcard_path[MAX_PATH];
@ -38,7 +38,7 @@ RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
rtLockMutex(_guard);
rt_scandir_handle *dir = &_dirs[_next];
_next = (_next + 1) % RT_ARRAY_COUNT(_dirs);
_next = (_next + 1) % RT_ARRAY_COUNT(_dirs);
rtUnlockMutex(_guard);
if (dir->handle != NULL) {
@ -47,7 +47,7 @@ RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
return NULL;
}
dir->handle = h;
dir->handle = h;
dir->next.is_last = false;
rtWStrToUTF8(data.cFileName, dir->next.name, 260);
if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
@ -61,7 +61,7 @@ RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
RT_DLLEXPORT rt_dirent rtNextDirectoryEntry(rt_scandir_handle *dir) {
rt_dirent current;
memcpy(&current, &dir->next, sizeof(rt_dirent));
WIN32_FIND_DATAW data;
if (!FindNextFileW(dir->handle, &data)) {
current.is_last = true;
@ -73,7 +73,6 @@ RT_DLLEXPORT rt_dirent rtNextDirectoryEntry(rt_scandir_handle *dir) {
else
dir->next.type = RT_DIRENT_TYPE_FILE;
return current;
}
@ -118,4 +117,108 @@ uint64_t rtGetFileModificationTimestamp(const char *path) {
return ts;
}
#endif
#elif defined(__linux__)
#include <string.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <time.h>
struct rt_scandir_handle_s {
DIR *handle;
rt_dirent next;
};
static rt_scandir_handle _dirs[256];
static unsigned int _next = 0;
static rt_mutex *_guard = NULL;
RT_DLLEXPORT rt_scandir_handle *rtScanDirectory(const char *path) {
DIR *h = opendir(path);
if (!h)
return NULL;
if (!_guard) {
_guard = rtCreateMutex();
if (!_guard) {
closedir(h);
return NULL;
}
}
rtLockMutex(_guard);
rt_scandir_handle *dir = &_dirs[_next];
_next = (_next + 1) % RT_ARRAY_COUNT(_dirs);
rtUnlockMutex(_guard);
if (dir->handle != NULL) {
rtLog("core", "Failed to acquire a scandir handle.");
closedir(h);
return NULL;
}
struct dirent *ent = readdir(h);
if (!ent) {
closedir(h);
return NULL;
}
dir->handle = h;
dir->next.is_last = false;
memcpy(dir->next.name, ent->d_name, 255);
if (ent->d_type == DT_DIR)
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
else
dir->next.type = RT_DIRENT_TYPE_FILE;
return dir;
}
RT_DLLEXPORT rt_dirent rtNextDirectoryEntry(rt_scandir_handle *dir) {
rt_dirent current;
memcpy(&current, &dir->next, sizeof(rt_dirent));
struct dirent *ent = readdir(dir->handle);
if (!ent) {
current.is_last = true;
return current;
}
memcpy(dir->next.name, ent->d_name, 255);
if (ent->d_type == DT_DIR)
dir->next.type = RT_DIRENT_TYPE_DIRECTORY;
else
dir->next.type = RT_DIRENT_TYPE_FILE;
return current;
}
RT_DLLEXPORT void rtCloseDirectory(rt_scandir_handle *dir) {
if (!dir)
return;
closedir(dir->handle);
dir->handle = NULL;
}
RT_DLLEXPORT bool rtCreateDirectory(const char *path) {
return mkdir(path, S_IRWXU | S_IRGRP) == 0;
}
RT_DLLEXPORT size_t rtGetFileSize(const char *path) {
struct stat st;
if (stat(path, &st) != 0)
return 0;
return (size_t)st.st_size;
}
uint64_t rtGetCurrentTimestamp(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint64_t)ts.tv_sec;
}
uint64_t rtGetFileModificationTimestamp(const char *path) {
struct stat st;
if (stat(path, &st) != 0)
return 0;
return (uint64_t)st.st_mtim.tv_sec;
}
#endif

View File

@ -1,6 +1,6 @@
# Runtime
runtime_deps = [thread_dep, m_dep, windowing_dep]
runtime_incdirs = include_directories(meson.project_source_root() / 'contrib')
runtime_incdirs = contrib_incdir
runtime_lib = library('rt',
# Project Sources
'aio.h',

View File

@ -179,14 +179,14 @@ static void CopyResourceData(const rt_resource *resource, void *dest) {
}
}
char *names_begin = (char *)read_write_dest;
char *names_begin = (char *)read_write_dest;
const char *src_names = rtResolveConstRelptr(&info->names);
memcpy(names_begin, src_names, info->names_size);
rtSetRelptr(&dest_info->names, names_begin);
dest_info->names_size = info->names_size;
const rt_render_target_info *src_rts = rtResolveConstRelptr(&info->render_targets);
rt_render_target_info *rts = (rt_render_target_info *)(dest_info + 1);
rt_render_target_info *rts = (rt_render_target_info *)(dest_info + 1);
for (uint32_t i = 0; i < info->render_target_count; ++i) {
const char *src_name = rtResolveConstRelptr(&src_rts[i].name);
if (src_name)
@ -277,7 +277,7 @@ static rt_result InitResourceCache(void) {
_cache.resource_lock = resource_lock_create.lock;
for (int i = 0; i < count; ++i) {
_cache.resources[i].next_free = (i < count - 1) ? i + 1 : UINT_MAX;
_cache.resources[i].next_free = (i < count - 1) ? (unsigned int)i + 1 : UINT_MAX;
}
_cache.first_free = 0;
@ -1046,11 +1046,11 @@ RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resour
(writes[j].flags & RT_RENDER_TARGET_WRITE_DISCARD) ? "YES" : "NO");
rtLog("RESMGR",
" clear_value: {rgba: {%f %f %f %f}, ds: {%f %u}}",
writes[j].clear.color.r,
writes[j].clear.color.g,
writes[j].clear.color.b,
writes[j].clear.color.a,
writes[j].clear.depth_stencil.depth,
(double)writes[j].clear.color.r,
(double)writes[j].clear.color.g,
(double)writes[j].clear.color.b,
(double)writes[j].clear.color.a,
(double)writes[j].clear.depth_stencil.depth,
writes[j].clear.depth_stencil.stencil);
}
}
@ -1116,4 +1116,4 @@ RT_DLLEXPORT void rtSaveResourceNamespace(void) {
out:
rtUnlockRead(&_namespace.lock);
rtReturnTemporaryArena(temp);
}
}

View File

@ -2,6 +2,17 @@
#define RT_MATH_H
/* Math types and functions */
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
struct vec2 {
struct xy {
float x;
float y;
};
};
/* 2d vector */
typedef union {
@ -30,4 +41,9 @@ typedef struct {
rt_v2i offset;
rt_v2i size;
} rt_rect2i;
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
#endif

View File

@ -3,6 +3,7 @@
/* basic types and macros */
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
@ -28,12 +29,14 @@ extern "C" {
#define RT_UNUSED(x) ((void)sizeof((x)))
#define RT_ARRAY_COUNT(x) (sizeof((x)) / sizeof((x)[0]))
#define RT_RESTRICT_VALUE_TO_BOUNDS(v, lower, upper) (((v) < (lower)) ? (lower) : (((v) > (upper)) ? (upper) : (v)))
#define RT_RESTRICT_VALUE_TO_BOUNDS(v, lower, upper) \
(((v) < (lower)) ? (lower) : (((v) > (upper)) ? (upper) : (v)))
#define RT_KB(n) ((n)*1024U)
#define RT_MB(n) ((n)*1024U * 1024U)
#define RT_GB(n) ((n)*1024U * 1024U * 1024U)
#ifndef __cplusplus
#if defined(_MSC_VER)
/* For some reason _Thread_local does not work with vs2022,
* despite MS documentation claiming it should. */
@ -45,9 +48,22 @@ extern "C" {
#elif __STDC_VERSION__ >= 201112L
#define RT_THREAD_LOCAL _Thread_local
#else
#pragma error Pre-C11 not supported.
#error Versions older than C11 not supported.
#endif
#endif
#else
// C++ 11 supports thread_local
#if __cplusplus >= 201103L
#define RT_THREAD_LOCAL thread_local
#elif defined(_MSC_VER)
#define RT_THREAD_LOCAL __declspec(thread)
#else
#error Versions older than C++11 not supported.
#endif
#endif
/* Matches windows MAX_PATH */
#define RT_PATH_MAX 260
typedef unsigned int rt_result;
@ -59,7 +75,7 @@ enum {
RT_CUSTOM_ERROR_START,
RT_UNKNOWN_ERROR = (rt_result)-1,
RT_UNKNOWN_ERROR = (rt_result)INT_MAX,
};
typedef struct {

View File

@ -5,6 +5,9 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#elif defined(__linux__)
#include <uchar.h>
#endif
RT_DLLEXPORT int rtCompareSpanToString(rt_text_span span, const char *cmp) {
@ -18,6 +21,9 @@ RT_DLLEXPORT int rtCompareSpanToString(rt_text_span span, const char *cmp) {
return 0;
}
/* These should not be necessary on linux. If we ever run into this problem,
* they could be implemented pretty easily. */
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);
@ -34,10 +40,11 @@ RT_DLLEXPORT rt_result rtUTF8ToWStr(const char *utf8, wchar_t *wstr, size_t len)
return RT_UNKNOWN_ERROR;
}
}
#elif defined(__linux__)
return RT_UNKNOWN_ERROR;
#endif
}
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);
@ -54,5 +61,7 @@ RT_DLLEXPORT rt_result rtWStrToUTF8(const wchar_t *wstr, char *utf8, size_t len)
return RT_UNKNOWN_ERROR;
}
}
#elif defined(__linux__)
return RT_UNKNOWN_ERROR;
#endif
}
}

View File

@ -129,8 +129,8 @@ RT_DLLEXPORT void rtSleep(unsigned int milliseconds) {
#elif defined(__linux__)
#define _GNU_SOURCE
#include <pthread.h>
#include <sys/types.h>
#include <unistd.h>
#if _POSIX_C_SOURCE >= 199309L
#include <time.h>
@ -151,8 +151,14 @@ static rt_thread _threads[MAX_THREADS];
static ptrdiff_t _first_reusable = MAX_THREADS;
static ptrdiff_t _next = 0;
static rt_thread_id _main_thread_id;
static pthread_mutex_t _guard = PTHREAD_MUTEX_INITIALIZER;
extern void SetMainThreadId(void) {
_main_thread_id = (rt_thread_id)gettid();
}
static void *linuxThreadWrapper(void *arg) {
rt_thread *user_thread = arg;
user_thread->needs_join = false;
@ -208,7 +214,7 @@ RT_DLLEXPORT unsigned int rtGetCPUCoreCount(void) {
}
RT_DLLEXPORT rt_thread_id rtGetCurrentThreadId(void) {
return (rt_thread_id)GetCurrentThreadId();
return (rt_thread_id)gettid();
}
RT_DLLEXPORT bool rtIsMainThread(void) {