Progress on assetc
This commit is contained in:
		
							parent
							
								
									4a0231a79b
								
							
						
					
					
						commit
						19f7e29215
					
				@ -14,5 +14,6 @@ AlwaysBreakAfterReturnType: None
 | 
				
			|||||||
BinPackArguments: false
 | 
					BinPackArguments: false
 | 
				
			||||||
BinPackParameters: false
 | 
					BinPackParameters: false
 | 
				
			||||||
BreakBeforeBraces: Attach
 | 
					BreakBeforeBraces: Attach
 | 
				
			||||||
IndentPPDirectives: BeforeHash
 | 
					IndentPPDirectives: None
 | 
				
			||||||
PointerAlignment: Right 
 | 
					PointerAlignment: Right 
 | 
				
			||||||
 | 
					ColumnLimit: 100
 | 
				
			||||||
							
								
								
									
										1
									
								
								.clang-format-ignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.clang-format-ignore
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					contrib/**/*
 | 
				
			||||||
							
								
								
									
										2
									
								
								contrib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								contrib/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					# Placed there by scripts/download_shaderc.bat
 | 
				
			||||||
 | 
					shaderc/*
 | 
				
			||||||
							
								
								
									
										80
									
								
								meson.build
									
									
									
									
									
								
							
							
						
						
									
										80
									
								
								meson.build
									
									
									
									
									
								
							@ -22,7 +22,11 @@ elif compiler.get_argument_syntax() == 'msvc'
 | 
				
			|||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if get_option('default_library') == 'static'
 | 
					if get_option('default_library') == 'static'
 | 
				
			||||||
    add_project_arguments(['-DVY_STATIC_LIB'], language : 'c')
 | 
					  add_project_arguments(['-DVY_STATIC_LIB'], language : 'c')
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if get_option('error_report_debugbreak')
 | 
				
			||||||
 | 
					  add_project_arguments(['-DVY_ERROR_REPORT_DEBUGBREAK'], language : 'c')
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Debug specific flags
 | 
					# Debug specific flags
 | 
				
			||||||
@ -45,32 +49,32 @@ incdir = include_directories(['contrib', 'src'])
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
runtime_lib = library('vyrt',
 | 
					runtime_lib = library('vyrt',
 | 
				
			||||||
  # Project Sources
 | 
					  # Project Sources
 | 
				
			||||||
  'src/runtime/runtime.h',
 | 
					 | 
				
			||||||
  'src/runtime/gfx.h',
 | 
					 | 
				
			||||||
  'src/runtime/renderer_api.h',
 | 
					 | 
				
			||||||
  'src/runtime/config.h',
 | 
					 | 
				
			||||||
  'src/runtime/threading.h',
 | 
					 | 
				
			||||||
  'src/runtime/app.h',
 | 
					 | 
				
			||||||
  'src/runtime/dynamic_libs.h',
 | 
					 | 
				
			||||||
  'src/runtime/jobs.h',
 | 
					 | 
				
			||||||
  'src/runtime/aio.h',
 | 
					  'src/runtime/aio.h',
 | 
				
			||||||
  'src/runtime/file_tab.h',
 | 
					  'src/runtime/app.h',
 | 
				
			||||||
  'src/runtime/buffer_manager.h',
 | 
					 | 
				
			||||||
  'src/runtime/assets.h',
 | 
					  'src/runtime/assets.h',
 | 
				
			||||||
 | 
					  'src/runtime/buffer_manager.h',
 | 
				
			||||||
  'src/runtime/error_report.c',
 | 
					  'src/runtime/config.h',
 | 
				
			||||||
  'src/runtime/gfx_main.c',
 | 
					  'src/runtime/dynamic_libs.h',
 | 
				
			||||||
 | 
					  'src/runtime/file_tab.h',
 | 
				
			||||||
 | 
					  'src/runtime/gfx.h',
 | 
				
			||||||
 | 
					  'src/runtime/jobs.h',
 | 
				
			||||||
 | 
					  'src/runtime/renderer_api.h',
 | 
				
			||||||
 | 
					  'src/runtime/runtime.h',
 | 
				
			||||||
 | 
					  'src/runtime/threading.h',
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  'src/runtime/aio.c',
 | 
				
			||||||
 | 
					  'src/runtime/app.c',
 | 
				
			||||||
 | 
					  'src/runtime/buffer_manager.c',
 | 
				
			||||||
  'src/runtime/config.c',
 | 
					  'src/runtime/config.c',
 | 
				
			||||||
 | 
					  'src/runtime/error_report.c',
 | 
				
			||||||
 | 
					  'src/runtime/file_tab.c',
 | 
				
			||||||
 | 
					  'src/runtime/gfx_main.c',
 | 
				
			||||||
 | 
					  'src/runtime/jobs.c',
 | 
				
			||||||
  'src/runtime/runtime_cvars.c',
 | 
					  'src/runtime/runtime_cvars.c',
 | 
				
			||||||
 | 
					  'src/runtime/text.c',
 | 
				
			||||||
 | 
					  'src/runtime/threading_cond.c',
 | 
				
			||||||
  'src/runtime/threading_mutex.c',
 | 
					  'src/runtime/threading_mutex.c',
 | 
				
			||||||
  'src/runtime/threading_thread.c',
 | 
					  'src/runtime/threading_thread.c',
 | 
				
			||||||
  'src/runtime/threading_cond.c',
 | 
					 | 
				
			||||||
  'src/runtime/app.c',
 | 
					 | 
				
			||||||
  'src/runtime/dynamic_libs.c',
 | 
					 | 
				
			||||||
  'src/runtime/jobs.c',
 | 
					 | 
				
			||||||
  'src/runtime/aio.c',
 | 
					 | 
				
			||||||
  'src/runtime/file_tab.c',
 | 
					 | 
				
			||||||
  'src/runtime/buffer_manager.c',
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Contrib Sources
 | 
					  # Contrib Sources
 | 
				
			||||||
  'contrib/xxhash/xxhash.c',
 | 
					  'contrib/xxhash/xxhash.c',
 | 
				
			||||||
@ -112,21 +116,39 @@ if vk_dep.found()
 | 
				
			|||||||
  static_renderer_lib = vk_renderer_lib
 | 
					  static_renderer_lib = vk_renderer_lib
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					shaderc_include = include_directories('contrib/shaderc/libshaderc/include')
 | 
				
			||||||
 | 
					shaderc_libdir = 'NONE'
 | 
				
			||||||
 | 
					if host_machine.system() == 'windows'
 | 
				
			||||||
 | 
					  shaderc_libdir = meson.project_source_root() / 'contrib/shaderc/build-win/libshaderc/Release'
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Asset Compiler Tool
 | 
					# Asset Compiler Tool
 | 
				
			||||||
executable('assetc',
 | 
					executable('assetc',
 | 
				
			||||||
 | 
					  'src/tools/assetc/assetmeta.h',
 | 
				
			||||||
 | 
					  'src/tools/assetc/description_parser.h',
 | 
				
			||||||
 | 
					  'src/tools/assetc/options.h',
 | 
				
			||||||
 | 
					  'src/tools/assetc/packages.h',
 | 
				
			||||||
  'src/tools/assetc/processing.h',
 | 
					  'src/tools/assetc/processing.h',
 | 
				
			||||||
 | 
					  'src/tools/assetc/processing_flags.h',
 | 
				
			||||||
  'src/tools/assetc/utils.h',
 | 
					  'src/tools/assetc/utils.h',
 | 
				
			||||||
  
 | 
					
 | 
				
			||||||
  'src/tools/assetc/assetc.c',
 | 
					  'src/tools/assetc/assetc.c',
 | 
				
			||||||
  'src/tools/assetc/processor.c',
 | 
					  'src/tools/assetc/assetmeta.c',
 | 
				
			||||||
 | 
					  'src/tools/assetc/description_parser.c',
 | 
				
			||||||
 | 
					  'src/tools/assetc/discovery.c',
 | 
				
			||||||
 | 
					  'src/tools/assetc/packages.c',
 | 
				
			||||||
  'src/tools/assetc/pipeline_processor.c',
 | 
					  'src/tools/assetc/pipeline_processor.c',
 | 
				
			||||||
 | 
					  'src/tools/assetc/processor.c',
 | 
				
			||||||
  'src/tools/assetc/shader_processor.c',
 | 
					  'src/tools/assetc/shader_processor.c',
 | 
				
			||||||
 | 
					  'src/tools/assetc/uidtable.c',
 | 
				
			||||||
  'src/tools/assetc/utils.c',
 | 
					  'src/tools/assetc/utils.c',
 | 
				
			||||||
  'src/tools/assetc/uidmap.c',
 | 
					
 | 
				
			||||||
  include_directories : incdir,
 | 
					  # Contrib sources
 | 
				
			||||||
 | 
					  'contrib/xxhash/xxhash.c',
 | 
				
			||||||
 | 
					  include_directories : [incdir, shaderc_include],
 | 
				
			||||||
  dependencies : [],
 | 
					  dependencies : [],
 | 
				
			||||||
  link_with : [runtime_lib],
 | 
					  link_with : [runtime_lib],
 | 
				
			||||||
 | 
					  link_args : ['-L'+shaderc_libdir, '-lshaderc_combined'],
 | 
				
			||||||
  win_subsystem : 'console')
 | 
					  win_subsystem : 'console')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Game
 | 
					# Game
 | 
				
			||||||
@ -143,4 +165,10 @@ executable('voyage',
 | 
				
			|||||||
  link_with : game_link_libs,
 | 
					  link_with : game_link_libs,
 | 
				
			||||||
  win_subsystem : 'windows')
 | 
					  win_subsystem : 'windows')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Unit Tests
 | 
				
			||||||
 | 
					rttest_exe = executable('rttest',
 | 
				
			||||||
 | 
					  'src/tests/rttest.c',
 | 
				
			||||||
 | 
					  link_with : [runtime_lib],
 | 
				
			||||||
 | 
					  include_directories : incdir,
 | 
				
			||||||
 | 
					  win_subsystem : 'console')
 | 
				
			||||||
 | 
					test('runtime test', rttest_exe)
 | 
				
			||||||
@ -1 +1,2 @@
 | 
				
			|||||||
option('use_xlib', type : 'boolean', value : false, description : 'Use Xlib for window creation under linux')
 | 
					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 vyReportError')
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,3 @@
 | 
				
			|||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										35
									
								
								scripts/download_shaderc.bat
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								scripts/download_shaderc.bat
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,35 @@
 | 
				
			|||||||
 | 
					@echo off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					REM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					REM 
 | 
				
			||||||
 | 
					REM Downloads shaderc from github into contrib/
 | 
				
			||||||
 | 
					REM 
 | 
				
			||||||
 | 
					REM Last changed: 24/11/23 (DD/MM/YY)
 | 
				
			||||||
 | 
					REM 
 | 
				
			||||||
 | 
					REM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SETLOCAL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SET SHADERC_VER=v2023.7
 | 
				
			||||||
 | 
					SET SHADERC_REPO=https://github.com/google/shaderc.git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					REM Check if we are beeing run from scripts/ or from root
 | 
				
			||||||
 | 
					IF EXIST meson.build GOTO :DOWNLOAD
 | 
				
			||||||
 | 
					CD ..
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					:DOWNLOAD
 | 
				
			||||||
 | 
					git clone --quiet %SHADERC_REPO% contrib\shaderc
 | 
				
			||||||
 | 
					PUSHD contrib\shaderc
 | 
				
			||||||
 | 
					git checkout --quiet %SHADERC_VER%
 | 
				
			||||||
 | 
					python3 .\utils\git-sync-deps
 | 
				
			||||||
 | 
					RMDIR /S /Q .git
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MKDIR build-win
 | 
				
			||||||
 | 
					PUSHD build-win
 | 
				
			||||||
 | 
					cmake ..
 | 
				
			||||||
 | 
					cmake --build . --config Release
 | 
				
			||||||
 | 
					POPD 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					POPD
 | 
				
			||||||
 | 
					ENDLOCAL
 | 
				
			||||||
							
								
								
									
										1
									
								
								shader/cell.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								shader/cell.as
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package pipelines.pkg;
 | 
				
			||||||
@ -1,5 +1,11 @@
 | 
				
			|||||||
vertex shader/cell_vert.shader;
 | 
					optimization speed;
 | 
				
			||||||
fragment shader/cell_frag.shader;
 | 
					
 | 
				
			||||||
 | 
					vertex {
 | 
				
			||||||
 | 
					    vk shader/cell_vert.glsl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					fragment {
 | 
				
			||||||
 | 
					    vk shader/cell_frag.glsl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
texture_bindings {
 | 
					texture_bindings {
 | 
				
			||||||
    0 MATERIAL_ALBEDO;
 | 
					    0 MATERIAL_ALBEDO;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								shader/cell_frag.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								shader/cell_frag.as
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package shaders.pkg;
 | 
				
			||||||
							
								
								
									
										8
									
								
								shader/cell_frag.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								shader/cell_frag.glsl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#version 450
 | 
				
			||||||
 | 
					#pragma shader_stage(fragment)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					layout (location = 0) out vec3 color;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    color = vec3(1, 1, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								shader/cell_vert.as
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								shader/cell_vert.as
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					package shaders.pkg;
 | 
				
			||||||
							
								
								
									
										6
									
								
								shader/cell_vert.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								shader/cell_vert.glsl
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					#version 450
 | 
				
			||||||
 | 
					#pragma shader_stage(vertex)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void main() {
 | 
				
			||||||
 | 
					    gl_Position = vec4(0, 0, 0, 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,4 +0,0 @@
 | 
				
			|||||||
#define VY_SHADER_TYPE_VERT
 | 
					 | 
				
			||||||
#ifdef VY_SHADER_VK
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
@ -2,13 +2,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int WINAPI wWinMain(HINSTANCE hInstance,
 | 
					int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
 | 
				
			||||||
                    HINSTANCE hPrevInstance,
 | 
					 | 
				
			||||||
                    PWSTR pCmdLine,
 | 
					 | 
				
			||||||
                    int nCmdShow) {
 | 
					 | 
				
			||||||
    return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
					    return vyWin32Entry(hInstance, hPrevInstance, pCmdLine, nCmdShow);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -52,7 +52,8 @@ static void ReleasePipelineSlot(vy_gfx_pipeline_handle id) {
 | 
				
			|||||||
        _storage.generation_in_use[slot] &= ~0x1;
 | 
					        _storage.generation_in_use[slot] &= ~0x1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compute_pipeline_info *info) {
 | 
					vy_gfx_pipeline_handle
 | 
				
			||||||
 | 
					VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compute_pipeline_info *info) {
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
    char info_log[512];
 | 
					    char info_log[512];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -93,7 +94,8 @@ vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compu
 | 
				
			|||||||
    return StorePipeline(pipeline);
 | 
					    return StorePipeline(pipeline);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileGraphicsPipeline)(const vy_graphics_pipeline_info *info) {
 | 
					vy_gfx_pipeline_handle
 | 
				
			||||||
 | 
					VY_RENDERER_API_FN(CompileGraphicsPipeline)(const vy_graphics_pipeline_info *info) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
    char info_log[512];
 | 
					    char info_log[512];
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <volk/volk.h>
 | 
					#include <volk/volk.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
struct HINSTANCE__;
 | 
					struct HINSTANCE__;
 | 
				
			||||||
struct HWND__;
 | 
					struct HWND__;
 | 
				
			||||||
@ -21,7 +20,6 @@ typedef struct {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
} vy_native_window;
 | 
					} vy_native_window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    VkInstance instance;
 | 
					    VkInstance instance;
 | 
				
			||||||
    VkDebugUtilsMessengerEXT messenger;
 | 
					    VkDebugUtilsMessengerEXT messenger;
 | 
				
			||||||
 | 
				
			|||||||
@ -10,14 +10,11 @@
 | 
				
			|||||||
#include "runtime/renderer_api.h"
 | 
					#include "runtime/renderer_api.h"
 | 
				
			||||||
#include "runtime/runtime.h"
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_I(
 | 
					VY_CVAR_I(r_VkEnableAPIAllocTracking,
 | 
				
			||||||
    r_VkEnableAPIAllocTracking,
 | 
					          "Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
 | 
				
			||||||
    "Enable tracking of allocations done by the vulkan api. [0/1] Default: 0",
 | 
					          0);
 | 
				
			||||||
    0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_S(r_VkPhysDeviceName,
 | 
					VY_CVAR_S(r_VkPhysDeviceName, "Name of the selected physical device. Default: \"\"", "");
 | 
				
			||||||
          "Name of the selected physical device. Default: \"\"",
 | 
					 | 
				
			||||||
          "");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_vk_gpu g_gpu;
 | 
					vy_vk_gpu g_gpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,10 +37,8 @@ static const char *AllocationScopeToString(VkSystemAllocationScope scope) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *TrackAllocation(void *userData,
 | 
					static void *
 | 
				
			||||||
                             size_t size,
 | 
					TrackAllocation(void *userData, size_t size, size_t alignment, VkSystemAllocationScope scope) {
 | 
				
			||||||
                             size_t alignment,
 | 
					 | 
				
			||||||
                             VkSystemAllocationScope scope) {
 | 
					 | 
				
			||||||
    vyLog("vk",
 | 
					    vyLog("vk",
 | 
				
			||||||
          "Allocation. Size: %zu, Alignment: %zu, Scope: %s",
 | 
					          "Allocation. Size: %zu, Alignment: %zu, Scope: %s",
 | 
				
			||||||
          size,
 | 
					          size,
 | 
				
			||||||
@ -127,13 +122,11 @@ static vy_result CreateInstance(void) {
 | 
				
			|||||||
    uint32_t available_layer_count = 0;
 | 
					    uint32_t available_layer_count = 0;
 | 
				
			||||||
    result = vkEnumerateInstanceLayerProperties(&available_layer_count, NULL);
 | 
					    result = vkEnumerateInstanceLayerProperties(&available_layer_count, NULL);
 | 
				
			||||||
    if (result == VK_SUCCESS) {
 | 
					    if (result == VK_SUCCESS) {
 | 
				
			||||||
        VkLayerProperties *props =
 | 
					        VkLayerProperties *props = calloc(available_layer_count, sizeof(VkLayerProperties));
 | 
				
			||||||
            calloc(available_layer_count, sizeof(VkLayerProperties));
 | 
					 | 
				
			||||||
        if (props) {
 | 
					        if (props) {
 | 
				
			||||||
            vkEnumerateInstanceLayerProperties(&available_layer_count, props);
 | 
					            vkEnumerateInstanceLayerProperties(&available_layer_count, props);
 | 
				
			||||||
            for (uint32_t i = 0; i < available_layer_count; ++i) {
 | 
					            for (uint32_t i = 0; i < available_layer_count; ++i) {
 | 
				
			||||||
                if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") ==
 | 
					                if (strcmp(props[i].layerName, "VK_LAYER_KHRONOS_validation") == 0) {
 | 
				
			||||||
                    0) {
 | 
					 | 
				
			||||||
                    layers[0]   = "VK_LAYER_KHRONOS_validation";
 | 
					                    layers[0]   = "VK_LAYER_KHRONOS_validation";
 | 
				
			||||||
                    layer_count = 1;
 | 
					                    layer_count = 1;
 | 
				
			||||||
                    break;
 | 
					                    break;
 | 
				
			||||||
@ -141,8 +134,7 @@ static vy_result CreateInstance(void) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            free(props);
 | 
					            free(props);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            vyLog("vk",
 | 
					            vyLog("vk", "Failed to allocate storage for instance layer properties.");
 | 
				
			||||||
                  "Failed to allocate storage for instance layer properties.");
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyLog("vk", "vkEnumerateInstanceLayerProperties failed.");
 | 
					        vyLog("vk", "vkEnumerateInstanceLayerProperties failed.");
 | 
				
			||||||
@ -167,7 +159,7 @@ static vy_result CreateInstance(void) {
 | 
				
			|||||||
#ifdef VY_DEBUG
 | 
					#ifdef VY_DEBUG
 | 
				
			||||||
    /* Create the debug utils messenger */
 | 
					    /* Create the debug utils messenger */
 | 
				
			||||||
    VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
 | 
					    VkDebugUtilsMessengerCreateInfoEXT messenger_info = {
 | 
				
			||||||
        .sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
					        .sType           = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
 | 
				
			||||||
        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
 | 
					        .messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
 | 
				
			||||||
                           VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
 | 
					                           VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
 | 
				
			||||||
        .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
 | 
					        .messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |
 | 
				
			||||||
@ -191,10 +183,8 @@ static vy_result CreateSurface(const vy_renderer_init_info *info) {
 | 
				
			|||||||
        .hinstance = info->hInstance,
 | 
					        .hinstance = info->hInstance,
 | 
				
			||||||
        .hwnd      = info->hWnd,
 | 
					        .hwnd      = info->hWnd,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    if (vkCreateWin32SurfaceKHR(g_gpu.instance,
 | 
					    if (vkCreateWin32SurfaceKHR(g_gpu.instance, &surface_info, g_gpu.alloc_cb, &g_gpu.surface) ==
 | 
				
			||||||
                                &surface_info,
 | 
					        VK_SUCCESS)
 | 
				
			||||||
                                g_gpu.alloc_cb,
 | 
					 | 
				
			||||||
                                &g_gpu.surface) == VK_SUCCESS)
 | 
					 | 
				
			||||||
        return VY_SUCCESS;
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        return 100;
 | 
					        return 100;
 | 
				
			||||||
@ -206,10 +196,8 @@ static vy_result CreateSurface(const vy_renderer_init_info *info) {
 | 
				
			|||||||
        .dpy    = info->display,
 | 
					        .dpy    = info->display,
 | 
				
			||||||
        .window = info->window,
 | 
					        .window = info->window,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    if (vkCreateXlibSurfaceKHR(g_gpu.instance,
 | 
					    if (vkCreateXlibSurfaceKHR(g_gpu.instance, &surface_info, &g_gpu.alloc_cb, &g_gpu.surface) ==
 | 
				
			||||||
                               &surface_info,
 | 
					        VK_SUCCESS)
 | 
				
			||||||
                               &g_gpu.alloc_cb,
 | 
					 | 
				
			||||||
                               &g_gpu.surface) == VK_SUCCESS)
 | 
					 | 
				
			||||||
        return VY_SUCCESS;
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
        return 100;
 | 
					        return 100;
 | 
				
			||||||
@ -222,16 +210,14 @@ typedef struct {
 | 
				
			|||||||
    uint32_t present;
 | 
					    uint32_t present;
 | 
				
			||||||
} vy_queue_indices;
 | 
					} vy_queue_indices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev,
 | 
					static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev, VkSurfaceKHR surface) {
 | 
				
			||||||
                                             VkSurfaceKHR surface) {
 | 
					 | 
				
			||||||
    vy_queue_indices indices = {.graphics = UINT32_MAX,
 | 
					    vy_queue_indices indices = {.graphics = UINT32_MAX,
 | 
				
			||||||
                                .compute  = UINT32_MAX,
 | 
					                                .compute  = UINT32_MAX,
 | 
				
			||||||
                                .present  = UINT32_MAX};
 | 
					                                .present  = UINT32_MAX};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t count = 0;
 | 
					    uint32_t count = 0;
 | 
				
			||||||
    vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &count, NULL);
 | 
					    vkGetPhysicalDeviceQueueFamilyProperties(phys_dev, &count, NULL);
 | 
				
			||||||
    VkQueueFamilyProperties *props =
 | 
					    VkQueueFamilyProperties *props = calloc(count, sizeof(VkQueueFamilyProperties));
 | 
				
			||||||
        calloc(count, sizeof(VkQueueFamilyProperties));
 | 
					 | 
				
			||||||
    if (!props) {
 | 
					    if (!props) {
 | 
				
			||||||
        return indices;
 | 
					        return indices;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -245,10 +231,7 @@ static vy_queue_indices RetrieveQueueIndices(VkPhysicalDevice phys_dev,
 | 
				
			|||||||
            indices.compute = i;
 | 
					            indices.compute = i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        VkBool32 present_supported = VK_FALSE;
 | 
					        VkBool32 present_supported = VK_FALSE;
 | 
				
			||||||
        vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev,
 | 
					        vkGetPhysicalDeviceSurfaceSupportKHR(phys_dev, i, surface, &present_supported);
 | 
				
			||||||
                                             i,
 | 
					 | 
				
			||||||
                                             surface,
 | 
					 | 
				
			||||||
                                             &present_supported);
 | 
					 | 
				
			||||||
        if (present_supported)
 | 
					        if (present_supported)
 | 
				
			||||||
            indices.present = i;
 | 
					            indices.present = i;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -262,19 +245,13 @@ static bool CheckDeviceExtensionSupported(VkPhysicalDevice phys_dev) {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t extension_count;
 | 
					    uint32_t extension_count;
 | 
				
			||||||
    vkEnumerateDeviceExtensionProperties(phys_dev,
 | 
					    vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &extension_count, NULL);
 | 
				
			||||||
                                         NULL,
 | 
					 | 
				
			||||||
                                         &extension_count,
 | 
					 | 
				
			||||||
                                         NULL);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    VkExtensionProperties *supported_extensions =
 | 
					    VkExtensionProperties *supported_extensions =
 | 
				
			||||||
        calloc(extension_count, sizeof(VkExtensionProperties));
 | 
					        calloc(extension_count, sizeof(VkExtensionProperties));
 | 
				
			||||||
    if (!supported_extensions)
 | 
					    if (!supported_extensions)
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    vkEnumerateDeviceExtensionProperties(phys_dev,
 | 
					    vkEnumerateDeviceExtensionProperties(phys_dev, NULL, &extension_count, supported_extensions);
 | 
				
			||||||
                                         NULL,
 | 
					 | 
				
			||||||
                                         &extension_count,
 | 
					 | 
				
			||||||
                                         supported_extensions);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    bool supported = true;
 | 
					    bool supported = true;
 | 
				
			||||||
    for (uint32_t i = 0; i < VY_ARRAY_COUNT(required_extensions); ++i) {
 | 
					    for (uint32_t i = 0; i < VY_ARRAY_COUNT(required_extensions); ++i) {
 | 
				
			||||||
@ -302,30 +279,23 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    g_gpu.phys_device          = VK_NULL_HANDLE;
 | 
					    g_gpu.phys_device          = VK_NULL_HANDLE;
 | 
				
			||||||
    uint32_t phys_device_count = 0;
 | 
					    uint32_t phys_device_count = 0;
 | 
				
			||||||
    VkResult result =
 | 
					    VkResult result = vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
 | 
				
			||||||
        vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, NULL);
 | 
					 | 
				
			||||||
    if (result != VK_SUCCESS) {
 | 
					    if (result != VK_SUCCESS) {
 | 
				
			||||||
        vyReportError("vk", "Failed to enumerate the physical devices.");
 | 
					        vyReportError("vk", "Failed to enumerate the physical devices.");
 | 
				
			||||||
        return 2;
 | 
					        return 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    VkPhysicalDevice *phys_devices =
 | 
					    VkPhysicalDevice *phys_devices = calloc(phys_device_count, sizeof(VkPhysicalDevice));
 | 
				
			||||||
        calloc(phys_device_count, sizeof(VkPhysicalDevice));
 | 
					 | 
				
			||||||
    if (!phys_devices) {
 | 
					    if (!phys_devices) {
 | 
				
			||||||
        vyReportError(
 | 
					        vyReportError("vk", "Failed to enumerate the physical devices: Out of memory.");
 | 
				
			||||||
            "vk",
 | 
					 | 
				
			||||||
            "Failed to enumerate the physical devices: Out of memory.");
 | 
					 | 
				
			||||||
        return 2;
 | 
					        return 2;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkEnumeratePhysicalDevices(g_gpu.instance,
 | 
					    vkEnumeratePhysicalDevices(g_gpu.instance, &phys_device_count, phys_devices);
 | 
				
			||||||
                               &phys_device_count,
 | 
					 | 
				
			||||||
                               phys_devices);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t highscore  = 0;
 | 
					    uint32_t highscore  = 0;
 | 
				
			||||||
    uint32_t best_index = phys_device_count;
 | 
					    uint32_t best_index = phys_device_count;
 | 
				
			||||||
    for (uint32_t i = 0; i < phys_device_count; ++i) {
 | 
					    for (uint32_t i = 0; i < phys_device_count; ++i) {
 | 
				
			||||||
        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
					        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
				
			||||||
            .sType =
 | 
					            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES,
 | 
				
			||||||
                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES,
 | 
					 | 
				
			||||||
            .pNext = NULL,
 | 
					            .pNext = NULL,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        VkPhysicalDeviceProperties2 props = {
 | 
					        VkPhysicalDeviceProperties2 props = {
 | 
				
			||||||
@ -337,8 +307,7 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
				
			|||||||
        if (!CheckDeviceExtensionSupported(phys_devices[i]))
 | 
					        if (!CheckDeviceExtensionSupported(phys_devices[i]))
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        vy_queue_indices indices =
 | 
					        vy_queue_indices indices = RetrieveQueueIndices(phys_devices[i], g_gpu.surface);
 | 
				
			||||||
            RetrieveQueueIndices(phys_devices[i], g_gpu.surface);
 | 
					 | 
				
			||||||
        if (indices.compute == UINT32_MAX || indices.present == UINT32_MAX ||
 | 
					        if (indices.compute == UINT32_MAX || indices.present == UINT32_MAX ||
 | 
				
			||||||
            indices.graphics == UINT32_MAX)
 | 
					            indices.graphics == UINT32_MAX)
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
@ -351,14 +320,10 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
				
			|||||||
        score += (props.properties.limits.maxFramebufferWidth / 100) *
 | 
					        score += (props.properties.limits.maxFramebufferWidth / 100) *
 | 
				
			||||||
                 (props.properties.limits.maxFramebufferHeight / 100);
 | 
					                 (props.properties.limits.maxFramebufferHeight / 100);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        score += (descriptor_indexing_props
 | 
					        score +=
 | 
				
			||||||
                      .shaderStorageBufferArrayNonUniformIndexingNative)
 | 
					            (descriptor_indexing_props.shaderStorageBufferArrayNonUniformIndexingNative) ? 100 : 0;
 | 
				
			||||||
                     ? 100
 | 
					        score +=
 | 
				
			||||||
                     : 0;
 | 
					            (descriptor_indexing_props.shaderSampledImageArrayNonUniformIndexingNative) ? 100 : 0;
 | 
				
			||||||
        score += (descriptor_indexing_props
 | 
					 | 
				
			||||||
                      .shaderSampledImageArrayNonUniformIndexingNative)
 | 
					 | 
				
			||||||
                     ? 100
 | 
					 | 
				
			||||||
                     : 0;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (score > highscore) {
 | 
					        if (score > highscore) {
 | 
				
			||||||
            highscore  = score;
 | 
					            highscore  = score;
 | 
				
			||||||
@ -373,10 +338,9 @@ static vy_result ChoosePhysicalDevice(void) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (best_index < phys_device_count) {
 | 
					    if (best_index < phys_device_count) {
 | 
				
			||||||
        g_gpu.phys_device = phys_devices[0];
 | 
					        g_gpu.phys_device                                                      = phys_devices[0];
 | 
				
			||||||
        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
					        VkPhysicalDeviceDescriptorIndexingProperties descriptor_indexing_props = {
 | 
				
			||||||
            .sType =
 | 
					            .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES,
 | 
				
			||||||
                VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES,
 | 
					 | 
				
			||||||
            .pNext = NULL,
 | 
					            .pNext = NULL,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        VkPhysicalDeviceProperties2 props = {
 | 
					        VkPhysicalDeviceProperties2 props = {
 | 
				
			||||||
@ -401,8 +365,7 @@ static vy_result CreateDevice(void) {
 | 
				
			|||||||
        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
					        VK_KHR_SWAPCHAIN_EXTENSION_NAME,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_queue_indices queue_indices =
 | 
					    vy_queue_indices queue_indices = RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
 | 
				
			||||||
        RetrieveQueueIndices(g_gpu.phys_device, g_gpu.surface);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    g_gpu.compute_family  = queue_indices.compute;
 | 
					    g_gpu.compute_family  = queue_indices.compute;
 | 
				
			||||||
    g_gpu.graphics_family = queue_indices.graphics;
 | 
					    g_gpu.graphics_family = queue_indices.graphics;
 | 
				
			||||||
@ -419,23 +382,21 @@ static vy_result CreateDevice(void) {
 | 
				
			|||||||
    queue_info[0].queueFamilyIndex = queue_indices.graphics;
 | 
					    queue_info[0].queueFamilyIndex = queue_indices.graphics;
 | 
				
			||||||
    queue_info[0].pQueuePriorities = &priority;
 | 
					    queue_info[0].pQueuePriorities = &priority;
 | 
				
			||||||
    if (queue_indices.compute != queue_indices.graphics) {
 | 
					    if (queue_indices.compute != queue_indices.graphics) {
 | 
				
			||||||
        queue_info[1].sType      = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
					        queue_info[1].sType            = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
				
			||||||
        queue_info[1].pNext      = NULL;
 | 
					        queue_info[1].pNext            = NULL;
 | 
				
			||||||
        queue_info[1].flags      = 0;
 | 
					        queue_info[1].flags            = 0;
 | 
				
			||||||
        queue_info[1].queueCount = 1;
 | 
					        queue_info[1].queueCount       = 1;
 | 
				
			||||||
        queue_info[1].queueFamilyIndex = queue_indices.compute;
 | 
					        queue_info[1].queueFamilyIndex = queue_indices.compute;
 | 
				
			||||||
        queue_info[1].pQueuePriorities = &priority;
 | 
					        queue_info[1].pQueuePriorities = &priority;
 | 
				
			||||||
        ++distinct_queue_count;
 | 
					        ++distinct_queue_count;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (queue_indices.present != queue_indices.graphics &&
 | 
					    if (queue_indices.present != queue_indices.graphics &&
 | 
				
			||||||
        queue_indices.present != queue_indices.compute) {
 | 
					        queue_indices.present != queue_indices.compute) {
 | 
				
			||||||
        queue_info[distinct_queue_count].sType =
 | 
					        queue_info[distinct_queue_count].sType      = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
				
			||||||
            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
 | 
					 | 
				
			||||||
        queue_info[distinct_queue_count].pNext      = NULL;
 | 
					        queue_info[distinct_queue_count].pNext      = NULL;
 | 
				
			||||||
        queue_info[distinct_queue_count].flags      = 0;
 | 
					        queue_info[distinct_queue_count].flags      = 0;
 | 
				
			||||||
        queue_info[distinct_queue_count].queueCount = 1;
 | 
					        queue_info[distinct_queue_count].queueCount = 1;
 | 
				
			||||||
        queue_info[distinct_queue_count].queueFamilyIndex =
 | 
					        queue_info[distinct_queue_count].queueFamilyIndex = queue_indices.present;
 | 
				
			||||||
            queue_indices.present;
 | 
					 | 
				
			||||||
        queue_info[distinct_queue_count].pQueuePriorities = &priority;
 | 
					        queue_info[distinct_queue_count].pQueuePriorities = &priority;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -446,26 +407,15 @@ static vy_result CreateDevice(void) {
 | 
				
			|||||||
        .pQueueCreateInfos       = queue_info,
 | 
					        .pQueueCreateInfos       = queue_info,
 | 
				
			||||||
        .queueCreateInfoCount    = distinct_queue_count,
 | 
					        .queueCreateInfoCount    = distinct_queue_count,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    if (vkCreateDevice(g_gpu.phys_device,
 | 
					    if (vkCreateDevice(g_gpu.phys_device, &device_info, g_gpu.alloc_cb, &g_gpu.device) !=
 | 
				
			||||||
                       &device_info,
 | 
					        VK_SUCCESS) {
 | 
				
			||||||
                       g_gpu.alloc_cb,
 | 
					 | 
				
			||||||
                       &g_gpu.device) != VK_SUCCESS) {
 | 
					 | 
				
			||||||
        vyReportError("vk", "Device creation failed.");
 | 
					        vyReportError("vk", "Device creation failed.");
 | 
				
			||||||
        return 10;
 | 
					        return 10;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vkGetDeviceQueue(g_gpu.device,
 | 
					    vkGetDeviceQueue(g_gpu.device, queue_indices.graphics, 0, &g_gpu.graphics_queue);
 | 
				
			||||||
                     queue_indices.graphics,
 | 
					    vkGetDeviceQueue(g_gpu.device, queue_indices.compute, 0, &g_gpu.compute_queue);
 | 
				
			||||||
                     0,
 | 
					    vkGetDeviceQueue(g_gpu.device, queue_indices.present, 0, &g_gpu.present_queue);
 | 
				
			||||||
                     &g_gpu.graphics_queue);
 | 
					 | 
				
			||||||
    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 VY_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,18 +7,16 @@
 | 
				
			|||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
#elif defined(VY_USE_XLIB)
 | 
					#elif defined(VY_USE_XLIB)
 | 
				
			||||||
    #include <X11/Xlib.h>
 | 
					#include <X11/Xlib.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
					VY_CVAR_I(r_VkPreferredSwapchainImages,
 | 
				
			||||||
          "Preferred number of swapchain iamges. [2/3] Default: 2",
 | 
					          "Preferred number of swapchain iamges. [2/3] Default: 2",
 | 
				
			||||||
          2);
 | 
					          2);
 | 
				
			||||||
VY_CVAR_I(r_VkPreferMailboxMode,
 | 
					VY_CVAR_I(r_VkPreferMailboxMode, "Prefer mailbox present mode over fifo mode. [0/1] Default: 0", 1);
 | 
				
			||||||
          "Prefer mailbox present mode over fifo mode. [0/1] Default: 0",
 | 
					 | 
				
			||||||
          1);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    VkPresentModeKHR present_mode;
 | 
					    VkPresentModeKHR present_mode;
 | 
				
			||||||
@ -35,10 +33,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
    if (r_VkPreferMailboxMode.i) {
 | 
					    if (r_VkPreferMailboxMode.i) {
 | 
				
			||||||
        VkPresentModeKHR modes[6];
 | 
					        VkPresentModeKHR modes[6];
 | 
				
			||||||
        uint32_t count = 6;
 | 
					        uint32_t count = 6;
 | 
				
			||||||
        vkGetPhysicalDeviceSurfacePresentModesKHR(g_gpu.phys_device,
 | 
					        vkGetPhysicalDeviceSurfacePresentModesKHR(g_gpu.phys_device, g_gpu.surface, &count, modes);
 | 
				
			||||||
                                                  g_gpu.surface,
 | 
					 | 
				
			||||||
                                                  &count,
 | 
					 | 
				
			||||||
                                                  modes);
 | 
					 | 
				
			||||||
        for (uint32_t i = 0; i < count; ++i) {
 | 
					        for (uint32_t i = 0; i < count; ++i) {
 | 
				
			||||||
            if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
 | 
					            if (modes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
 | 
				
			||||||
                params.present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
 | 
					                params.present_mode = VK_PRESENT_MODE_MAILBOX_KHR;
 | 
				
			||||||
@ -48,10 +43,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
    /* Determine surface format */
 | 
					    /* Determine surface format */
 | 
				
			||||||
    VkSurfaceFormatKHR formats[64];
 | 
					    VkSurfaceFormatKHR formats[64];
 | 
				
			||||||
    uint32_t format_count = 64;
 | 
					    uint32_t format_count = 64;
 | 
				
			||||||
    vkGetPhysicalDeviceSurfaceFormatsKHR(g_gpu.phys_device,
 | 
					    vkGetPhysicalDeviceSurfaceFormatsKHR(g_gpu.phys_device, g_gpu.surface, &format_count, formats);
 | 
				
			||||||
                                         g_gpu.surface,
 | 
					 | 
				
			||||||
                                         &format_count,
 | 
					 | 
				
			||||||
                                         formats);
 | 
					 | 
				
			||||||
    params.surface_format = formats[0];
 | 
					    params.surface_format = formats[0];
 | 
				
			||||||
    for (uint32_t i = 0; i < format_count; ++i) {
 | 
					    for (uint32_t i = 0; i < format_count; ++i) {
 | 
				
			||||||
        if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
 | 
					        if (formats[i].format == VK_FORMAT_B8G8R8A8_SRGB &&
 | 
				
			||||||
@ -63,9 +55,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* get extent */
 | 
					    /* get extent */
 | 
				
			||||||
    VkSurfaceCapabilitiesKHR capabilities;
 | 
					    VkSurfaceCapabilitiesKHR capabilities;
 | 
				
			||||||
    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_gpu.phys_device,
 | 
					    vkGetPhysicalDeviceSurfaceCapabilitiesKHR(g_gpu.phys_device, g_gpu.surface, &capabilities);
 | 
				
			||||||
                                              g_gpu.surface,
 | 
					 | 
				
			||||||
                                              &capabilities);
 | 
					 | 
				
			||||||
    if (capabilities.currentExtent.width != UINT32_MAX) {
 | 
					    if (capabilities.currentExtent.width != UINT32_MAX) {
 | 
				
			||||||
        params.extent = capabilities.currentExtent;
 | 
					        params.extent = capabilities.currentExtent;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -76,9 +66,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
        params.extent.height = (uint32_t)client_area.bottom;
 | 
					        params.extent.height = (uint32_t)client_area.bottom;
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        XWindowAttributes attribs;
 | 
					        XWindowAttributes attribs;
 | 
				
			||||||
        XGetWindowAttributes(g_gpu.native_window.display,
 | 
					        XGetWindowAttributes(g_gpu.native_window.display, g_gpu.native_window.window, &attribs);
 | 
				
			||||||
                             g_gpu.native_window.window,
 | 
					 | 
				
			||||||
                             &attribs);
 | 
					 | 
				
			||||||
        params.extent.width  = (uint32_t)attribs.width;
 | 
					        params.extent.width  = (uint32_t)attribs.width;
 | 
				
			||||||
        params.extent.height = (uint32_t)attribs.height;
 | 
					        params.extent.height = (uint32_t)attribs.height;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -91,8 +79,7 @@ static vy_device_swapchain_parameters DetermineSwapchainParameters(void) {
 | 
				
			|||||||
vy_swapchain g_swapchain;
 | 
					vy_swapchain g_swapchain;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_result vyCreateSwapchain(void) {
 | 
					vy_result vyCreateSwapchain(void) {
 | 
				
			||||||
    vy_device_swapchain_parameters device_params =
 | 
					    vy_device_swapchain_parameters device_params = DetermineSwapchainParameters();
 | 
				
			||||||
        DetermineSwapchainParameters();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint32_t image_count = r_VkPreferredSwapchainImages.i;
 | 
					    uint32_t image_count = r_VkPreferredSwapchainImages.i;
 | 
				
			||||||
    if (image_count < 2)
 | 
					    if (image_count < 2)
 | 
				
			||||||
@ -137,14 +124,9 @@ vy_result vyCreateSwapchain(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /* Retrieve images */
 | 
					    /* Retrieve images */
 | 
				
			||||||
    g_swapchain.image_count = 0;
 | 
					    g_swapchain.image_count = 0;
 | 
				
			||||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
					    vkGetSwapchainImagesKHR(g_gpu.device, g_swapchain.swapchain, &g_swapchain.image_count, NULL);
 | 
				
			||||||
                            g_swapchain.swapchain,
 | 
					 | 
				
			||||||
                            &g_swapchain.image_count,
 | 
					 | 
				
			||||||
                            NULL);
 | 
					 | 
				
			||||||
    if (g_swapchain.image_count > VY_VK_MAX_SWAPCHAIN_IMAGES) {
 | 
					    if (g_swapchain.image_count > VY_VK_MAX_SWAPCHAIN_IMAGES) {
 | 
				
			||||||
        vyReportError("vk",
 | 
					        vyReportError("vk", "Unsupported number of swapchain images: %u", g_swapchain.image_count);
 | 
				
			||||||
                      "Unsupported number of swapchain images: %u",
 | 
					 | 
				
			||||||
                      g_swapchain.image_count);
 | 
					 | 
				
			||||||
        return 51;
 | 
					        return 51;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
					    vkGetSwapchainImagesKHR(g_gpu.device,
 | 
				
			||||||
@ -179,8 +161,7 @@ vy_result vyCreateSwapchain(void) {
 | 
				
			|||||||
                              &view_info,
 | 
					                              &view_info,
 | 
				
			||||||
                              g_gpu.alloc_cb,
 | 
					                              g_gpu.alloc_cb,
 | 
				
			||||||
                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
					                              &g_swapchain.image_views[i]) != VK_SUCCESS) {
 | 
				
			||||||
            vyReportError("vk",
 | 
					            vyReportError("vk", "Failed to create an image view for the swapchain.");
 | 
				
			||||||
                          "Failed to create an image view for the swapchain.");
 | 
					 | 
				
			||||||
            return 52;
 | 
					            return 52;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -196,9 +177,7 @@ vy_result vyRecreateSwapchain(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void vyDestroySwapchain(void) {
 | 
					void vyDestroySwapchain(void) {
 | 
				
			||||||
    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
					    for (uint32_t i = 0; i < g_swapchain.image_count; ++i) {
 | 
				
			||||||
        vkDestroyImageView(g_gpu.device,
 | 
					        vkDestroyImageView(g_gpu.device, g_swapchain.image_views[i], g_gpu.alloc_cb);
 | 
				
			||||||
                           g_swapchain.image_views[i],
 | 
					 | 
				
			||||||
                           g_gpu.alloc_cb);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
 | 
					    vkDestroySwapchainKHR(g_gpu.device, g_swapchain.swapchain, g_gpu.alloc_cb);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,10 @@
 | 
				
			|||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
#include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#elif defined(__linux__)
 | 
				
			||||||
 | 
					#include <sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
@ -11,7 +15,6 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/* Maintain a ringbuffer of pending operations */
 | 
					/* Maintain a ringbuffer of pending operations */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    HANDLE file_handle;
 | 
					    HANDLE file_handle;
 | 
				
			||||||
@ -49,11 +52,10 @@ static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
				
			|||||||
        if (_ringbuffer.head + count <= _ringbuffer.capacity) {
 | 
					        if (_ringbuffer.head + count <= _ringbuffer.capacity) {
 | 
				
			||||||
            result.a_count   = count;
 | 
					            result.a_count   = count;
 | 
				
			||||||
            result.a         = &_ringbuffer.storage[_ringbuffer.head];
 | 
					            result.a         = &_ringbuffer.storage[_ringbuffer.head];
 | 
				
			||||||
            _ringbuffer.head =
 | 
					            _ringbuffer.head = (_ringbuffer.head + count) % _ringbuffer.capacity;
 | 
				
			||||||
                (_ringbuffer.head + count) % _ringbuffer.capacity;
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            /* Check if enough space is free at the end */
 | 
					            /* Check if enough space is free at the end */
 | 
				
			||||||
            uint32_t a_count   = _ringbuffer.capacity - _ringbuffer.head;
 | 
					            uint32_t a_count = _ringbuffer.capacity - _ringbuffer.head;
 | 
				
			||||||
            uint32_t b_count = count - a_count;
 | 
					            uint32_t b_count = count - a_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (b_count <= _ringbuffer.tail) {
 | 
					            if (b_count <= _ringbuffer.tail) {
 | 
				
			||||||
@ -70,10 +72,9 @@ static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
				
			|||||||
        /* Head is lower than tail */
 | 
					        /* Head is lower than tail */
 | 
				
			||||||
        uint32_t num_free = _ringbuffer.tail - _ringbuffer.head;
 | 
					        uint32_t num_free = _ringbuffer.tail - _ringbuffer.head;
 | 
				
			||||||
        if (count < num_free) {
 | 
					        if (count < num_free) {
 | 
				
			||||||
            result.a_count = count;
 | 
					            result.a_count   = count;
 | 
				
			||||||
            result.a       = &_ringbuffer.storage[_ringbuffer.head];
 | 
					            result.a         = &_ringbuffer.storage[_ringbuffer.head];
 | 
				
			||||||
            _ringbuffer.head =
 | 
					            _ringbuffer.head = (_ringbuffer.head + count) % _ringbuffer.capacity;
 | 
				
			||||||
                (_ringbuffer.head + count) % _ringbuffer.capacity;
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            /* Not enough space, we would overwrite the tail */
 | 
					            /* Not enough space, we would overwrite the tail */
 | 
				
			||||||
            vyLog("aio", "Ringbuffer is full.");
 | 
					            vyLog("aio", "Ringbuffer is full.");
 | 
				
			||||||
@ -85,10 +86,9 @@ static vy_ringbuffer_space ReserveRingbufferSpace(uint32_t count) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
static void win32CompletionRoutine(DWORD error_code,
 | 
					static void
 | 
				
			||||||
                                   DWORD num_bytes_transfered,
 | 
					win32CompletionRoutine(DWORD error_code, DWORD num_bytes_transfered, LPOVERLAPPED overlapped) {
 | 
				
			||||||
                                   LPOVERLAPPED overlapped) {
 | 
					    vy_aio *op = (vy_aio *)overlapped->hEvent;
 | 
				
			||||||
    vy_aio *op = (vy_aio*)overlapped->hEvent;
 | 
					 | 
				
			||||||
    assert(op->state == VY_AIO_STATE_PENDING);
 | 
					    assert(op->state == VY_AIO_STATE_PENDING);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (error_code != ERROR_SUCCESS) {
 | 
					    if (error_code != ERROR_SUCCESS) {
 | 
				
			||||||
@ -97,12 +97,11 @@ static void win32CompletionRoutine(DWORD error_code,
 | 
				
			|||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        op->state = VY_AIO_STATE_FINISHED;
 | 
					        op->state = VY_AIO_STATE_FINISHED;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    CloseHandle(op->file_handle);
 | 
					    CloseHandle(op->file_handle);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations) {
 | 
					VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations) {
 | 
				
			||||||
    _ringbuffer.guard = vyCreateMutex();
 | 
					    _ringbuffer.guard = vyCreateMutex();
 | 
				
			||||||
    if (!_ringbuffer.guard) {
 | 
					    if (!_ringbuffer.guard) {
 | 
				
			||||||
@ -114,8 +113,8 @@ VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations) {
 | 
				
			|||||||
    _ringbuffer.storage = calloc(max_concurrent_operations, sizeof(vy_aio));
 | 
					    _ringbuffer.storage = calloc(max_concurrent_operations, sizeof(vy_aio));
 | 
				
			||||||
    if (!_ringbuffer.storage)
 | 
					    if (!_ringbuffer.storage)
 | 
				
			||||||
        return VY_AIO_OUT_OF_MEMORY;
 | 
					        return VY_AIO_OUT_OF_MEMORY;
 | 
				
			||||||
    _ringbuffer.head = 0;
 | 
					    _ringbuffer.head     = 0;
 | 
				
			||||||
    _ringbuffer.tail = 0;
 | 
					    _ringbuffer.tail     = 0;
 | 
				
			||||||
    _ringbuffer.capacity = max_concurrent_operations;
 | 
					    _ringbuffer.capacity = max_concurrent_operations;
 | 
				
			||||||
    return VY_SUCCESS;
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -126,8 +125,7 @@ VY_DLLEXPORT void vyShutdownAIO(void) {
 | 
				
			|||||||
    _ringbuffer.capacity = 0;
 | 
					    _ringbuffer.capacity = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch,
 | 
					VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_handle *handles) {
 | 
				
			||||||
                            vy_aio_handle *handles) {
 | 
					 | 
				
			||||||
    if (batch->num_loads > VY_LOAD_BATCH_MAX_SIZE) {
 | 
					    if (batch->num_loads > VY_LOAD_BATCH_MAX_SIZE) {
 | 
				
			||||||
        return VY_AIO_LOAD_TOO_LARGE;
 | 
					        return VY_AIO_LOAD_TOO_LARGE;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -139,13 +137,11 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (unsigned int i = 0; i < batch->num_loads; ++i) {
 | 
					    for (unsigned int i = 0; i < batch->num_loads; ++i) {
 | 
				
			||||||
        vy_aio *op = (i < rbspace.a_count) ? &rbspace.a[i]
 | 
					        vy_aio *op = (i < rbspace.a_count) ? &rbspace.a[i] : &rbspace.b[i - rbspace.a_count];
 | 
				
			||||||
                                           : &rbspace.b[i - rbspace.a_count];
 | 
					        op->state  = VY_AIO_STATE_PENDING;
 | 
				
			||||||
        op->state = VY_AIO_STATE_PENDING;
 | 
					 | 
				
			||||||
        const char *file_path = vyGetFilePath(batch->loads[i].file);
 | 
					        const char *file_path = vyGetFilePath(batch->loads[i].file);
 | 
				
			||||||
        if (!file_path) {
 | 
					        if (!file_path) {
 | 
				
			||||||
            vyReportError("aio",
 | 
					            vyReportError("aio", "Failed to resolve file path for a batched load");
 | 
				
			||||||
                          "Failed to resolve file path for a batched load");
 | 
					 | 
				
			||||||
            op->state  = VY_AIO_STATE_INVALID;
 | 
					            op->state  = VY_AIO_STATE_INVALID;
 | 
				
			||||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
					            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
@ -168,9 +164,7 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch,
 | 
				
			|||||||
                                -1,
 | 
					                                -1,
 | 
				
			||||||
                                wpath,
 | 
					                                wpath,
 | 
				
			||||||
                                VY_ARRAY_COUNT(wpath)) == 0) {
 | 
					                                VY_ARRAY_COUNT(wpath)) == 0) {
 | 
				
			||||||
            vyReportError("aio",
 | 
					            vyReportError("aio", "MultiByteToWideChar failed with error code: %u", GetLastError());
 | 
				
			||||||
                          "MultiByteToWideChar failed with error code: %u",
 | 
					 | 
				
			||||||
                          GetLastError());
 | 
					 | 
				
			||||||
            op->state  = VY_AIO_STATE_FINISHED;
 | 
					            op->state  = VY_AIO_STATE_FINISHED;
 | 
				
			||||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
					            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
@ -193,15 +187,15 @@ VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch,
 | 
				
			|||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        op->file_handle = file_handle;
 | 
					        op->file_handle = file_handle;
 | 
				
			||||||
        BOOL result = ReadFileEx(file_handle,
 | 
					        BOOL result     = ReadFileEx(file_handle,
 | 
				
			||||||
                                 batch->loads[i].dest,
 | 
					                                 batch->loads[i].dest,
 | 
				
			||||||
                                 (DWORD)batch->loads[i].num_bytes,
 | 
					                                 (DWORD)batch->loads[i].num_bytes,
 | 
				
			||||||
                                 &op->overlapped,
 | 
					                                 &op->overlapped,
 | 
				
			||||||
                                 win32CompletionRoutine);
 | 
					                                 win32CompletionRoutine);
 | 
				
			||||||
        DWORD err   = GetLastError();
 | 
					        DWORD err       = GetLastError();
 | 
				
			||||||
        if (!result || err != ERROR_SUCCESS) {
 | 
					        if (!result || err != ERROR_SUCCESS) {
 | 
				
			||||||
            vyReportError("aio", "ReadFileEx failed with error code: %u", err);
 | 
					            vyReportError("aio", "ReadFileEx failed with error code: %u", err);
 | 
				
			||||||
            op->state = VY_AIO_STATE_FINISHED;
 | 
					            op->state  = VY_AIO_STATE_FINISHED;
 | 
				
			||||||
            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
					            handles[i] = VY_AIO_INVALID_HANDLE;
 | 
				
			||||||
            CloseHandle(file_handle);
 | 
					            CloseHandle(file_handle);
 | 
				
			||||||
            op->file_handle = NULL;
 | 
					            op->file_handle = NULL;
 | 
				
			||||||
@ -229,14 +223,15 @@ VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle) {
 | 
				
			|||||||
    return state;
 | 
					    return state;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 VY_DLLEXPORT void vyReleaseAIO(vy_aio_handle handle) {
 | 
					VY_DLLEXPORT void vyReleaseAIO(vy_aio_handle handle) {
 | 
				
			||||||
    if (handle == VY_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity) {
 | 
					    if (handle == VY_AIO_INVALID_HANDLE || handle > _ringbuffer.capacity) {
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vyLockMutex(_ringbuffer.guard);
 | 
					    vyLockMutex(_ringbuffer.guard);
 | 
				
			||||||
    _ringbuffer.storage[handle - 1].state = VY_AIO_STATE_INVALID;
 | 
					    _ringbuffer.storage[handle - 1].state = VY_AIO_STATE_INVALID;
 | 
				
			||||||
    if (handle - 1 == _ringbuffer.tail) {
 | 
					    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) */
 | 
					        /* 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;
 | 
					        uint32_t i = _ringbuffer.tail;
 | 
				
			||||||
        while ((_ringbuffer.storage[i].state == VY_AIO_STATE_INVALID) && i != _ringbuffer.head) {
 | 
					        while ((_ringbuffer.storage[i].state == VY_AIO_STATE_INVALID) && i != _ringbuffer.head) {
 | 
				
			||||||
            i = (i + 1) % _ringbuffer.capacity;
 | 
					            i = (i + 1) % _ringbuffer.capacity;
 | 
				
			||||||
@ -245,3 +240,19 @@ VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    vyUnlockMutex(_ringbuffer.guard);
 | 
					    vyUnlockMutex(_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;
 | 
				
			||||||
 | 
					    do {
 | 
				
			||||||
 | 
					        state = vyGetAIOState(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);
 | 
				
			||||||
 | 
					    return state;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -3,8 +3,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					 | 
				
			||||||
#include "file_tab.h"
 | 
					#include "file_tab.h"
 | 
				
			||||||
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    size_t offset;    /**< Starting offset inside the file in bytes */
 | 
					    size_t offset;    /**< Starting offset inside the file in bytes */
 | 
				
			||||||
@ -13,7 +13,7 @@ typedef struct {
 | 
				
			|||||||
     *  Must be valid until the load is finished.
 | 
					     *  Must be valid until the load is finished.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    void *dest;
 | 
					    void *dest;
 | 
				
			||||||
    vy_file_id file;  /**< Unique identifier for the file */
 | 
					    vy_file_id file; /**< Unique identifier for the file */
 | 
				
			||||||
} vy_file_load;
 | 
					} vy_file_load;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VY_LOAD_BATCH_MAX_SIZE 64
 | 
					#define VY_LOAD_BATCH_MAX_SIZE 64
 | 
				
			||||||
@ -24,12 +24,11 @@ typedef struct {
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    vy_file_load loads[VY_LOAD_BATCH_MAX_SIZE];
 | 
					    vy_file_load loads[VY_LOAD_BATCH_MAX_SIZE];
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    /** Must be smaller or equal to @c VY_LOAD_BATCH_MAX_SIZE */
 | 
					    /** Must be smaller or equal to @c VY_LOAD_BATCH_MAX_SIZE */
 | 
				
			||||||
    unsigned int num_loads;
 | 
					    unsigned int num_loads;
 | 
				
			||||||
} vy_load_batch;
 | 
					} vy_load_batch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define VY_AIO_INVALID_HANDLE 0
 | 
					#define VY_AIO_INVALID_HANDLE 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Handle for an async io operation. Can be used to query the state and result. */
 | 
					/** Handle for an async io operation. Can be used to query the state and result. */
 | 
				
			||||||
@ -41,7 +40,6 @@ enum {
 | 
				
			|||||||
    VY_AIO_OUT_OF_MEMORY,
 | 
					    VY_AIO_OUT_OF_MEMORY,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef enum {
 | 
					typedef enum {
 | 
				
			||||||
    VY_AIO_STATE_INVALID,
 | 
					    VY_AIO_STATE_INVALID,
 | 
				
			||||||
    VY_AIO_STATE_PENDING,
 | 
					    VY_AIO_STATE_PENDING,
 | 
				
			||||||
@ -53,11 +51,12 @@ VY_DLLEXPORT vy_result vyInitAIO(unsigned int max_concurrent_operations);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyShutdownAIO(void);
 | 
					VY_DLLEXPORT void vyShutdownAIO(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch,
 | 
					VY_DLLEXPORT vy_result vySubmitLoadBatch(const vy_load_batch *batch, vy_aio_handle *handles);
 | 
				
			||||||
                                        vy_aio_handle *handles);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle);
 | 
					VY_DLLEXPORT volatile vy_aio_state vyGetAIOState(vy_aio_handle handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT vy_aio_state vyWaitForAIOCompletion(vy_aio_handle handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Releases the internal storage for the operation.
 | 
					/* 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.
 | 
					 * The system is allowed to re-use the same handle value for new operations after this was called.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
				
			|||||||
@ -1,9 +1,9 @@
 | 
				
			|||||||
#include "app.h"
 | 
					#include "app.h"
 | 
				
			||||||
 | 
					#include "aio.h"
 | 
				
			||||||
 | 
					#include "buffer_manager.h"
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
#include "aio.h"
 | 
					 | 
				
			||||||
#include "renderer_api.h"
 | 
					#include "renderer_api.h"
 | 
				
			||||||
#include "buffer_manager.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void __RegisterRuntimeCVars(void);
 | 
					extern void __RegisterRuntimeCVars(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -12,13 +12,10 @@ VY_CVAR_I(rt_WindowWidth, "Window width. Default: 1024", 1024);
 | 
				
			|||||||
VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
					VY_CVAR_I(rt_WindowHeight, "Window height. Default: 768", 768);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static LRESULT CALLBACK win32WndProc(HWND hWnd,
 | 
					static LRESULT CALLBACK win32WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
 | 
				
			||||||
                                     UINT uMsg,
 | 
					 | 
				
			||||||
                                     WPARAM wParam,
 | 
					 | 
				
			||||||
                                     LPARAM lParam) {
 | 
					 | 
				
			||||||
    switch (uMsg) {
 | 
					    switch (uMsg) {
 | 
				
			||||||
    case WM_CLOSE:
 | 
					    case WM_CLOSE:
 | 
				
			||||||
        PostQuitMessage(0);
 | 
					        PostQuitMessage(0);
 | 
				
			||||||
@ -28,10 +25,8 @@ static LRESULT CALLBACK win32WndProc(HWND hWnd,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
					VY_DLLEXPORT int
 | 
				
			||||||
                              HINSTANCE hPrevInstance,
 | 
					vyWin32Entry(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) {
 | 
				
			||||||
                              PWSTR pCmdLine,
 | 
					 | 
				
			||||||
                              int nCmdShow) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    __RegisterRuntimeCVars();
 | 
					    __RegisterRuntimeCVars();
 | 
				
			||||||
    vyRegisterRendererCVars();
 | 
					    vyRegisterRendererCVars();
 | 
				
			||||||
@ -103,9 +98,7 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!wnd) {
 | 
					    if (!wnd) {
 | 
				
			||||||
        vyReportError("CORE",
 | 
					        vyReportError("CORE", "Failed to create the game window: %u", GetLastError());
 | 
				
			||||||
                      "Failed to create the game window: %u",
 | 
					 | 
				
			||||||
                      GetLastError());
 | 
					 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -144,11 +137,10 @@ VY_DLLEXPORT int vyWin32Entry(HINSTANCE hInstance,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#elif defined(VY_USE_XLIB)
 | 
					#elif defined(VY_USE_XLIB)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #include <X11/Xlib.h>
 | 
					#include <X11/Xlib.h>
 | 
				
			||||||
    #include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) {
 | 
				
			||||||
xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) {
 | 
					 | 
				
			||||||
    Atom wm_state      = XInternAtom(dpy, "_NET_W_STATE", False);
 | 
					    Atom wm_state      = XInternAtom(dpy, "_NET_W_STATE", False);
 | 
				
			||||||
    Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
 | 
					    Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
 | 
				
			||||||
    if (wm_state == None || wm_fullscreen == None) {
 | 
					    if (wm_state == None || wm_fullscreen == None) {
 | 
				
			||||||
@ -156,20 +148,20 @@ xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) {
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define _NET_WM_STATE_REMOVE     0
 | 
					#define _NET_WM_STATE_REMOVE     0
 | 
				
			||||||
    #define _NET_WM_STATE_ADD        1
 | 
					#define _NET_WM_STATE_ADD        1
 | 
				
			||||||
    #define EVENT_SOURCE_APPLICATION 1
 | 
					#define EVENT_SOURCE_APPLICATION 1
 | 
				
			||||||
    XEvent ev;
 | 
					    XEvent ev;
 | 
				
			||||||
    ev.type                 = ClientMessage;
 | 
					    ev.type                 = ClientMessage;
 | 
				
			||||||
    ev.xclient.display      = dpy;
 | 
					    ev.xclient.display      = dpy;
 | 
				
			||||||
    ev.xclient.window       = window;
 | 
					    ev.xclient.window       = window;
 | 
				
			||||||
    ev.xclient.message_type = wm_state;
 | 
					    ev.xclient.message_type = wm_state;
 | 
				
			||||||
    ev.xclient.format       = 32;
 | 
					    ev.xclient.format       = 32;
 | 
				
			||||||
    ev.xclient.data.l[0] = (enable) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
 | 
					    ev.xclient.data.l[0]    = (enable) ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
 | 
				
			||||||
    ev.xclient.data.l[1] = wm_fullscreen;
 | 
					    ev.xclient.data.l[1]    = wm_fullscreen;
 | 
				
			||||||
    ev.xclient.data.l[2] = 0;
 | 
					    ev.xclient.data.l[2]    = 0;
 | 
				
			||||||
    ev.xclient.data.l[3] = EVENT_SOURCE_APPLICATION;
 | 
					    ev.xclient.data.l[3]    = EVENT_SOURCE_APPLICATION;
 | 
				
			||||||
    ev.xclient.data.l[4] = 0;
 | 
					    ev.xclient.data.l[4]    = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Window root_window = XRootWindow(dpy, screen);
 | 
					    Window root_window = XRootWindow(dpy, screen);
 | 
				
			||||||
    long ev_mask       = SubstructureRedirectMask;
 | 
					    long ev_mask       = SubstructureRedirectMask;
 | 
				
			||||||
@ -178,9 +170,9 @@ xlibSetFullscreen(Display *dpy, int screen, Window window, bool enable) {
 | 
				
			|||||||
        vyReportError("CORE", "Failed to send x11 fullscreen event.");
 | 
					        vyReportError("CORE", "Failed to send x11 fullscreen event.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #undef _NET_WM_STATE_ADD
 | 
					#undef _NET_WM_STATE_ADD
 | 
				
			||||||
    #undef _NET_WM_STATE_REMOVE
 | 
					#undef _NET_WM_STATE_REMOVE
 | 
				
			||||||
    #undef EVENT_SOURCE_APPLICATION
 | 
					#undef EVENT_SOURCE_APPLICATION
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
					VY_DLLEXPORT int vyXlibEntry(int argc, char **argv) {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,4 +8,13 @@ typedef uint32_t vy_uid;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#define VY_INVALID_UID 0
 | 
					#define VY_INVALID_UID 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Used to identify renderer backend dependent assets. */
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    VY_INVALID_RENDERER_BACKEND_CODE = 0,
 | 
				
			||||||
 | 
					    VY_RENDERER_BACKEND_CODE_VK      = 1,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VY_RENDERER_BACKEND_CODE_ONE_PAST_LAST,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					typedef uint8_t vy_renderer_backend_code;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
@ -1,12 +1,12 @@
 | 
				
			|||||||
 | 
					#include "buffer_manager.h"
 | 
				
			||||||
 | 
					#include "config.h"
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
#include "threading.h"
 | 
					#include "threading.h"
 | 
				
			||||||
#include "config.h"
 | 
					 | 
				
			||||||
#include "buffer_manager.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdlib.h>
 | 
					 | 
				
			||||||
#include <stdint.h>
 | 
					 | 
				
			||||||
#include <stdbool.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct vy_buffer_region_s {
 | 
					typedef struct vy_buffer_region_s {
 | 
				
			||||||
    void *memory;
 | 
					    void *memory;
 | 
				
			||||||
@ -22,7 +22,7 @@ typedef struct vy_buffer_region_s {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include <intrin.h>
 | 
					#include <intrin.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define lzcnt32(x) __lzcnt((x))
 | 
					#define lzcnt32(x)  __lzcnt((x))
 | 
				
			||||||
#define popcnt32(x) __popcnt((x))
 | 
					#define popcnt32(x) __popcnt((x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __forceinline uint32_t tzcnt32(uint32_t x) {
 | 
					static __forceinline uint32_t tzcnt32(uint32_t x) {
 | 
				
			||||||
@ -40,7 +40,7 @@ static inline bool IsLZCNTSupported(void) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined(__GNUC__)
 | 
					#elif defined(__GNUC__)
 | 
				
			||||||
#define lzcnt32(x) __builtin_clz((x))
 | 
					#define lzcnt32(x)  __builtin_clz((x))
 | 
				
			||||||
#define tzcnt32(x)  __builtin_ctz((x))
 | 
					#define tzcnt32(x)  __builtin_ctz((x))
 | 
				
			||||||
#define popcnt32(x) __builtin_popcount((x))
 | 
					#define popcnt32(x) __builtin_popcount((x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -49,13 +49,13 @@ static inline bool IsLZCNTSupported(void) {
 | 
				
			|||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* NOTE(Kevin): Keep these sorted! */
 | 
					/* 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[] = {VY_KB(512), VY_MB(1), VY_MB(4), VY_MB(8)};
 | 
				
			||||||
#define NUM_BLOCK_SIZES (sizeof(_block_sizes) / sizeof(_block_sizes[0]))
 | 
					#define NUM_BLOCK_SIZES (sizeof(_block_sizes) / sizeof(_block_sizes[0]))
 | 
				
			||||||
static vy_buffer_region _regions[NUM_BLOCK_SIZES];
 | 
					static vy_buffer_region _regions[NUM_BLOCK_SIZES];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_SZ(
 | 
					VY_CVAR_SZ(rt_BufferManagerMemory,
 | 
				
			||||||
    rt_BufferManagerMemory,
 | 
					           "Total number of bytes allocated for the buffer manager. Default: 1GB",
 | 
				
			||||||
    "Total number of bytes allocated for the buffer manager. Default: 1GB", VY_GB(1));
 | 
					           VY_GB(1));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_result vyInitBufferManager(void) {
 | 
					VY_DLLEXPORT vy_result vyInitBufferManager(void) {
 | 
				
			||||||
    if ((rt_BufferManagerMemory.sz % NUM_BLOCK_SIZES) != 0)
 | 
					    if ((rt_BufferManagerMemory.sz % NUM_BLOCK_SIZES) != 0)
 | 
				
			||||||
@ -74,14 +74,14 @@ VY_DLLEXPORT vy_result vyInitBufferManager(void) {
 | 
				
			|||||||
                  mem_per_size / (1024 * 1024),
 | 
					                  mem_per_size / (1024 * 1024),
 | 
				
			||||||
                  _block_sizes[i] / 1024);
 | 
					                  _block_sizes[i] / 1024);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        size_t block_count = mem_per_size / _block_sizes[i];
 | 
					        size_t block_count      = mem_per_size / _block_sizes[i];
 | 
				
			||||||
        _regions[i].block_count = block_count;
 | 
					        _regions[i].block_count = block_count;
 | 
				
			||||||
        _regions[i].guard       = vyCreateMutex();
 | 
					        _regions[i].guard       = vyCreateMutex();
 | 
				
			||||||
        if (!_regions[i].guard) {
 | 
					        if (!_regions[i].guard) {
 | 
				
			||||||
            vyReportError("BUFFERMGR", "Failed to create guard mutex %u", i);
 | 
					            vyReportError("BUFFERMGR", "Failed to create guard mutex %u", i);
 | 
				
			||||||
            return VY_BUFFER_MGR_MUTEX_CREATION_FAILED;
 | 
					            return VY_BUFFER_MGR_MUTEX_CREATION_FAILED;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        _regions[i].memory      = malloc(mem_per_size);
 | 
					        _regions[i].memory = malloc(mem_per_size);
 | 
				
			||||||
        if (!_regions[i].memory) {
 | 
					        if (!_regions[i].memory) {
 | 
				
			||||||
            vyDestroyMutex(_regions[i].guard);
 | 
					            vyDestroyMutex(_regions[i].guard);
 | 
				
			||||||
            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
					            vyReportError("BUFFERMGR", "Failed to allocate memory.", i);
 | 
				
			||||||
@ -117,7 +117,7 @@ VY_DLLEXPORT void vyShutdownBufferManager(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
					VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
				
			||||||
    assert(IsLZCNTSupported());
 | 
					    assert(IsLZCNTSupported());
 | 
				
			||||||
    
 | 
					
 | 
				
			||||||
    // Determine the best block size to use
 | 
					    // Determine the best block size to use
 | 
				
			||||||
    size_t required_blocks = (size + _block_sizes[0] - 1) / _block_sizes[0];
 | 
					    size_t required_blocks = (size + _block_sizes[0] - 1) / _block_sizes[0];
 | 
				
			||||||
    size_t best_fit        = 0;
 | 
					    size_t best_fit        = 0;
 | 
				
			||||||
@ -148,18 +148,18 @@ VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
				
			|||||||
                    size_t first_free = 32 - free_high_blocks;
 | 
					                    size_t first_free = 32 - free_high_blocks;
 | 
				
			||||||
                    region->bitmap[i] |= (in_use_mask << first_free);
 | 
					                    region->bitmap[i] |= (in_use_mask << first_free);
 | 
				
			||||||
                    block_index = i * 32 + first_free;
 | 
					                    block_index = i * 32 + first_free;
 | 
				
			||||||
                    result      = (char *)region->memory +
 | 
					                    result      = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
				
			||||||
                        block_index * _block_sizes[best_fit];
 | 
					 | 
				
			||||||
                } else if (tzcnt32(region->bitmap[i]) >= required_blocks) {
 | 
					                } else if (tzcnt32(region->bitmap[i]) >= required_blocks) {
 | 
				
			||||||
                    /* Low blocks are free */
 | 
					                    /* Low blocks are free */
 | 
				
			||||||
                    region->bitmap[i] |= in_use_mask;
 | 
					                    region->bitmap[i] |= in_use_mask;
 | 
				
			||||||
                    block_index = i * 32;
 | 
					                    block_index = i * 32;
 | 
				
			||||||
                    result      = (char *)region->memory +  block_index * _block_sizes[best_fit];
 | 
					                    result      = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    /* Check if we can find a large enough range of free blocks.
 | 
					                    /* Check if we can find a large enough range of free blocks.
 | 
				
			||||||
                     * Start after the first set bit.
 | 
					                     * Start after the first set bit.
 | 
				
			||||||
                     */
 | 
					                     */
 | 
				
			||||||
                    for (uint32_t j = tzcnt32(region->bitmap[i]) + 1; j < 32 - required_blocks; ++j) {
 | 
					                    for (uint32_t j = tzcnt32(region->bitmap[i]) + 1; j < 32 - required_blocks;
 | 
				
			||||||
 | 
					                         ++j) {
 | 
				
			||||||
                        if ((region->bitmap[i] & in_use_mask << j) == 0) {
 | 
					                        if ((region->bitmap[i] & in_use_mask << j) == 0) {
 | 
				
			||||||
                            region->bitmap[i] |= (in_use_mask << j);
 | 
					                            region->bitmap[i] |= (in_use_mask << j);
 | 
				
			||||||
                            block_index = i * 32 + j;
 | 
					                            block_index = i * 32 + j;
 | 
				
			||||||
@ -170,23 +170,25 @@ VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            } else if (region->bitmap[i] == 0) {
 | 
					            } else if (region->bitmap[i] == 0) {
 | 
				
			||||||
                /* All free */
 | 
					                /* All free */
 | 
				
			||||||
                region->bitmap[i]  = in_use_mask;
 | 
					                region->bitmap[i] = in_use_mask;
 | 
				
			||||||
                block_index = i * 32;
 | 
					                block_index       = i * 32;
 | 
				
			||||||
                result             = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
					                result            = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
				
			||||||
            } else if (i < dword_count - 1) {
 | 
					            } else if (i < dword_count - 1) {
 | 
				
			||||||
                /* Check if we can use high blocks from this dword and low blocks from the next one */
 | 
					                /* 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 high_blocks = lzcnt32(region->bitmap[i]);
 | 
				
			||||||
                size_t low_blocks  = (region->bitmap[i + 1] != 0) ? tzcnt32(region->bitmap[i + 1]) : 32;
 | 
					                size_t low_blocks =
 | 
				
			||||||
 | 
					                    (region->bitmap[i + 1] != 0) ? tzcnt32(region->bitmap[i + 1]) : 32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (high_blocks + low_blocks >= required_blocks) {
 | 
					                if (high_blocks + low_blocks >= required_blocks) {
 | 
				
			||||||
                    size_t high_mask = (1u << high_blocks) - 1;
 | 
					                    size_t high_mask  = (1u << high_blocks) - 1;
 | 
				
			||||||
                    size_t first_free = 32 - high_blocks;
 | 
					                    size_t first_free = 32 - high_blocks;
 | 
				
			||||||
                    size_t low_mask = (1u << (required_blocks - high_blocks)) - 1;
 | 
					                    size_t low_mask   = (1u << (required_blocks - high_blocks)) - 1;
 | 
				
			||||||
                    
 | 
					
 | 
				
			||||||
                    region->bitmap[i] |= (high_mask << first_free);
 | 
					                    region->bitmap[i] |= (high_mask << first_free);
 | 
				
			||||||
                    region->bitmap[i + 1] |= low_mask;
 | 
					                    region->bitmap[i + 1] |= low_mask;
 | 
				
			||||||
                    block_index = i * 32 + first_free;
 | 
					                    block_index = i * 32 + first_free;
 | 
				
			||||||
                    result             = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
					                    result      = (char *)region->memory + block_index * _block_sizes[best_fit];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -202,13 +204,14 @@ VY_DLLEXPORT void *vyAllocBuffer(size_t size) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size) {
 | 
					VY_DLLEXPORT void vyReleaseBuffer(const void *begin, size_t size) {
 | 
				
			||||||
 | 
					    if (!begin)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
    uintptr_t begin_addr = (uintptr_t)begin;
 | 
					    uintptr_t begin_addr = (uintptr_t)begin;
 | 
				
			||||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
					    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
				
			||||||
        uintptr_t region_addr = (uintptr_t)_regions[i].memory;
 | 
					        uintptr_t region_addr = (uintptr_t)_regions[i].memory;
 | 
				
			||||||
        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
					        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
				
			||||||
        if (begin_addr >= region_addr &&
 | 
					        if (begin_addr >= region_addr && begin_addr + size <= region_addr + region_size) {
 | 
				
			||||||
                begin_addr + size <= region_addr + region_size) {
 | 
					
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
					            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
				
			||||||
            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
					            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -232,8 +235,7 @@ VY_DLLEXPORT void vyIncreaseBufferRefCount(const void *begin, size_t size) {
 | 
				
			|||||||
    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
					    for (unsigned int i = 0; i < NUM_BLOCK_SIZES; ++i) {
 | 
				
			||||||
        uintptr_t region_addr = (uintptr_t)_regions[i].memory;
 | 
					        uintptr_t region_addr = (uintptr_t)_regions[i].memory;
 | 
				
			||||||
        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
					        size_t region_size    = _block_sizes[i] * _regions[i].block_count;
 | 
				
			||||||
        if (begin_addr >= region_addr &&
 | 
					        if (begin_addr >= region_addr && begin_addr + size <= region_addr + region_size) {
 | 
				
			||||||
            begin_addr + size <= region_addr + region_size) {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
					            size_t block_count = (size + _block_sizes[i] - 1) / _block_sizes[i];
 | 
				
			||||||
            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
					            size_t first_block = (begin_addr - region_addr) / _block_sizes[i];
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
#include "threading.h"
 | 
					 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					#include "threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
				
			|||||||
@ -3,16 +3,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef enum
 | 
					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_SIZE,
 | 
				
			||||||
} vy_cvar_type;
 | 
					} vy_cvar_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct
 | 
					typedef struct {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    const char *name;
 | 
					    const char *name;
 | 
				
			||||||
    const char *description;
 | 
					    const char *description;
 | 
				
			||||||
    union {
 | 
					    union {
 | 
				
			||||||
@ -24,26 +22,14 @@ typedef struct
 | 
				
			|||||||
    vy_cvar_type type;
 | 
					    vy_cvar_type type;
 | 
				
			||||||
} vy_cvar;
 | 
					} vy_cvar;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define VY_CVAR_I(n, d, v)                                                     \
 | 
					#define VY_CVAR_I(n, d, v)                                                                         \
 | 
				
			||||||
    vy_cvar n = {.name        = #n,                                            \
 | 
					    vy_cvar n = {.name = #n, .description = d, .i = (v), .type = VY_CVAR_TYPE_INT}
 | 
				
			||||||
                 .description = d,                                             \
 | 
					#define VY_CVAR_F(n, d, v)                                                                         \
 | 
				
			||||||
                 .i           = (v),                                           \
 | 
					    vy_cvar n = {.name = #n, .description = d, .f = (v), .type = VY_CVAR_TYPE_FLOAT}
 | 
				
			||||||
                 .type        = VY_CVAR_TYPE_INT}
 | 
					#define VY_CVAR_S(n, d, v)                                                                         \
 | 
				
			||||||
#define VY_CVAR_F(n, d, v)                                                     \
 | 
					    vy_cvar n = {.name = #n, .description = d, .s = (v), .type = VY_CVAR_TYPE_STRING}
 | 
				
			||||||
    vy_cvar n = {.name        = #n,                                            \
 | 
					#define VY_CVAR_SZ(n, d, v)                                                                        \
 | 
				
			||||||
                 .description = d,                                             \
 | 
					    vy_cvar n = {.name = #n, .description = d, .sz = (v), .type = VY_CVAR_TYPE_SIZE}
 | 
				
			||||||
                 .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}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyRegisterCVAR(vy_cvar *cvar);
 | 
					VY_DLLEXPORT void vyRegisterCVAR(vy_cvar *cvar);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -10,18 +10,13 @@ VY_DLLEXPORT vy_dynlib vyOpenCallerLib(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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, MB_PRECOMPOSED, libname, -1, libname_w, MAX_PATH);
 | 
				
			||||||
                        MB_PRECOMPOSED,
 | 
					 | 
				
			||||||
                        libname,
 | 
					 | 
				
			||||||
                        -1,
 | 
					 | 
				
			||||||
                        libname_w,
 | 
					 | 
				
			||||||
                        MAX_PATH);
 | 
					 | 
				
			||||||
    HMODULE mod = LoadLibraryW(libname_w);
 | 
					    HMODULE mod = LoadLibraryW(libname_w);
 | 
				
			||||||
    return (vy_dynlib)mod;
 | 
					    return (vy_dynlib)mod;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol) {
 | 
					VY_DLLEXPORT void *vyGetSymbol(vy_dynlib lib, const char *symbol) {
 | 
				
			||||||
    return (void*)GetProcAddress((HMODULE)lib, symbol);
 | 
					    return (void *)GetProcAddress((HMODULE)lib, symbol);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
					VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
				
			||||||
@ -47,5 +42,4 @@ VY_DLLEXPORT void vyCloseLib(vy_dynlib lib) {
 | 
				
			|||||||
    dlclose(lib);
 | 
					    dlclose(lib);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -4,13 +4,13 @@
 | 
				
			|||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define VY_DLLNAME(s)                                                      \
 | 
					#define VY_DLLNAME(s)                                                                              \
 | 
				
			||||||
        (".\\"s                                                                \
 | 
					    (".\\"s                                                                                        \
 | 
				
			||||||
         ".dll")
 | 
					     ".dll")
 | 
				
			||||||
#elif defined(__linux__)
 | 
					#elif defined(__linux__)
 | 
				
			||||||
    #define VY_DLLNAME(s)                                                      \
 | 
					#define VY_DLLNAME(s)                                                                              \
 | 
				
			||||||
        ("./lib"s                                                              \
 | 
					    ("./lib"s                                                                                      \
 | 
				
			||||||
         ".so")
 | 
					     ".so")
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void *vy_dynlib;
 | 
					typedef void *vy_dynlib;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,43 +1,47 @@
 | 
				
			|||||||
#include <stdarg.h>
 | 
					#include <stdarg.h>
 | 
				
			||||||
#include <stdio.h>
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
#include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DbgBreak DebugBreak()
 | 
				
			||||||
 | 
					#elif defined(__GNUC__)
 | 
				
			||||||
 | 
					#define DbgBreak __builtin_trap()
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					/* Not available */
 | 
				
			||||||
 | 
					#define DbgBreak 
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* TODO(Kevin): Log to file, show error message box, ... */
 | 
					/* TODO(Kevin): Log to file, show error message box, ... */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void DisplayErrorBox(const char *text)
 | 
					static bool DisplayErrorBox(const char *text) {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    WCHAR msg[256];
 | 
					    WCHAR msg[256];
 | 
				
			||||||
    MultiByteToWideChar(CP_UTF8,
 | 
					    vyUTF8ToWStr(text, msg, VY_ARRAY_COUNT(msg));
 | 
				
			||||||
                        MB_PRECOMPOSED,
 | 
					
 | 
				
			||||||
                        text,
 | 
					#ifdef VY_ERROR_REPORT_DEBUGBREAK
 | 
				
			||||||
                        -1,
 | 
					    return MessageBoxW(NULL, msg, L"Error", MB_OKCANCEL | MB_ICONERROR) == IDCANCEL;
 | 
				
			||||||
                        msg,
 | 
					#else
 | 
				
			||||||
                        VY_ARRAY_COUNT(msg));
 | 
					 | 
				
			||||||
    MessageBoxW(NULL, msg, L"Error", MB_ICONERROR);
 | 
					    MessageBoxW(NULL, msg, L"Error", MB_ICONERROR);
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
 | 
					#endif /* VY_ERROR_REPORT_DEBUGBREAK */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    return false;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void LogOut(const char *text)
 | 
					static void LogOut(const char *text) {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    WCHAR msg[256];
 | 
					    WCHAR msg[256];
 | 
				
			||||||
    MultiByteToWideChar(CP_UTF8,
 | 
					    vyUTF8ToWStr(text, msg, VY_ARRAY_COUNT(msg));
 | 
				
			||||||
                        MB_PRECOMPOSED,
 | 
					 | 
				
			||||||
                        text,
 | 
					 | 
				
			||||||
                        -1,
 | 
					 | 
				
			||||||
                        msg,
 | 
					 | 
				
			||||||
                        VY_ARRAY_COUNT(msg));
 | 
					 | 
				
			||||||
    OutputDebugStringW(msg);
 | 
					    OutputDebugStringW(msg);
 | 
				
			||||||
#elif defined(__linux__)
 | 
					 | 
				
			||||||
    fprintf(stderr, "%s", text);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					    fprintf(stderr, "%s", text);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
					VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
				
			||||||
@ -51,7 +55,9 @@ VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...) {
 | 
				
			|||||||
    at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
					    at += snprintf(&buf[at], VY_ARRAY_COUNT(buf) - at - 1, "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    LogOut(buf);
 | 
					    LogOut(buf);
 | 
				
			||||||
    DisplayErrorBox(buf);
 | 
					    if (DisplayErrorBox(buf)) {
 | 
				
			||||||
 | 
					        DbgBreak;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...) {
 | 
					VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...) {
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,7 @@ vy_result vyInitFileTab(unsigned int max_files) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    _file_tab.capacity  = max_files;
 | 
					    _file_tab.capacity  = max_files;
 | 
				
			||||||
    _file_tab.name_head = 0;
 | 
					    _file_tab.name_head = 0;
 | 
				
			||||||
    _file_tab.mutex = vyCreateMutex();
 | 
					    _file_tab.mutex     = vyCreateMutex();
 | 
				
			||||||
    return VY_SUCCESS;
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -40,7 +40,6 @@ void vyShutdownFileTab(void) {
 | 
				
			|||||||
    vyDestroyMutex(_file_tab.mutex);
 | 
					    vyDestroyMutex(_file_tab.mutex);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
vy_file_id vyGetFileId(const char *path) {
 | 
					vy_file_id vyGetFileId(const char *path) {
 | 
				
			||||||
    vy_text_span span;
 | 
					    vy_text_span span;
 | 
				
			||||||
    span.start  = path;
 | 
					    span.start  = path;
 | 
				
			||||||
@ -80,8 +79,8 @@ VY_DLLEXPORT vy_file_id vyAddFileFromSpan(vy_text_span path) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            memcpy(_file_tab.names + _file_tab.name_head, path.start, slen);
 | 
					            memcpy(_file_tab.names + _file_tab.name_head, path.start, slen);
 | 
				
			||||||
            _file_tab.names[_file_tab.name_head + slen - 1] = '\0';
 | 
					            _file_tab.names[_file_tab.name_head + slen - 1] = '\0';
 | 
				
			||||||
            _file_tab.name_offsets[at] = _file_tab.name_head;
 | 
					            _file_tab.name_offsets[at]                      = _file_tab.name_head;
 | 
				
			||||||
            _file_tab.ids[at]          = fid;
 | 
					            _file_tab.ids[at]                               = fid;
 | 
				
			||||||
            _file_tab.name_head += slen;
 | 
					            _file_tab.name_head += slen;
 | 
				
			||||||
            break;
 | 
					            break;
 | 
				
			||||||
        } else if (_file_tab.ids[at] == fid) {
 | 
					        } else if (_file_tab.ids[at] == fid) {
 | 
				
			||||||
 | 
				
			|||||||
@ -23,5 +23,4 @@ VY_DLLEXPORT vy_file_id vyAddFileFromSpan(vy_text_span path);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT const char *vyGetFilePath(vy_file_id fid);
 | 
					VY_DLLEXPORT const char *vyGetFilePath(vy_file_id fid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -17,47 +17,41 @@ vy_renderer_api g_renderer;
 | 
				
			|||||||
static vy_dynlib _renderer_lib;
 | 
					static vy_dynlib _renderer_lib;
 | 
				
			||||||
static bool _renderer_loaded = false;
 | 
					static bool _renderer_loaded = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_CVAR_S(rt_Renderer,
 | 
					VY_CVAR_S(rt_Renderer, "Select the render backend. Available options: [vk], Default: vk", "vk");
 | 
				
			||||||
          "Select the render backend. Available options: [vk], Default: vk",
 | 
					 | 
				
			||||||
          "vk");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef VY_STATIC_LIB
 | 
					#ifdef VY_STATIC_LIB
 | 
				
			||||||
extern void VY_RENDERER_API_FN(RegisterCVars)(void);
 | 
					extern void VY_RENDERER_API_FN(RegisterCVars)(void);
 | 
				
			||||||
extern vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *);
 | 
					extern vy_result VY_RENDERER_API_FN(Init)(const vy_renderer_init_info *);
 | 
				
			||||||
extern void VY_RENDERER_API_FN(Shutdown)(void);
 | 
					extern void VY_RENDERER_API_FN(Shutdown)(void);
 | 
				
			||||||
extern vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileComputePipeline)(
 | 
					extern vy_gfx_pipeline_handle
 | 
				
			||||||
    const vy_compute_pipeline_info *);
 | 
					    VY_RENDERER_API_FN(CompileComputePipeline)(const vy_compute_pipeline_info *);
 | 
				
			||||||
extern vy_gfx_pipeline_handle VY_RENDERER_API_FN(CompileGraphicsPipeline)(
 | 
					extern vy_gfx_pipeline_handle
 | 
				
			||||||
    const vy_graphics_pipeline_info *);
 | 
					    VY_RENDERER_API_FN(CompileGraphicsPipeline)(const vy_graphics_pipeline_info *);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool LoadRenderer(void) {
 | 
					static bool LoadRenderer(void) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if !defined(VY_STATIC_LIB)
 | 
					#if !defined(VY_STATIC_LIB)
 | 
				
			||||||
    #define RETRIEVE_SYMBOL(name, type)                                        \
 | 
					#define RETRIEVE_SYMBOL(name, type)                                                                \
 | 
				
			||||||
        g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vyRen" #name);   \
 | 
					    g_renderer.name = (type *)vyGetSymbol(_renderer_lib, "vyRen" #name);                           \
 | 
				
			||||||
        if (!g_renderer.name) {                                                \
 | 
					    if (!g_renderer.name) {                                                                        \
 | 
				
			||||||
            vyReportError(                                                     \
 | 
					        vyReportError("GFX",                                                                       \
 | 
				
			||||||
                "GFX",                                                         \
 | 
					                      "Unable to retrieve renderer function %s from backend %s",                   \
 | 
				
			||||||
                "Unable to retrieve renderer function %s from backend %s",     \
 | 
					                      #name,                                                                       \
 | 
				
			||||||
                #name,                                                         \
 | 
					                      rt_Renderer.s);                                                              \
 | 
				
			||||||
                rt_Renderer.s);                                                \
 | 
					    }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (strcmp(rt_Renderer.s, "vk") == 0) {
 | 
					    if (strcmp(rt_Renderer.s, "vk") == 0) {
 | 
				
			||||||
        _renderer_lib = vyOpenLib(VY_DLLNAME("vyvk"));
 | 
					        _renderer_lib = vyOpenLib(VY_DLLNAME("vyvk"));
 | 
				
			||||||
        if (!_renderer_lib) {
 | 
					        if (!_renderer_lib) {
 | 
				
			||||||
            vyReportError("GFX",
 | 
					            vyReportError("GFX", "Unable to load renderer backend: %s", VY_DLLNAME("vyvk"));
 | 
				
			||||||
                          "Unable to load renderer backend: %s",
 | 
					 | 
				
			||||||
                          VY_DLLNAME("vyvk"));
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        RETRIEVE_SYMBOL(RegisterCVars, vy_register_renderer_cvars_fn);
 | 
					        RETRIEVE_SYMBOL(RegisterCVars, vy_register_renderer_cvars_fn);
 | 
				
			||||||
        RETRIEVE_SYMBOL(Init, vy_init_renderer_fn);
 | 
					        RETRIEVE_SYMBOL(Init, vy_init_renderer_fn);
 | 
				
			||||||
        RETRIEVE_SYMBOL(Shutdown, vy_shutdown_renderer_fn);
 | 
					        RETRIEVE_SYMBOL(Shutdown, vy_shutdown_renderer_fn);
 | 
				
			||||||
        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);
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyReportError("GFX",
 | 
					        vyReportError("GFX",
 | 
				
			||||||
                      "Unsupported renderer backend: (%s) %s",
 | 
					                      "Unsupported renderer backend: (%s) %s",
 | 
				
			||||||
@ -65,12 +59,12 @@ static bool LoadRenderer(void) {
 | 
				
			|||||||
                      rt_Renderer.s);
 | 
					                      rt_Renderer.s);
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #undef RETRIEVE_SYMBOL
 | 
					#undef RETRIEVE_SYMBOL
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    g_renderer.RegisterCVars = &vyRenRegisterCVars;
 | 
					    g_renderer.RegisterCVars           = &vyRenRegisterCVars;
 | 
				
			||||||
    g_renderer.Init          = &vyRenInit;
 | 
					    g_renderer.Init                    = &vyRenInit;
 | 
				
			||||||
    g_renderer.Shutdown      = &vyRenShutdown;
 | 
					    g_renderer.Shutdown                = &vyRenShutdown;
 | 
				
			||||||
    g_renderer.CompileComputePipeline = &vyRenCompileComputePipeline;
 | 
					    g_renderer.CompileComputePipeline  = &vyRenCompileComputePipeline;
 | 
				
			||||||
    g_renderer.CompileGraphicsPipeline = &vyRenCompileGraphicsPipeline;
 | 
					    g_renderer.CompileGraphicsPipeline = &vyRenCompileGraphicsPipeline;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
 | 
				
			|||||||
@ -60,6 +60,6 @@ void vyInitJobSystem(unsigned int worker_count) {
 | 
				
			|||||||
        worker_count = MAX_WORKERS;
 | 
					        worker_count = MAX_WORKERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (unsigned int i = 0; i < worker_count; ++i) {
 | 
					    for (unsigned int i = 0; i < worker_count; ++i) {
 | 
				
			||||||
        _worker_data[i].thread = vySpawnThread(WorkerEntry, &_worker_data[i]);
 | 
					        _worker_data[i].thread = vySpawnThread(WorkerEntry, &_worker_data[i], "JobWorker");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "gfx.h"
 | 
					#include "gfx.h"
 | 
				
			||||||
#include "runtime.h"
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					#include "assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
struct HINSTANCE__;
 | 
					struct HINSTANCE__;
 | 
				
			||||||
@ -38,11 +39,24 @@ typedef struct {
 | 
				
			|||||||
    size_t fragment_source_length;
 | 
					    size_t fragment_source_length;
 | 
				
			||||||
} vy_graphics_pipeline_info;
 | 
					} vy_graphics_pipeline_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_uid vertex_shader;
 | 
				
			||||||
 | 
					    vy_uid fragment_shader;
 | 
				
			||||||
 | 
					    vy_uid compute_shader;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_relptr texture_bindings;
 | 
				
			||||||
 | 
					    vy_relptr uniform_bindings;
 | 
				
			||||||
 | 
					    vy_relptr storage_bindings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint16_t texture_binding_count;
 | 
				
			||||||
 | 
					    uint16_t uniform_binding_count;
 | 
				
			||||||
 | 
					    uint16_t storage_binding_count;
 | 
				
			||||||
 | 
					} vy_pipeline_info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef void vy_register_renderer_cvars_fn(void);
 | 
					typedef void vy_register_renderer_cvars_fn(void);
 | 
				
			||||||
typedef vy_result vy_init_renderer_fn(const vy_renderer_init_info *info);
 | 
					typedef vy_result vy_init_renderer_fn(const vy_renderer_init_info *info);
 | 
				
			||||||
typedef void vy_shutdown_renderer_fn(void);
 | 
					typedef void vy_shutdown_renderer_fn(void);
 | 
				
			||||||
typedef vy_gfx_pipeline_handle
 | 
					typedef vy_gfx_pipeline_handle vy_compile_compute_pipeline_fn(const vy_compute_pipeline_info *info);
 | 
				
			||||||
vy_compile_compute_pipeline_fn(const vy_compute_pipeline_info *info);
 | 
					 | 
				
			||||||
typedef vy_gfx_pipeline_handle
 | 
					typedef vy_gfx_pipeline_handle
 | 
				
			||||||
vy_compile_graphics_pipeline_fn(const vy_graphics_pipeline_info *info);
 | 
					vy_compile_graphics_pipeline_fn(const vy_graphics_pipeline_info *info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -4,30 +4,82 @@
 | 
				
			|||||||
/* basic types and macros */
 | 
					/* basic types and macros */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stddef.h>
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(_WIN32) && !defined(VY_STATIC_LIB)
 | 
					#if defined(_MSC_VER) && !defined(VY_STATIC_LIB)
 | 
				
			||||||
    #define VY_DLLEXPORT __declspec(dllexport)
 | 
					#define VY_DLLEXPORT __declspec(dllexport)
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
    #define VY_DLLEXPORT
 | 
					#define VY_DLLEXPORT
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(_MSC_VER)
 | 
				
			||||||
 | 
					#define VY_INLINE __forceinline
 | 
				
			||||||
 | 
					#elif defined(__GNUC__) || defined(__clang__)
 | 
				
			||||||
 | 
					#define VY_INLINE inline __attribute__((always_inline))
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#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_KB(n) ((n)*1024U)
 | 
				
			||||||
#define VY_MB(n) ((n) * 1024U * 1024U)
 | 
					#define VY_MB(n) ((n)*1024U * 1024U)
 | 
				
			||||||
#define VY_GB(n) ((n) * 1024U * 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
 | 
				
			||||||
 | 
					#define VY_UNKNOWN_ERROR (vy_result)-1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    const char *start;
 | 
					    const char *start;
 | 
				
			||||||
    unsigned int length;
 | 
					    unsigned int length;
 | 
				
			||||||
} vy_text_span;
 | 
					} vy_text_span;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns results like strcmp():
 | 
				
			||||||
 | 
					 * - If the first differing character is smaller in span than in cmp: < 0
 | 
				
			||||||
 | 
					 * - If span and cmp are equal: 0
 | 
				
			||||||
 | 
					 * - If the first differing character is greater in span than in cmp: > 0
 | 
				
			||||||
 | 
					 * - 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...);
 | 
					VY_DLLEXPORT void vyReportError(const char *subsystem, const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...);
 | 
					VY_DLLEXPORT void vyLog(const char *subsystem, const char *fmt, ...);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
					    VY_INVALID_UNICODE     = 1,
 | 
				
			||||||
 | 
					    VY_INSUFFICIENT_BUFFER = 2,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Relative pointer */
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    int32_t off;
 | 
				
			||||||
 | 
					} vy_relptr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VY_INLINE void *vyResolveRelptr(vy_relptr *ptr) {
 | 
				
			||||||
 | 
					    if (ptr->off != 0) {
 | 
				
			||||||
 | 
					        char *p = (char *)ptr;
 | 
				
			||||||
 | 
					        return (void *)(p + (ptrdiff_t)ptr->off);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static VY_INLINE void vySetRelptr(vy_relptr *ptr, void *target) {
 | 
				
			||||||
 | 
					    if (target) {
 | 
				
			||||||
 | 
					        char *p = (char *)ptr, *t = (char *)target;
 | 
				
			||||||
 | 
					        ptrdiff_t d = t - p;
 | 
				
			||||||
 | 
					        ptr->off    = (int32_t)d;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        ptr->off = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -6,8 +6,7 @@ extern vy_cvar rt_WindowWidth;
 | 
				
			|||||||
extern vy_cvar rt_WindowHeight;
 | 
					extern vy_cvar rt_WindowHeight;
 | 
				
			||||||
extern vy_cvar rt_BufferManagerMemory;
 | 
					extern vy_cvar rt_BufferManagerMemory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void __RegisterRuntimeCVars(void)
 | 
					void __RegisterRuntimeCVars(void) {
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    vyRegisterCVAR(&rt_Renderer);
 | 
					    vyRegisterCVAR(&rt_Renderer);
 | 
				
			||||||
    vyRegisterCVAR(&rt_Fullscreen);
 | 
					    vyRegisterCVAR(&rt_Fullscreen);
 | 
				
			||||||
    vyRegisterCVAR(&rt_WindowWidth);
 | 
					    vyRegisterCVAR(&rt_WindowWidth);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								src/runtime/text.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/runtime/text.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#include "runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT int vyCompareSpanToString(vy_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;
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < cmp_len; ++i) {
 | 
				
			||||||
 | 
					        if (span.start[i] != cmp[i])
 | 
				
			||||||
 | 
					            return span.start[i] - cmp[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT vy_result vyUTF8ToWStr(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;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        DWORD err = GetLastError();
 | 
				
			||||||
 | 
					        if (err == ERROR_INSUFFICIENT_BUFFER)
 | 
				
			||||||
 | 
					            return VY_INSUFFICIENT_BUFFER;
 | 
				
			||||||
 | 
					        else if (err == ERROR_NO_UNICODE_TRANSLATION)
 | 
				
			||||||
 | 
					            return VY_INVALID_UNICODE;
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            vyReportError("CORE", "Unexpected error in vyUTF8ToWStr(): %u", err);
 | 
				
			||||||
 | 
					            return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -34,8 +34,10 @@ typedef struct vy_thread_s vy_thread;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
typedef void vy_thread_entry_fn(void *param);
 | 
					typedef void vy_thread_entry_fn(void *param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param);
 | 
					VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT void vyJoinThread(vy_thread *thread);
 | 
					VY_DLLEXPORT void vyJoinThread(vy_thread *thread);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
@ -3,14 +3,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef __linux__
 | 
					#ifdef __linux__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
struct vy_condition_var_s {
 | 
					struct vy_condition_var_s {
 | 
				
			||||||
    pthread_mutex_t mutex;
 | 
					    pthread_mutex_t mutex;
 | 
				
			||||||
    pthread_cond_t cond;
 | 
					    pthread_cond_t cond;
 | 
				
			||||||
    ptrdiff_t next_reusable;
 | 
					    ptrdiff_t next_reusable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_CONDS 1024
 | 
					#define MAX_CONDS 1024
 | 
				
			||||||
vy_condition_var _conds[MAX_CONDS];
 | 
					vy_condition_var _conds[MAX_CONDS];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
					static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
@ -68,23 +68,21 @@ VY_DLLEXPORT void vyWaitOnConditionVar(vy_condition_var *var) {
 | 
				
			|||||||
#elif defined(_WIN32)
 | 
					#elif defined(_WIN32)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
struct vy_condition_var_s {
 | 
					struct vy_condition_var_s {
 | 
				
			||||||
    CRITICAL_SECTION critical_section;
 | 
					    CRITICAL_SECTION critical_section;
 | 
				
			||||||
    CONDITION_VARIABLE cond;
 | 
					    CONDITION_VARIABLE cond;
 | 
				
			||||||
    ptrdiff_t next_reusable;
 | 
					    ptrdiff_t next_reusable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_CONDS 1024
 | 
					#define MAX_CONDS 1024
 | 
				
			||||||
vy_condition_var _conds[MAX_CONDS];
 | 
					vy_condition_var _conds[MAX_CONDS];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
					static ptrdiff_t _first_reusable = MAX_CONDS;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
static HANDLE _guard;
 | 
					static HANDLE _guard;
 | 
				
			||||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
					static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce,
 | 
					static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
				
			||||||
                                 PVOID parameter,
 | 
					 | 
				
			||||||
                                 PVOID *context) {
 | 
					 | 
				
			||||||
    VY_UNUSED(initOnce);
 | 
					    VY_UNUSED(initOnce);
 | 
				
			||||||
    VY_UNUSED(parameter);
 | 
					    VY_UNUSED(parameter);
 | 
				
			||||||
    VY_UNUSED(context);
 | 
					    VY_UNUSED(context);
 | 
				
			||||||
 | 
				
			|||||||
@ -2,24 +2,22 @@
 | 
				
			|||||||
#include "threading.h"
 | 
					#include "threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    #define WIN32_LEAN_AND_MEAN
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
    #include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct vy_mutex_s {
 | 
					struct vy_mutex_s {
 | 
				
			||||||
    HANDLE handle;
 | 
					    HANDLE handle;
 | 
				
			||||||
    ptrdiff_t next_reusable;
 | 
					    ptrdiff_t next_reusable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_MUTEX 1024
 | 
					#define MAX_MUTEX 1024
 | 
				
			||||||
static vy_mutex _mutex[MAX_MUTEX];
 | 
					static vy_mutex _mutex[MAX_MUTEX];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
					static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
static HANDLE _guard;
 | 
					static HANDLE _guard;
 | 
				
			||||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
					static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce,
 | 
					static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
				
			||||||
                                 PVOID parameter,
 | 
					 | 
				
			||||||
                                 PVOID *context) {
 | 
					 | 
				
			||||||
    VY_UNUSED(initOnce);
 | 
					    VY_UNUSED(initOnce);
 | 
				
			||||||
    VY_UNUSED(parameter);
 | 
					    VY_UNUSED(parameter);
 | 
				
			||||||
    VY_UNUSED(context);
 | 
					    VY_UNUSED(context);
 | 
				
			||||||
@ -28,7 +26,6 @@ static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce,
 | 
				
			|||||||
    return _guard != NULL;
 | 
					    return _guard != NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
					VY_DLLEXPORT vy_mutex *vyCreateMutex(void) {
 | 
				
			||||||
    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
					    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
				
			||||||
        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
					        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
				
			||||||
@ -74,13 +71,13 @@ VY_DLLEXPORT bool vyUnlockMutex(vy_mutex *mutex) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#elif defined(__linux__)
 | 
					#elif defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #include <pthread.h>
 | 
					#include <pthread.h>
 | 
				
			||||||
struct vy_mutex_s {
 | 
					struct vy_mutex_s {
 | 
				
			||||||
    pthread_mutex_t handle;
 | 
					    pthread_mutex_t handle;
 | 
				
			||||||
    ptrdiff_t next_reusable;
 | 
					    ptrdiff_t next_reusable;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_MUTEX 1024
 | 
					#define MAX_MUTEX 1024
 | 
				
			||||||
static vy_mutex _mutex[MAX_MUTEX];
 | 
					static vy_mutex _mutex[MAX_MUTEX];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
					static ptrdiff_t _first_reusable = MAX_MUTEX;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -17,7 +17,7 @@ struct vy_thread_s {
 | 
				
			|||||||
    bool needs_join;
 | 
					    bool needs_join;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_THREADS 256
 | 
					#define MAX_THREADS 256
 | 
				
			||||||
static vy_thread _threads[MAX_THREADS];
 | 
					static vy_thread _threads[MAX_THREADS];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
					static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
@ -25,9 +25,7 @@ static ptrdiff_t _next           = 0;
 | 
				
			|||||||
static HANDLE _guard;
 | 
					static HANDLE _guard;
 | 
				
			||||||
static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
					static INIT_ONCE _guard_init = INIT_ONCE_STATIC_INIT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce,
 | 
					static BOOL CALLBACK InitGuardFn(PINIT_ONCE initOnce, PVOID parameter, PVOID *context) {
 | 
				
			||||||
                                 PVOID parameter,
 | 
					 | 
				
			||||||
                                 PVOID *context) {
 | 
					 | 
				
			||||||
    VY_UNUSED(initOnce);
 | 
					    VY_UNUSED(initOnce);
 | 
				
			||||||
    VY_UNUSED(parameter);
 | 
					    VY_UNUSED(parameter);
 | 
				
			||||||
    VY_UNUSED(context);
 | 
					    VY_UNUSED(context);
 | 
				
			||||||
@ -44,7 +42,7 @@ static DWORD WINAPI win32ThreadWrapper(LPVOID arg) {
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param) {
 | 
					VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
					    if (!InitOnceExecuteOnce(&_guard_init, InitGuardFn, NULL, NULL)) {
 | 
				
			||||||
        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
					        vyReportError("core", "Failed to initialize the guard mutex.");
 | 
				
			||||||
@ -70,13 +68,18 @@ VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param) {
 | 
				
			|||||||
        ++_next;
 | 
					        ++_next;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (thrd) {
 | 
					    if (thrd) {
 | 
				
			||||||
        thrd->entry = entry;
 | 
					        thrd->entry  = entry;
 | 
				
			||||||
        thrd->param = param;
 | 
					        thrd->param  = param;
 | 
				
			||||||
        thrd->handle = CreateThread(NULL, 0, win32ThreadWrapper, (LPVOID)thrd, 0, NULL);
 | 
					        thrd->handle = CreateThread(NULL, 0, win32ThreadWrapper, (LPVOID)thrd, 0, NULL);
 | 
				
			||||||
        if (thrd->handle == NULL) {
 | 
					        if (thrd->handle == NULL) {
 | 
				
			||||||
            vyLog("core", "Thread creation failed");
 | 
					            vyLog("core", "Thread creation failed");
 | 
				
			||||||
            thrd = NULL;
 | 
					            thrd = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        WCHAR wname[64];
 | 
				
			||||||
 | 
					        if (thrd && name && vyUTF8ToWStr(name, wname, sizeof(wname)) == VY_SUCCESS)
 | 
				
			||||||
 | 
					            SetThreadDescription(thrd->handle, wname);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyReportError("core", "Ran out of thread objects");
 | 
					        vyReportError("core", "Ran out of thread objects");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -99,10 +102,17 @@ VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
				
			|||||||
    ReleaseMutex(_guard);
 | 
					    ReleaseMutex(_guard);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void) {
 | 
				
			||||||
 | 
					    SYSTEM_INFO info;
 | 
				
			||||||
 | 
					    GetSystemInfo(&info);
 | 
				
			||||||
 | 
					    return (unsigned int)info.dwNumberOfProcessors;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#elif defined(__linux__)
 | 
					#elif defined(__linux__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #include <pthread.h>
 | 
					#define _GNU_SOURCE
 | 
				
			||||||
 | 
					#include <pthread.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct vy_thread_s {
 | 
					struct vy_thread_s {
 | 
				
			||||||
    pthread_t handle;
 | 
					    pthread_t handle;
 | 
				
			||||||
@ -114,7 +124,7 @@ struct vy_thread_s {
 | 
				
			|||||||
    bool needs_join;
 | 
					    bool needs_join;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #define MAX_THREADS 256
 | 
					#define MAX_THREADS 256
 | 
				
			||||||
static vy_thread _threads[MAX_THREADS];
 | 
					static vy_thread _threads[MAX_THREADS];
 | 
				
			||||||
static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
					static ptrdiff_t _first_reusable = MAX_THREADS;
 | 
				
			||||||
static ptrdiff_t _next           = 0;
 | 
					static ptrdiff_t _next           = 0;
 | 
				
			||||||
@ -129,7 +139,7 @@ static void *linuxThreadWrapper(void *arg) {
 | 
				
			|||||||
    return NULL;
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param) {
 | 
					VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param, const char *name) {
 | 
				
			||||||
    vy_thread *thrd = NULL;
 | 
					    vy_thread *thrd = NULL;
 | 
				
			||||||
    pthread_mutex_lock(&_guard);
 | 
					    pthread_mutex_lock(&_guard);
 | 
				
			||||||
    if (_first_reusable < MAX_THREADS) {
 | 
					    if (_first_reusable < MAX_THREADS) {
 | 
				
			||||||
@ -147,11 +157,12 @@ VY_DLLEXPORT vy_thread *vySpawnThread(vy_thread_entry_fn *entry, void *param) {
 | 
				
			|||||||
    if (thrd) {
 | 
					    if (thrd) {
 | 
				
			||||||
        thrd->entry = entry;
 | 
					        thrd->entry = entry;
 | 
				
			||||||
        thrd->param = param;
 | 
					        thrd->param = param;
 | 
				
			||||||
        if (pthread_create(&thrd->handle, NULL, linuxThreadWrapper, thrd) !=
 | 
					        if (pthread_create(&thrd->handle, NULL, linuxThreadWrapper, thrd) != 0) {
 | 
				
			||||||
            0) {
 | 
					 | 
				
			||||||
            vyLog("core", "Thread creation failed");
 | 
					            vyLog("core", "Thread creation failed");
 | 
				
			||||||
            thrd = NULL;
 | 
					            thrd = NULL;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (thrd && name)
 | 
				
			||||||
 | 
					            pthread_setname_np(thrd->handle, name);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyReportError("core", "Ran out of thread objects");
 | 
					        vyReportError("core", "Ran out of thread objects");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -169,4 +180,9 @@ VY_DLLEXPORT void vyJoinThread(vy_thread *thread) {
 | 
				
			|||||||
    pthread_mutex_unlock(&_guard);
 | 
					    pthread_mutex_unlock(&_guard);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VY_DLLEXPORT unsigned int vyGetCPUCoreCount(void) {
 | 
				
			||||||
 | 
					    int n = (int)sysconf(_SC_NPROCESSORS_ONLN);
 | 
				
			||||||
 | 
					    return (n > 0) ? (unsigned int)n : (unsigned int)sysconf(_SC_NPROCESSORS_CONF);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										73
									
								
								src/tests/rttest.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/tests/rttest.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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)];
 | 
				
			||||||
 | 
					    *target = 42;
 | 
				
			||||||
 | 
					    vySetRelptr(ptr, target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void *resolved = vyResolveRelptr(ptr);
 | 
				
			||||||
 | 
					    if ((uintptr_t)resolved != (uintptr_t)target)
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*(unsigned int *)resolved != *target)
 | 
				
			||||||
 | 
					        return 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_result NegRelPtrTest(void) {
 | 
				
			||||||
 | 
					    char buf[sizeof(unsigned int) + sizeof(vy_relptr)];
 | 
				
			||||||
 | 
					    unsigned int *target = (unsigned int *)buf;
 | 
				
			||||||
 | 
					    vy_relptr *ptr       = (vy_relptr *)&buf[sizeof(unsigned int)];
 | 
				
			||||||
 | 
					    *target              = 42;
 | 
				
			||||||
 | 
					    vySetRelptr(ptr, target);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void *resolved = vyResolveRelptr(ptr);
 | 
				
			||||||
 | 
					    if ((uintptr_t)resolved != (uintptr_t)target)
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (*(unsigned int *)resolved != *target)
 | 
				
			||||||
 | 
					        return 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Scaffolding 
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Run all the test cases, output if they passed or failed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef vy_result vy_test_fnc(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    const char *name;
 | 
				
			||||||
 | 
					    vy_test_fnc *fnc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} vy_test_case;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TEST_CASE(fn) { .name = #fn, .fnc = fn, }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_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) {
 | 
				
			||||||
 | 
					        printf("[%s] ... ", _test_cases[i].name);
 | 
				
			||||||
 | 
					        vy_result res = _test_cases[i].fnc();
 | 
				
			||||||
 | 
					        if (res == VY_SUCCESS) {
 | 
				
			||||||
 | 
					            printf("OK\n");
 | 
				
			||||||
 | 
					        } 
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            printf("FAILED (%u)\n", res);
 | 
				
			||||||
 | 
					            ++out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return out;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,20 +1,93 @@
 | 
				
			|||||||
 | 
					#include "assetmeta.h"
 | 
				
			||||||
#include "processing.h"
 | 
					#include "processing.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					#include "packages.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define VY_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
				
			||||||
 | 
					#include "options.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime/aio.h"
 | 
					#include "runtime/aio.h"
 | 
				
			||||||
#include "runtime/buffer_manager.h"
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
#include <stdlib.h>
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern vy_result vyProcessPipelineFile(vy_file_id file,
 | 
					extern vy_result vyProcessPipelineFile(vy_file_id file,
 | 
				
			||||||
                                       void *buffer,
 | 
					                                       void *buffer,
 | 
				
			||||||
                                       size_t size,
 | 
					                                       size_t size,
 | 
				
			||||||
 | 
					                                       uint32_t flags,
 | 
				
			||||||
                                       vy_processor_output *output);
 | 
					                                       vy_processor_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern vy_result vyProcessShaderFile(vy_file_id file,
 | 
					extern vy_result vyProcessShaderFile(vy_file_id file,
 | 
				
			||||||
                                     void *buffer,
 | 
					                                     void *buffer,
 | 
				
			||||||
                                     size_t size,
 | 
					                                     size_t size,
 | 
				
			||||||
 | 
					                                     uint32_t flags,
 | 
				
			||||||
                                     vy_processor_output *output);
 | 
					                                     vy_processor_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_assetc_options g_assetc_options = {
 | 
				
			||||||
 | 
					    .root_directory   = ".",
 | 
				
			||||||
 | 
					    .optimization     = VY_ASSET_OPTIMIZATION_NONE,
 | 
				
			||||||
 | 
					    .renderer_backend = VY_RENDERER_BACKEND_CODE_VK,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseCommandLineArgs(int argc, char **argv) {
 | 
				
			||||||
 | 
					    bool have_root_directory = false;
 | 
				
			||||||
 | 
					    for (int i = 1; i < argc; ++i) {
 | 
				
			||||||
 | 
					        if (i < argc - 1) {
 | 
				
			||||||
 | 
					            const char *val = argv[i + 1];
 | 
				
			||||||
 | 
					            bool matched    = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            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;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                                  "Invalid render backend %s. Valid options are: vk",
 | 
				
			||||||
 | 
					                                  val);
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                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;
 | 
				
			||||||
 | 
					                } else if (strcmp(val, "space") == 0) {
 | 
				
			||||||
 | 
					                    g_assetc_options.optimization = VY_ASSET_OPTIMIZATION_SPACE;
 | 
				
			||||||
 | 
					                } else if (strcmp(val, "performance") == 0) {
 | 
				
			||||||
 | 
					                    g_assetc_options.optimization = VY_ASSET_OPTIMIZATION_PERFORMANCE;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                                  "Invalid optimization level %s. Valid options are: none, space, "
 | 
				
			||||||
 | 
					                                  "performance",
 | 
				
			||||||
 | 
					                                  val);
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                matched = true;
 | 
				
			||||||
 | 
					            } else if (argv[i][0] == '-') {
 | 
				
			||||||
 | 
					                vyReportError("ASSETC", "Invalid command line argument %s", argv[i]);
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (matched) {
 | 
				
			||||||
 | 
					                /* Skip the value */
 | 
				
			||||||
 | 
					                ++i;
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!have_root_directory) {
 | 
				
			||||||
 | 
					            g_assetc_options.root_directory = argv[i];
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            /* Maybe have secondary directories later? */
 | 
				
			||||||
 | 
					            vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                          "More than one root directory passed as command line "
 | 
				
			||||||
 | 
					                          "argument.");
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char **argv) {
 | 
					int main(int argc, char **argv) {
 | 
				
			||||||
    /* Setup */
 | 
					    /* Setup */
 | 
				
			||||||
    if (vyInitFileTab(4096) != VY_SUCCESS) {
 | 
					    if (vyInitFileTab(4096) != VY_SUCCESS) {
 | 
				
			||||||
@ -27,22 +100,37 @@ int main(int argc, char **argv) {
 | 
				
			|||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vyInitUIDMap();
 | 
					    if (!ParseCommandLineArgs(argc, argv)) {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vyInitPackages();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (vyLoadAssetMeta() != VY_SUCCESS) {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vySetWorkingDirectory(g_assetc_options.root_directory);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vyAddAssetProcessor(".pipeline", vyProcessPipelineFile) != VY_SUCCESS)
 | 
					    if (vyAddAssetProcessor(".pipeline", vyProcessPipelineFile) != VY_SUCCESS)
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    if (vyAddAssetProcessor(".shader", vyProcessShaderFile) != VY_SUCCESS)
 | 
					    if (vyAddAssetProcessor(".glsl", vyProcessShaderFile) != VY_SUCCESS)
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (vyStartProcessing() != VY_SUCCESS) {
 | 
					    if (vyStartProcessing() != VY_SUCCESS) {
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vyAddFileToProcessingQueue(vyAddFile("shader\\cell.pipeline"));
 | 
					    vyAddFileToProcessingQueue(vyAddFile("shader\\cell.pipeline"), 0);
 | 
				
			||||||
    while (1)
 | 
					
 | 
				
			||||||
        _sleep(10);
 | 
					    vyWaitUntilProcessingIsFinished();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vyStopProcessing();
 | 
					    vyStopProcessing();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vySaveAssetMeta();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vyShutdownBufferManager();
 | 
				
			||||||
 | 
					    vyShutdownAIO();
 | 
				
			||||||
    vyShutdownFileTab();
 | 
					    vyShutdownFileTab();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										219
									
								
								src/tools/assetc/assetmeta.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								src/tools/assetc/assetmeta.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,219 @@
 | 
				
			|||||||
 | 
					#include "assetmeta.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/threading.h"
 | 
				
			||||||
 | 
					#include "runtime/aio.h"
 | 
				
			||||||
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <xxhash/xxhash.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAP_SIZE 2048
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_file_id fids[MAP_SIZE];
 | 
				
			||||||
 | 
					    vy_uid uids[MAP_SIZE];
 | 
				
			||||||
 | 
					    vy_assetmeta meta[MAP_SIZE];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int used_slots;
 | 
				
			||||||
 | 
					} vy_uid_map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(push, 1)
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    XXH64_canonical_t checksum;
 | 
				
			||||||
 | 
					    uint32_t num_entries;
 | 
				
			||||||
 | 
					    uint32_t _reserved;
 | 
				
			||||||
 | 
					} vy_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;
 | 
				
			||||||
 | 
					#pragma pack(pop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_uid_map _map;
 | 
				
			||||||
 | 
					static vy_mutex *_guard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyLoadAssetMeta(void) {
 | 
				
			||||||
 | 
					    _guard = vyCreateMutex();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /* Load the meta file */
 | 
				
			||||||
 | 
					    size_t fsz = vyGetFileSize("meta.bin");
 | 
				
			||||||
 | 
					    if (fsz == 0) {
 | 
				
			||||||
 | 
					        vyLog("ASSETC", "Metadata file 'meta.bin' not found. All assets will be processed.");
 | 
				
			||||||
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void *buffer = vyAllocBuffer(fsz);
 | 
				
			||||||
 | 
					    if (!buffer) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC", "Failed to allocate buffer for holding asset metadata.");
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    vy_load_batch load;
 | 
				
			||||||
 | 
					    load.loads[0].dest = buffer;
 | 
				
			||||||
 | 
					    load.loads[0].file = vyAddFile("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);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (vyWaitForAIOCompletion(handle) != VY_AIO_STATE_FINISHED) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC", "Failed to load 'meta.bin'.");
 | 
				
			||||||
 | 
					        vyReleaseBuffer(buffer, fsz);
 | 
				
			||||||
 | 
					        vyReleaseAIO(handle);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vyReleaseAIO(handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const vy_assetmeta_header *header = buffer;
 | 
				
			||||||
 | 
					    const vy_assetmeta_entry *entries = (vy_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);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(vy_assetmeta_entry) * header->num_entries);
 | 
				
			||||||
 | 
					    XXH64_hash_t header_hash = XXH64_hashFromCanonical(&header->checksum);
 | 
				
			||||||
 | 
					    if (hash != header_hash) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                      "Metadata file 'meta.bin' is corrupted: Wrong checksum.");
 | 
				
			||||||
 | 
					        vyReleaseBuffer(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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vyReleaseBuffer(buffer, fsz);
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vySaveAssetMeta(void) {
 | 
				
			||||||
 | 
					    vy_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)
 | 
				
			||||||
 | 
					            header.num_entries += 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_assetmeta_entry *entries = vyAllocBuffer(sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
				
			||||||
 | 
					    if (!entries)
 | 
				
			||||||
 | 
					        return VY_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) {
 | 
				
			||||||
 | 
					            entries[j].source_file = _map.fids[i];
 | 
				
			||||||
 | 
					            entries[j].uid         = _map.uids[i];
 | 
				
			||||||
 | 
					            entries[j].meta        = _map.meta[i];
 | 
				
			||||||
 | 
					            ++j;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    XXH64_hash_t hash = XXH3_64bits(entries, sizeof(vy_assetmeta_entry) * header.num_entries);
 | 
				
			||||||
 | 
					    XXH64_canonicalFromHash(&header.checksum, hash);
 | 
				
			||||||
 | 
					    header._reserved = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    FILE *f = fopen("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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fclose(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_uid vyLookupUID(vy_file_id fid) {
 | 
				
			||||||
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					    unsigned int i = 0;
 | 
				
			||||||
 | 
					    vy_uid result  = VY_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) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bool vyGetAssetMeta(vy_file_id source_file, vy_assetmeta *meta) {
 | 
				
			||||||
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					    unsigned int i = 0;
 | 
				
			||||||
 | 
					    bool result    = false;
 | 
				
			||||||
 | 
					    while (i < MAP_SIZE) {
 | 
				
			||||||
 | 
					        unsigned int slot = (source_file + i) % MAP_SIZE;
 | 
				
			||||||
 | 
					        if (_map.fids[slot] == source_file) {
 | 
				
			||||||
 | 
					            *meta  = _map.meta[slot];
 | 
				
			||||||
 | 
					            result = true;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        } else if (_map.fids[slot] == VY_INVALID_FILE_ID) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyAddUIDMapping(vy_file_id fid, vy_uid uid, const vy_assetmeta *meta) {
 | 
				
			||||||
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					    float fill_rate = (float)_map.used_slots / MAP_SIZE;
 | 
				
			||||||
 | 
					    if (fill_rate >= .5f) {
 | 
				
			||||||
 | 
					        vyLog("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) {
 | 
				
			||||||
 | 
					            _map.fids[slot] = fid;
 | 
				
			||||||
 | 
					            _map.uids[slot] = uid;
 | 
				
			||||||
 | 
					            if (meta) {
 | 
				
			||||||
 | 
					                _map.meta[slot] = *meta;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                _map.meta[slot].last_changed = 0;
 | 
				
			||||||
 | 
					                _map.meta[slot].compiled_ts = 0;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            ++_map.used_slots;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        } else if (_map.fids[slot] == fid) {
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        ++i;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (i == MAP_SIZE) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC", "Failed to insert entry into UID map.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/tools/assetc/assetmeta.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/tools/assetc/assetmeta.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_ASSETMETA_H
 | 
				
			||||||
 | 
					#define VY_ASSETC_ASSETMETA_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/file_tab.h"
 | 
				
			||||||
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Metadata for assets used only by assetc */
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    uint64_t last_changed;
 | 
				
			||||||
 | 
					    uint64_t compiled_ts;
 | 
				
			||||||
 | 
					} vy_assetmeta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyLoadAssetMeta(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vySaveAssetMeta(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The UID map associates processed files with generated asset uids. */
 | 
				
			||||||
 | 
					void vyAddUIDMapping(vy_file_id fid, vy_uid uid, const vy_assetmeta *meta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Returns true if the asset is found. false otherwise */
 | 
				
			||||||
 | 
					bool vyGetAssetMeta(vy_file_id source_file, vy_assetmeta *meta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_uid vyLookupUID(vy_file_id fid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/tools/assetc/compiled.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/tools/assetc/compiled.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_COMPILED_H
 | 
				
			||||||
 | 
					#define VY_ASSETC_COMPILED_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_uid vyGetUID(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyStoreOutput(vy_uid uid, const void *data, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyWriteCompiledFiles(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										209
									
								
								src/tools/assetc/description_parser.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								src/tools/assetc/description_parser.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,209 @@
 | 
				
			|||||||
 | 
					#include "description_parser.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool IsAllowedChar(char c) {
 | 
				
			||||||
 | 
					    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
 | 
				
			||||||
 | 
					           (c == '.') || (c == '_') || (c == '/');
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool IsWhitespace(char c) {
 | 
				
			||||||
 | 
					    return c == ' ' || c == '\t' || c == '\n' || c == '\r';
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void SkipWhitespace(vy_parse_state *state) {
 | 
				
			||||||
 | 
					    while (state->at < state->length && IsWhitespace(state->text[state->at])) {
 | 
				
			||||||
 | 
					        if (state->text[state->at] == '\n')
 | 
				
			||||||
 | 
					            ++state->line;
 | 
				
			||||||
 | 
					        ++state->at;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
				
			||||||
 | 
					    vy_text_span name;
 | 
				
			||||||
 | 
					    name.start  = &state->text[state->at];
 | 
				
			||||||
 | 
					    name.length = 0;
 | 
				
			||||||
 | 
					    while (state->at < state->length && !IsWhitespace(state->text[state->at])) {
 | 
				
			||||||
 | 
					        if (IsAllowedChar(state->text[state->at])) {
 | 
				
			||||||
 | 
					            ++state->at;
 | 
				
			||||||
 | 
					            ++name.length;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            vyReportError("GFX",
 | 
				
			||||||
 | 
					                          "%s:%d Unexpected character %c",
 | 
				
			||||||
 | 
					                          state->file,
 | 
				
			||||||
 | 
					                          state->line,
 | 
				
			||||||
 | 
					                          state->text[state->at]);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *_name = name;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
				
			||||||
 | 
					    vy_text_span value;
 | 
				
			||||||
 | 
					    value.start  = &state->text[state->at];
 | 
				
			||||||
 | 
					    value.length = 0;
 | 
				
			||||||
 | 
					    while (state->at < state->length && !IsWhitespace(state->text[state->at]) &&
 | 
				
			||||||
 | 
					           state->text[state->at] != ';') {
 | 
				
			||||||
 | 
					        if (IsAllowedChar(state->text[state->at])) {
 | 
				
			||||||
 | 
					            ++state->at;
 | 
				
			||||||
 | 
					            ++value.length;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            vyReportError("GFX",
 | 
				
			||||||
 | 
					                          "%s:%d Unexpected character %c",
 | 
				
			||||||
 | 
					                          state->file,
 | 
				
			||||||
 | 
					                          state->line,
 | 
				
			||||||
 | 
					                          state->text[state->at]);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *_value = value;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
				
			||||||
 | 
					    vy_parsed_stmt stmt;
 | 
				
			||||||
 | 
					    stmt.next = UINT_MAX; /* end of list */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SkipWhitespace(state);
 | 
				
			||||||
 | 
					    if (!ParseAttribute(state, &stmt.attribute))
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    SkipWhitespace(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state->at == state->length) {
 | 
				
			||||||
 | 
					        vyReportError("GFX", "%s:%d Expected either a value or '{'", state->file, state->line);
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (state->text[state->at] == '{') {
 | 
				
			||||||
 | 
					        /* Consume '{' */
 | 
				
			||||||
 | 
					        ++state->at;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        stmt.form = VY_STMT_FORM_LIST;
 | 
				
			||||||
 | 
					        if (!ParseStmtList(state, &stmt.list_index))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Consume '}' */
 | 
				
			||||||
 | 
					        if (state->at < state->length && state->text[state->at] == '}')
 | 
				
			||||||
 | 
					            ++state->at;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        stmt.form = VY_STMT_FORM_VALUE;
 | 
				
			||||||
 | 
					        if (!ParseValue(state, &stmt.value))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Consume ';' */
 | 
				
			||||||
 | 
					        if (state->at < state->length && state->text[state->at] == ';')
 | 
				
			||||||
 | 
					            ++state->at;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    SkipWhitespace(state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 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);
 | 
				
			||||||
 | 
					        if (!temp) {
 | 
				
			||||||
 | 
					            vyReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        state->statements         = temp;
 | 
				
			||||||
 | 
					        state->statement_capacity = cap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    state->statements[state->statement_count] = stmt;
 | 
				
			||||||
 | 
					    *stmt_index                               = state->statement_count++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
				
			||||||
 | 
					    vy_parsed_stmt_list list;
 | 
				
			||||||
 | 
					    list.first = UINT_MAX;
 | 
				
			||||||
 | 
					    list.count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int last = UINT_MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (state->at < state->length && state->text[state->at] != '}') {
 | 
				
			||||||
 | 
					        unsigned int stmt;
 | 
				
			||||||
 | 
					        if (!ParseStmt(state, &stmt))
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (last != UINT_MAX)
 | 
				
			||||||
 | 
					            state->statements[last].next = stmt;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            list.first = stmt;
 | 
				
			||||||
 | 
					        last = stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ++list.count;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Add list to array */
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					        if (!temp) {
 | 
				
			||||||
 | 
					            vyReportError("GFX", "While parsing %s: Out of memory\n", state->file);
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        state->statement_lists         = temp;
 | 
				
			||||||
 | 
					        state->statement_list_capacity = cap;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    state->statement_lists[state->statement_list_count] = list;
 | 
				
			||||||
 | 
					    *list_index                                         = state->statement_list_count++;
 | 
				
			||||||
 | 
					    return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const vy_parsed_stmt * vyFindStatement(const vy_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];
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
 | 
					            return stmt;
 | 
				
			||||||
 | 
					        stmt_index = stmt->next;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyParseDescription(const char *text,
 | 
				
			||||||
 | 
					                             size_t length,
 | 
				
			||||||
 | 
					                             const char *file_path,
 | 
				
			||||||
 | 
					                             unsigned int *_root_list,
 | 
				
			||||||
 | 
					                             vy_parse_state *_state) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_parse_state state = {.text                    = text,
 | 
				
			||||||
 | 
					                            .at                      = 0,
 | 
				
			||||||
 | 
					                            .length                  = length,
 | 
				
			||||||
 | 
					                            .line                    = 1,
 | 
				
			||||||
 | 
					                            .file                    = file_path,
 | 
				
			||||||
 | 
					                            .statements              = NULL,
 | 
				
			||||||
 | 
					                            .statement_lists         = NULL,
 | 
				
			||||||
 | 
					                            .statement_capacity      = 0,
 | 
				
			||||||
 | 
					                            .statement_list_capacity = 0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int root_list = 0;
 | 
				
			||||||
 | 
					    if (!ParseStmtList(&state, &root_list)) {
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    *_root_list = root_list;
 | 
				
			||||||
 | 
					    *_state     = state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyReleaseParseState(vy_parse_state *state) {
 | 
				
			||||||
 | 
					    free(state->statements);
 | 
				
			||||||
 | 
					    free(state->statement_lists);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										53
									
								
								src/tools/assetc/description_parser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/tools/assetc/description_parser.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_DESCRIPTION_PARSER_H
 | 
				
			||||||
 | 
					#define VY_ASSETC_DESCRIPTION_PARSER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    VY_STMT_FORM_VALUE,
 | 
				
			||||||
 | 
					    VY_STMT_FORM_LIST,
 | 
				
			||||||
 | 
					} vy_stmt_form;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    unsigned int first;
 | 
				
			||||||
 | 
					    unsigned int count;
 | 
				
			||||||
 | 
					} vy_parsed_stmt_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_stmt_form form;
 | 
				
			||||||
 | 
					    vy_text_span attribute;
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        vy_text_span value;
 | 
				
			||||||
 | 
					        unsigned int list_index;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    /* For lists */
 | 
				
			||||||
 | 
					    unsigned int next;
 | 
				
			||||||
 | 
					} vy_parsed_stmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    const char *file;
 | 
				
			||||||
 | 
					    const char *text;
 | 
				
			||||||
 | 
					    size_t at;
 | 
				
			||||||
 | 
					    size_t length;
 | 
				
			||||||
 | 
					    int line;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_parsed_stmt *statements;
 | 
				
			||||||
 | 
					    unsigned int statement_count;
 | 
				
			||||||
 | 
					    unsigned int statement_capacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_parsed_stmt_list *statement_lists;
 | 
				
			||||||
 | 
					    unsigned int statement_list_count;
 | 
				
			||||||
 | 
					    unsigned int statement_list_capacity;
 | 
				
			||||||
 | 
					} vy_parse_state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyParseDescription(const char *text,
 | 
				
			||||||
 | 
					                             size_t length,
 | 
				
			||||||
 | 
					                             const char *file_path,
 | 
				
			||||||
 | 
					                             unsigned int *root_list,
 | 
				
			||||||
 | 
					                             vy_parse_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const vy_parsed_stmt *vyFindStatement(const vy_parse_state *state, unsigned int list_index, const char *attribute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyReleaseParseState(vy_parse_state *state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/tools/assetc/discovery.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/tools/assetc/discovery.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					void DiscoverAssets(void) {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								src/tools/assetc/options.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/tools/assetc/options.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_OPTIONS_H
 | 
				
			||||||
 | 
					#define VY_ASSETC_OPTIONS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum {
 | 
				
			||||||
 | 
					    /* No optimization */
 | 
				
			||||||
 | 
					    VY_ASSET_OPTIMIZATION_NONE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Create small assets */
 | 
				
			||||||
 | 
					    VY_ASSET_OPTIMIZATION_SPACE,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Create assets for fast execution */
 | 
				
			||||||
 | 
					    VY_ASSET_OPTIMIZATION_PERFORMANCE,
 | 
				
			||||||
 | 
					} vy_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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef VY_ASSETC_DONT_DEFINE_OPTIONS_GLOBAL
 | 
				
			||||||
 | 
					extern vy_assetc_options g_assetc_options;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										90
									
								
								src/tools/assetc/packages.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								src/tools/assetc/packages.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					#include "packages.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/threading.h"
 | 
				
			||||||
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_uid uid;
 | 
				
			||||||
 | 
					    void *buffer;
 | 
				
			||||||
 | 
					    size_t buffer_size;
 | 
				
			||||||
 | 
					} vy_package_entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    char *name;
 | 
				
			||||||
 | 
					    unsigned int num_entries;
 | 
				
			||||||
 | 
					    unsigned int entry_capacity;
 | 
				
			||||||
 | 
					    vy_package_entry *entries;
 | 
				
			||||||
 | 
					} vy_package;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define MAX_PACKAGES 1024
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_package _packages[MAX_PACKAGES];
 | 
				
			||||||
 | 
					unsigned int _package_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_mutex *_guard;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int vyAddPackageFile(vy_text_span name) {
 | 
				
			||||||
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (unsigned int i = 0; i < _package_count; ++i) {
 | 
				
			||||||
 | 
					        if (vyCompareSpanToString(name, _packages[i].name) == 0) {
 | 
				
			||||||
 | 
					            vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					            return i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Create a new package */
 | 
				
			||||||
 | 
					    _packages[_package_count].name = malloc(name.length + 1);
 | 
				
			||||||
 | 
					    if (!_packages[_package_count].name) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                      "Failed to allocate storage for new package %*.s",
 | 
				
			||||||
 | 
					                      name.length,
 | 
				
			||||||
 | 
					                      name.start);
 | 
				
			||||||
 | 
					        vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					        return UINT_MAX;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    memcpy(_packages[_package_count].name, name.start, name.length);
 | 
				
			||||||
 | 
					    _packages[_package_count].name[name.length] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsigned int index = _package_count++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					    return index;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyInitPackages(void) {
 | 
				
			||||||
 | 
					    _guard = vyCreateMutex();
 | 
				
			||||||
 | 
					    /* Create the default package (0) */
 | 
				
			||||||
 | 
					    vyAddPackageFile((vy_text_span){.start = "default.pkg", .length = 12});
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyAddAssetToPackage(unsigned int package, vy_uid uid, void *buffer, size_t size) {
 | 
				
			||||||
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					    if (package >= _package_count) {
 | 
				
			||||||
 | 
					        vyReportError("ASSETC", "Trying to add an asset to a non-existing package.");
 | 
				
			||||||
 | 
					        vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vy_package *pkg = &_packages[package];
 | 
				
			||||||
 | 
					    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));
 | 
				
			||||||
 | 
					        if (!n) {
 | 
				
			||||||
 | 
					            vyReportError("ASSETC", "Failed to grow storage for package %u.", package);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pkg->entry_capacity = new_cap;
 | 
				
			||||||
 | 
					        pkg->entries        = n;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pkg->entries[pkg->num_entries].buffer = buffer;
 | 
				
			||||||
 | 
					    pkg->entries[pkg->num_entries].buffer_size = size;
 | 
				
			||||||
 | 
					    pkg->entries[pkg->num_entries].uid = uid;
 | 
				
			||||||
 | 
					    ++pkg->num_entries;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								src/tools/assetc/packages.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/tools/assetc/packages.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_PACKAGES_H
 | 
				
			||||||
 | 
					#define VY_ASSETC_PACKAGES_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyInitPackages(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unsigned int vyAddPackageFile(vy_text_span name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyAddAssetToPackage(unsigned int package, vy_uid uid, void *buffer, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -10,213 +10,36 @@
 | 
				
			|||||||
#include "runtime/gfx.h"
 | 
					#include "runtime/gfx.h"
 | 
				
			||||||
#include "runtime/handles.h"
 | 
					#include "runtime/handles.h"
 | 
				
			||||||
#include "runtime/runtime.h"
 | 
					#include "runtime/runtime.h"
 | 
				
			||||||
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
 | 
					#include "runtime/renderer_api.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "assetmeta.h"
 | 
				
			||||||
 | 
					#include "description_parser.h"
 | 
				
			||||||
 | 
					#include "options.h"
 | 
				
			||||||
#include "processing.h"
 | 
					#include "processing.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
typedef enum {
 | 
					#include "processing_flags.h"
 | 
				
			||||||
    VY_STMT_FORM_VALUE,
 | 
					 | 
				
			||||||
    VY_STMT_FORM_LIST,
 | 
					 | 
				
			||||||
} vy_stmt_form;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    unsigned int first;
 | 
					    vy_attribute_binding *uniform_bindings;
 | 
				
			||||||
    unsigned int count;
 | 
					    vy_attribute_binding *storage_bindings;
 | 
				
			||||||
} vy_parsed_stmt_list;
 | 
					    vy_attribute_binding *texture_bindings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					    vy_uid vertex_shader;
 | 
				
			||||||
    vy_stmt_form form;
 | 
					    vy_uid fragment_shader;
 | 
				
			||||||
    vy_text_span attribute;
 | 
					    vy_uid compute_shader;
 | 
				
			||||||
    union {
 | 
					 | 
				
			||||||
        vy_text_span value;
 | 
					 | 
				
			||||||
        unsigned int list_index;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
    /* For lists */
 | 
					 | 
				
			||||||
    unsigned int next;
 | 
					 | 
				
			||||||
} vy_parsed_stmt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					    /* TODO Fixed function settings */
 | 
				
			||||||
    const char *file;
 | 
					 | 
				
			||||||
    const char *text;
 | 
					 | 
				
			||||||
    size_t at;
 | 
					 | 
				
			||||||
    size_t length;
 | 
					 | 
				
			||||||
    int line;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_parsed_stmt *statements;
 | 
					    /* Sampler settings */
 | 
				
			||||||
    unsigned int statement_count;
 | 
					 | 
				
			||||||
    unsigned int statement_capacity;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_parsed_stmt_list *statement_lists;
 | 
					    uint16_t uniform_binding_count;
 | 
				
			||||||
    unsigned int statement_list_count;
 | 
					    uint16_t storage_binding_count;
 | 
				
			||||||
    unsigned int statement_list_capacity;
 | 
					    uint16_t texture_binding_count;
 | 
				
			||||||
} vy_parse_state;
 | 
					} vy_parsed_pipeline_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool IsAllowedChar(char c) {
 | 
					static void
 | 
				
			||||||
    return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
 | 
					DbgPrintShaderFile(const vy_parse_state *state, unsigned int list_index, unsigned int indent) {
 | 
				
			||||||
           (c >= 'A' && c <= 'Z') || (c == '.') || (c == '_') || (c == '/');
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool IsWhitespace(char c) {
 | 
					 | 
				
			||||||
    return c == ' ' || c == '\t' || c == '\n' || c == '\r';
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void SkipWhitespace(vy_parse_state *state) {
 | 
					 | 
				
			||||||
    while (state->at < state->length && IsWhitespace(state->text[state->at])) {
 | 
					 | 
				
			||||||
        if (state->text[state->at] == '\n')
 | 
					 | 
				
			||||||
            ++state->line;
 | 
					 | 
				
			||||||
        ++state->at;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseAttribute(vy_parse_state *state, vy_text_span *_name) {
 | 
					 | 
				
			||||||
    vy_text_span name;
 | 
					 | 
				
			||||||
    name.start  = &state->text[state->at];
 | 
					 | 
				
			||||||
    name.length = 0;
 | 
					 | 
				
			||||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at])) {
 | 
					 | 
				
			||||||
        if (IsAllowedChar(state->text[state->at])) {
 | 
					 | 
				
			||||||
            ++state->at;
 | 
					 | 
				
			||||||
            ++name.length;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            vyReportError("GFX",
 | 
					 | 
				
			||||||
                          "%s:%d Unexpected character %c",
 | 
					 | 
				
			||||||
                          state->file,
 | 
					 | 
				
			||||||
                          state->line,
 | 
					 | 
				
			||||||
                          state->text[state->at]);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    *_name = name;
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseValue(vy_parse_state *state, vy_text_span *_value) {
 | 
					 | 
				
			||||||
    vy_text_span value;
 | 
					 | 
				
			||||||
    value.start  = &state->text[state->at];
 | 
					 | 
				
			||||||
    value.length = 0;
 | 
					 | 
				
			||||||
    while (state->at < state->length && !IsWhitespace(state->text[state->at]) &&
 | 
					 | 
				
			||||||
           state->text[state->at] != ';') {
 | 
					 | 
				
			||||||
        if (IsAllowedChar(state->text[state->at])) {
 | 
					 | 
				
			||||||
            ++state->at;
 | 
					 | 
				
			||||||
            ++value.length;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            vyReportError("GFX",
 | 
					 | 
				
			||||||
                          "%s:%d Unexpected character %c",
 | 
					 | 
				
			||||||
                          state->file,
 | 
					 | 
				
			||||||
                          state->line,
 | 
					 | 
				
			||||||
                          state->text[state->at]);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    *_value = value;
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseStmt(vy_parse_state *state, unsigned int *stmt_index) {
 | 
					 | 
				
			||||||
    vy_parsed_stmt stmt;
 | 
					 | 
				
			||||||
    stmt.next = UINT_MAX; /* end of list */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SkipWhitespace(state);
 | 
					 | 
				
			||||||
    if (!ParseAttribute(state, &stmt.attribute))
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    SkipWhitespace(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (state->at == state->length) {
 | 
					 | 
				
			||||||
        vyReportError("GFX",
 | 
					 | 
				
			||||||
                      "%s:%d Expected either a value or '{'",
 | 
					 | 
				
			||||||
                      state->file,
 | 
					 | 
				
			||||||
                      state->line);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (state->text[state->at] == '{') {
 | 
					 | 
				
			||||||
        /* Consume '{' */
 | 
					 | 
				
			||||||
        ++state->at;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        stmt.form = VY_STMT_FORM_LIST;
 | 
					 | 
				
			||||||
        if (!ParseStmtList(state, &stmt.list_index))
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Consume '}' */
 | 
					 | 
				
			||||||
        if (state->at < state->length && state->text[state->at] == '}')
 | 
					 | 
				
			||||||
            ++state->at;
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        stmt.form = VY_STMT_FORM_VALUE;
 | 
					 | 
				
			||||||
        if (!ParseValue(state, &stmt.value))
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Consume ';' */
 | 
					 | 
				
			||||||
        if (state->at < state->length && state->text[state->at] == ';')
 | 
					 | 
				
			||||||
            ++state->at;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    SkipWhitespace(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* 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);
 | 
					 | 
				
			||||||
        if (!temp) {
 | 
					 | 
				
			||||||
            vyReportError("GFX",
 | 
					 | 
				
			||||||
                          "While parsing %s: Out of memory\n",
 | 
					 | 
				
			||||||
                          state->file);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        state->statements         = temp;
 | 
					 | 
				
			||||||
        state->statement_capacity = cap;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    state->statements[state->statement_count] = stmt;
 | 
					 | 
				
			||||||
    *stmt_index                               = state->statement_count++;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseStmtList(vy_parse_state *state, unsigned int *list_index) {
 | 
					 | 
				
			||||||
    vy_parsed_stmt_list list;
 | 
					 | 
				
			||||||
    list.first = state->statement_count;
 | 
					 | 
				
			||||||
    list.count = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    unsigned int last = UINT_MAX;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (state->at < state->length && state->text[state->at] != '}') {
 | 
					 | 
				
			||||||
        unsigned int stmt;
 | 
					 | 
				
			||||||
        if (!ParseStmt(state, &stmt))
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (last != UINT_MAX)
 | 
					 | 
				
			||||||
            state->statements[last].next = stmt;
 | 
					 | 
				
			||||||
        last = stmt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ++list.count;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Add list to array */
 | 
					 | 
				
			||||||
    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);
 | 
					 | 
				
			||||||
        if (!temp) {
 | 
					 | 
				
			||||||
            vyReportError("GFX",
 | 
					 | 
				
			||||||
                          "While parsing %s: Out of memory\n",
 | 
					 | 
				
			||||||
                          state->file);
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        state->statement_lists         = temp;
 | 
					 | 
				
			||||||
        state->statement_list_capacity = cap;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    state->statement_lists[state->statement_list_count] = list;
 | 
					 | 
				
			||||||
    *list_index = state->statement_list_count++;
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void DbgPrintShaderFile(const vy_parse_state *state,
 | 
					 | 
				
			||||||
                               unsigned int list_index,
 | 
					 | 
				
			||||||
                               unsigned int indent) {
 | 
					 | 
				
			||||||
    assert(list_index < state->statement_list_count);
 | 
					    assert(list_index < state->statement_list_count);
 | 
				
			||||||
    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
					    const vy_parsed_stmt_list *list = &state->statement_lists[list_index];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -238,33 +61,6 @@ static void DbgPrintShaderFile(const vy_parse_state *state,
 | 
				
			|||||||
    assert(stmt_index == UINT_MAX || stmt_index == 0);
 | 
					    assert(stmt_index == UINT_MAX || stmt_index == 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool CompareSpanToString(vy_text_span span, const char *cmp) {
 | 
					 | 
				
			||||||
    size_t cmp_len = strlen(cmp);
 | 
					 | 
				
			||||||
    if (cmp_len != (size_t)span.length)
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    for (size_t i = 0; i < cmp_len; ++i) {
 | 
					 | 
				
			||||||
        if (span.start[i] != cmp[i])
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const vy_parsed_stmt *FindStatement(const vy_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];
 | 
					 | 
				
			||||||
    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 (CompareSpanToString(stmt->attribute, attribute))
 | 
					 | 
				
			||||||
            return stmt;
 | 
					 | 
				
			||||||
        stmt_index = stmt->next;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
					static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
				
			||||||
    if (span.length == 0)
 | 
					    if (span.length == 0)
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
@ -276,8 +72,7 @@ static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
				
			|||||||
            unsigned int digit = (unsigned int)(span.start[at] - '0');
 | 
					            unsigned int digit = (unsigned int)(span.start[at] - '0');
 | 
				
			||||||
            n += digit * exp;
 | 
					            n += digit * exp;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            vyReportError("GFX",
 | 
					            vyReportError("GFX", "Unexpected non-digit character in binding index");
 | 
				
			||||||
                          "Unexpected non-digit character in binding index");
 | 
					 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        --at;
 | 
					        --at;
 | 
				
			||||||
@ -288,15 +83,12 @@ static bool ParseBindingIndex(vy_text_span span, unsigned int *index) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_attribute_value ParseBindingValue(vy_text_span span) {
 | 
					static vy_attribute_value ParseBindingValue(vy_text_span span) {
 | 
				
			||||||
    if (CompareSpanToString(span, "MATERIAL_ALBEDO")) {
 | 
					    if (vyCompareSpanToString(span, "MATERIAL_ALBEDO") == 0) {
 | 
				
			||||||
        return VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO;
 | 
					        return VY_ATTRIBUTE_VALUE_MATERIAL_ALBEDO;
 | 
				
			||||||
    } else if (CompareSpanToString(span, "MATERIAL_NORMAL")) {
 | 
					    } else if (vyCompareSpanToString(span, "MATERIAL_NORMAL") == 0) {
 | 
				
			||||||
        return VY_ATTRIBUTE_VALUE_MATERIAL_NORMAL;
 | 
					        return VY_ATTRIBUTE_VALUE_MATERIAL_NORMAL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vyReportError("GFX",
 | 
					    vyReportError("GFX", "Unsupported binding value %*.s", span.length, span.start);
 | 
				
			||||||
                  "Unsupported binding value %*.s",
 | 
					 | 
				
			||||||
                  span.length,
 | 
					 | 
				
			||||||
                  span.start);
 | 
					 | 
				
			||||||
    return VY_ATTRIBUTE_VALUE_UNDEFINED;
 | 
					    return VY_ATTRIBUTE_VALUE_UNDEFINED;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -305,8 +97,8 @@ static bool ParseBindings(vy_parse_state *state,
 | 
				
			|||||||
                          const char *name,
 | 
					                          const char *name,
 | 
				
			||||||
                          const char *file_path,
 | 
					                          const char *file_path,
 | 
				
			||||||
                          vy_attribute_binding **p_bindings,
 | 
					                          vy_attribute_binding **p_bindings,
 | 
				
			||||||
                          unsigned int *p_binding_count) {
 | 
					                          uint16_t *p_binding_count) {
 | 
				
			||||||
    const vy_parsed_stmt *bindings = FindStatement(state, root_list, name);
 | 
					    const vy_parsed_stmt *bindings = vyFindStatement(state, root_list, name);
 | 
				
			||||||
    if (bindings) {
 | 
					    if (bindings) {
 | 
				
			||||||
        if (bindings->form != VY_STMT_FORM_LIST) {
 | 
					        if (bindings->form != VY_STMT_FORM_LIST) {
 | 
				
			||||||
            vyReportError("GFX",
 | 
					            vyReportError("GFX",
 | 
				
			||||||
@ -316,10 +108,9 @@ static bool ParseBindings(vy_parse_state *state,
 | 
				
			|||||||
                          file_path);
 | 
					                          file_path);
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const vy_parsed_stmt_list *binding_list =
 | 
					        const vy_parsed_stmt_list *binding_list = &state->statement_lists[bindings->list_index];
 | 
				
			||||||
            &state->statement_lists[bindings->list_index];
 | 
					 | 
				
			||||||
        vy_attribute_binding *shader_bindings =
 | 
					        vy_attribute_binding *shader_bindings =
 | 
				
			||||||
            malloc(sizeof(vy_attribute_binding) * binding_list->count);
 | 
					            vyAllocBuffer(sizeof(vy_attribute_binding) * binding_list->count);
 | 
				
			||||||
        if (!bindings) {
 | 
					        if (!bindings) {
 | 
				
			||||||
            vyReportError("GFX", "Out of memory");
 | 
					            vyReportError("GFX", "Out of memory");
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
@ -329,22 +120,23 @@ static bool ParseBindings(vy_parse_state *state,
 | 
				
			|||||||
        unsigned int stmt_index = binding_list->first;
 | 
					        unsigned int stmt_index = binding_list->first;
 | 
				
			||||||
        for (unsigned int i = 0; i < binding_list->count; ++i) {
 | 
					        for (unsigned int i = 0; i < binding_list->count; ++i) {
 | 
				
			||||||
            const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
					            const vy_parsed_stmt *stmt = &state->statements[stmt_index];
 | 
				
			||||||
            if (!ParseBindingIndex(stmt->attribute,
 | 
					            if (!ParseBindingIndex(stmt->attribute, &shader_bindings[i].index)) {
 | 
				
			||||||
                                   &shader_bindings[i].index)) {
 | 
					                vyReleaseBuffer(shader_bindings,
 | 
				
			||||||
                free(shader_bindings);
 | 
					                                sizeof(vy_attribute_binding) * binding_list->count);
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            shader_bindings[i].value = ParseBindingValue(stmt->value);
 | 
					            shader_bindings[i].value = ParseBindingValue(stmt->value);
 | 
				
			||||||
            if (shader_bindings[i].value == VY_ATTRIBUTE_VALUE_UNDEFINED) {
 | 
					            if (shader_bindings[i].value == VY_ATTRIBUTE_VALUE_UNDEFINED) {
 | 
				
			||||||
                free(shader_bindings);
 | 
					                vyReleaseBuffer(shader_bindings,
 | 
				
			||||||
 | 
					                                sizeof(vy_attribute_binding) * binding_list->count);
 | 
				
			||||||
                return false;
 | 
					                return false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            stmt_index = stmt->next;
 | 
					            stmt_index = stmt->next;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        *p_bindings      = shader_bindings;
 | 
					        *p_bindings      = shader_bindings;
 | 
				
			||||||
        *p_binding_count = binding_count;
 | 
					        *p_binding_count = (uint16_t)binding_count;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        *p_bindings      = NULL;
 | 
					        *p_bindings      = NULL;
 | 
				
			||||||
@ -353,136 +145,163 @@ static bool ParseBindings(vy_parse_state *state,
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    VY_SHADER_STAGE_BIT_begin,
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    VY_SHADER_STAGE_BIT_VERTEX   = 1,
 | 
					 | 
				
			||||||
    VY_SHADER_STAGE_BIT_FRAGMENT = 2,
 | 
					 | 
				
			||||||
    VY_SHADER_STAGE_BIT_COMPUTE  = 3,
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    VY_SHADER_STAGE_BIT_count,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
#define VY_SSBIT(n) (1 << (n))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    vy_attribute_binding *uniform_bindings;
 | 
					 | 
				
			||||||
    vy_attribute_binding *storage_bindings;
 | 
					 | 
				
			||||||
    vy_attribute_binding *texture_bindings;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Toggels shader stages on or off */
 | 
					 | 
				
			||||||
    uint32_t shader_stage_bitmask;
 | 
					 | 
				
			||||||
    vy_uid vertex_shader;
 | 
					 | 
				
			||||||
    vy_uid fragment_shader;
 | 
					 | 
				
			||||||
    vy_uid compute_shader;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* TODO Fixed function settings */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /* Sampler settings */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    unsigned int uniform_binding_count;
 | 
					 | 
				
			||||||
    unsigned int storage_binding_count;
 | 
					 | 
				
			||||||
    unsigned int texture_binding_count;
 | 
					 | 
				
			||||||
} vy_pipeline_data;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static vy_result ParseShader(vy_parse_state *state,
 | 
					static vy_result ParseShader(vy_parse_state *state,
 | 
				
			||||||
                             unsigned int root_list,
 | 
					                             unsigned int root_list,
 | 
				
			||||||
                             const char *name,
 | 
					                             const char *name,
 | 
				
			||||||
                             const char *file_path,
 | 
					                             const char *file_path,
 | 
				
			||||||
 | 
					                             uint32_t processing_flags,
 | 
				
			||||||
                             vy_uid *p_shader_uid) {
 | 
					                             vy_uid *p_shader_uid) {
 | 
				
			||||||
    const vy_parsed_stmt *stmt = FindStatement(state, root_list, name);
 | 
					    const vy_parsed_stmt *stmt = vyFindStatement(state, root_list, name);
 | 
				
			||||||
    if (stmt) {
 | 
					    if (stmt) {
 | 
				
			||||||
        if (stmt->form != VY_STMT_FORM_VALUE) {
 | 
					        if (stmt->form != VY_STMT_FORM_LIST) {
 | 
				
			||||||
            vyReportError("GFX",
 | 
					            vyReportError("GFX",
 | 
				
			||||||
                          "Expected a file name as the value of "
 | 
					                          "Expected a list as the value of "
 | 
				
			||||||
                          "\"%s\" in %s",
 | 
					                          "\"%s\" in %s",
 | 
				
			||||||
                          name,
 | 
					                          name,
 | 
				
			||||||
                          file_path);
 | 
					                          file_path);
 | 
				
			||||||
            return VY_PROCESSING_FAILED;
 | 
					            return VY_PROCESSING_FAILED;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        vy_file_id shader_file = vyAddFileFromSpan(stmt->value);
 | 
					        const vy_parsed_stmt_list *shader_list = &state->statement_lists[stmt->list_index];
 | 
				
			||||||
        vy_uid uid             = vyLookupUID(shader_file);
 | 
					 | 
				
			||||||
        if (uid == VY_INVALID_UID) {
 | 
					 | 
				
			||||||
            /* Add the shader file to processing and wait until its done */
 | 
					 | 
				
			||||||
            if (vyAddFileToProcessingQueue(shader_file) != VY_SUCCESS)
 | 
					 | 
				
			||||||
                return VY_PROCESSING_FAILED;
 | 
					 | 
				
			||||||
            return VY_PROCESSING_TRY_AGAIN;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        *p_shader_uid = uid;
 | 
					        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",
 | 
				
			||||||
 | 
					                              "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;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            vy_renderer_backend_code backend = VY_INVALID_RENDERER_BACKEND_CODE;
 | 
				
			||||||
 | 
					            if (vyCompareSpanToString(shader->attribute, "vk") == 0) {
 | 
				
			||||||
 | 
					                backend = VY_RENDERER_BACKEND_CODE_VK;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                vyReportError("GFX",
 | 
				
			||||||
 | 
					                              "Invalid renderer backend"
 | 
				
			||||||
 | 
					                              "\"%*s\" in %s of file %s",
 | 
				
			||||||
 | 
					                              (int)shader->attribute.length,
 | 
				
			||||||
 | 
					                              shader->attribute.start,
 | 
				
			||||||
 | 
					                              name,
 | 
				
			||||||
 | 
					                              file_path);
 | 
				
			||||||
 | 
					                return VY_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) {
 | 
				
			||||||
 | 
					                    /* 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;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                *p_shader_uid = uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                /* Don't break, because that validates the file. (attributes are checked for invalid
 | 
				
			||||||
 | 
					                 * values). */
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            stmt_index = shader->next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return VY_SUCCESS;
 | 
					        return VY_SUCCESS;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return VY_PROCESSING_FAILED;
 | 
					    return VY_PROCESSING_FAILED;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_result ParsePipelineFile(vy_file_id fid,
 | 
					static uint32_t
 | 
				
			||||||
                                   const char *text,
 | 
					ParseOptimizationLevel(vy_parse_state *state, unsigned int root_list, const char *file_path) {
 | 
				
			||||||
                                   size_t length,
 | 
					    uint32_t optimization_level;
 | 
				
			||||||
                                   vy_pipeline_data *pipeline) {
 | 
					    switch (g_assetc_options.optimization) { 
 | 
				
			||||||
 | 
					    case VY_ASSET_OPTIMIZATION_PERFORMANCE:
 | 
				
			||||||
 | 
					        optimization_level = VY_SHADER_FLAG_OPTIMIZE_SPEED;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VY_ASSET_OPTIMIZATION_SPACE:
 | 
				
			||||||
 | 
					        optimization_level = VY_SHADER_FLAG_OPTIMIZE_SIZE;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        optimization_level = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const vy_parsed_stmt *stmt = vyFindStatement(state, root_list, "optimization");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (stmt) {
 | 
				
			||||||
 | 
					        if (stmt->form != VY_STMT_FORM_VALUE) {
 | 
				
			||||||
 | 
					            vyReportError("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) {
 | 
				
			||||||
 | 
					            optimization_level = 0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            vyReportError("GFX",
 | 
				
			||||||
 | 
					                          "Expected one of 'speed', 'size' and 'none' for \"optimization\" in %s",
 | 
				
			||||||
 | 
					                          file_path);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return optimization_level;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_result
 | 
				
			||||||
 | 
					ParsePipelineFile(vy_file_id fid, const char *text, size_t length, vy_parsed_pipeline_data *pipeline) {
 | 
				
			||||||
    /* This is the grammar for pipeline files:
 | 
					    /* This is the grammar for pipeline files:
 | 
				
			||||||
     * <stmt-list> ::= <stmt>*
 | 
					     * <stmt-list> ::= <stmt>*
 | 
				
			||||||
     * <stmt> ::= <attribute> ( ( <value> ';' ) | ( '{' <stmt-list> '}' ) )
 | 
					     * <stmt> ::= <attribute> ( ( <value> ';' ) | ( '{' <stmt-list> '}' ) )
 | 
				
			||||||
     * <attribute> ::= [:alnum:]*
 | 
					     * <attribute> ::= [:alnum:]*
 | 
				
			||||||
     * <value>:: = [:alnum:]* */
 | 
					     * <value>:: = [:alnum:]* */
 | 
				
			||||||
    const char *file_path = vyGetFilePath(fid);
 | 
					    const char *file_path = vyGetFilePath(fid);
 | 
				
			||||||
    vy_parse_state state  = {.text                    = text,
 | 
					    vy_parse_state state;
 | 
				
			||||||
                             .at                      = 0,
 | 
					    unsigned int root_list;
 | 
				
			||||||
                             .length                  = length,
 | 
					    vy_result result = vyParseDescription(text, length, file_path, &root_list, &state);
 | 
				
			||||||
                             .line                    = 1,
 | 
					    if (result != VY_SUCCESS) {
 | 
				
			||||||
                             .file                    = file_path,
 | 
					 | 
				
			||||||
                             .statements              = NULL,
 | 
					 | 
				
			||||||
                             .statement_lists         = NULL,
 | 
					 | 
				
			||||||
                             .statement_capacity      = 0,
 | 
					 | 
				
			||||||
                             .statement_list_capacity = 0};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    vy_result result = VY_SUCCESS;
 | 
					 | 
				
			||||||
    unsigned int root_list = 0;
 | 
					 | 
				
			||||||
    if (!ParseStmtList(&state, &root_list)) {
 | 
					 | 
				
			||||||
        result = false;
 | 
					 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    DbgPrintShaderFile(&state, root_list, 0);
 | 
					    /* We allow the pipeline file to overwrite the optimization level */
 | 
				
			||||||
 | 
					    uint32_t optimization = ParseOptimizationLevel(&state, root_list, file_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Process shader stages */
 | 
					    /* Process shader stages */
 | 
				
			||||||
    pipeline->shader_stage_bitmask = 0;
 | 
					    if (ParseShader(&state,
 | 
				
			||||||
    vy_result shader_result;
 | 
					                    root_list,
 | 
				
			||||||
    if ((shader_result = ParseShader(&state,
 | 
					                    "vertex",
 | 
				
			||||||
                                     root_list,
 | 
					                    file_path,
 | 
				
			||||||
                                     "vertex",
 | 
					                    VY_SHADER_FLAG_VERTEX | optimization,
 | 
				
			||||||
                                     file_path,
 | 
					                    &pipeline->vertex_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
				
			||||||
                                     &pipeline->vertex_shader)) == VY_SUCCESS) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        pipeline->shader_stage_bitmask |= VY_SHADER_STAGE_BIT_VERTEX;
 | 
					 | 
				
			||||||
    } else if (shader_result == VY_PROCESSING_TRY_AGAIN) {
 | 
					 | 
				
			||||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
					        result = VY_PROCESSING_TRY_AGAIN;
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if ((shader_result = ParseShader(&state,
 | 
					    if (ParseShader(&state,
 | 
				
			||||||
                                     root_list,
 | 
					                    root_list,
 | 
				
			||||||
                                     "fragment",
 | 
					                    "fragment",
 | 
				
			||||||
                                     file_path,
 | 
					                    file_path,
 | 
				
			||||||
                                     &pipeline->vertex_shader)) == VY_SUCCESS) {
 | 
					                    VY_SHADER_FLAG_FRAGMENT | optimization,
 | 
				
			||||||
 | 
					                    &pipeline->fragment_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
				
			||||||
        pipeline->shader_stage_bitmask |= VY_SHADER_STAGE_BIT_FRAGMENT;
 | 
					 | 
				
			||||||
    } else if (shader_result == VY_PROCESSING_TRY_AGAIN) {
 | 
					 | 
				
			||||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
					        result = VY_PROCESSING_TRY_AGAIN;
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if ((shader_result = ParseShader(&state,
 | 
					    if (ParseShader(&state,
 | 
				
			||||||
                                     root_list,
 | 
					                    root_list,
 | 
				
			||||||
                                     "compute",
 | 
					                    "compute",
 | 
				
			||||||
                                     file_path,
 | 
					                    file_path,
 | 
				
			||||||
                                     &pipeline->vertex_shader)) == VY_SUCCESS) {
 | 
					                    VY_SHADER_FLAG_COMPUTE | optimization,
 | 
				
			||||||
 | 
					                    &pipeline->compute_shader) == VY_PROCESSING_TRY_AGAIN) {
 | 
				
			||||||
        pipeline->shader_stage_bitmask |= VY_SHADER_STAGE_BIT_COMPUTE;
 | 
					 | 
				
			||||||
    } else if (shader_result == VY_PROCESSING_TRY_AGAIN) {
 | 
					 | 
				
			||||||
        result = VY_PROCESSING_TRY_AGAIN;
 | 
					        result = VY_PROCESSING_TRY_AGAIN;
 | 
				
			||||||
        goto out;
 | 
					        goto out;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Process bindings */
 | 
					    /* Process bindings */
 | 
				
			||||||
    pipeline->texture_bindings    = NULL;
 | 
					    pipeline->texture_bindings      = NULL;
 | 
				
			||||||
    pipeline->texture_binding_count = 0;
 | 
					    pipeline->texture_binding_count = 0;
 | 
				
			||||||
    pipeline->uniform_bindings      = NULL;
 | 
					    pipeline->uniform_bindings      = NULL;
 | 
				
			||||||
    pipeline->uniform_binding_count = 0;
 | 
					    pipeline->uniform_binding_count = 0;
 | 
				
			||||||
@ -528,11 +347,68 @@ out:
 | 
				
			|||||||
vy_result vyProcessPipelineFile(vy_file_id file,
 | 
					vy_result vyProcessPipelineFile(vy_file_id file,
 | 
				
			||||||
                                void *buffer,
 | 
					                                void *buffer,
 | 
				
			||||||
                                size_t size,
 | 
					                                size_t size,
 | 
				
			||||||
 | 
					                                uint32_t flags,
 | 
				
			||||||
                                vy_processor_output *output) {
 | 
					                                vy_processor_output *output) {
 | 
				
			||||||
    vy_pipeline_data tmp;
 | 
					    VY_UNUSED(flags);
 | 
				
			||||||
 | 
					    vy_parsed_pipeline_data tmp;
 | 
				
			||||||
 | 
					    memset(&tmp, 0, sizeof(tmp));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_result result = ParsePipelineFile(file, buffer, size, &tmp);
 | 
					    vy_result result = ParsePipelineFile(file, buffer, size, &tmp);
 | 
				
			||||||
    if (result == VY_SUCCESS) {
 | 
					    if (result == VY_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) *
 | 
				
			||||||
 | 
					                (tmp.storage_binding_count + tmp.texture_binding_count + tmp.uniform_binding_count);
 | 
				
			||||||
 | 
					        void *out_buffer = vyAllocBuffer(outbuffer_size);
 | 
				
			||||||
 | 
					        if (!buffer) {
 | 
				
			||||||
 | 
					            return VY_PROCESSING_FAILED;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vy_pipeline_info *info      = out_buffer;
 | 
				
			||||||
 | 
					        info->vertex_shader         = tmp.vertex_shader;
 | 
				
			||||||
 | 
					        info->fragment_shader       = tmp.fragment_shader;
 | 
				
			||||||
 | 
					        info->compute_shader        = tmp.compute_shader;
 | 
				
			||||||
 | 
					        info->texture_binding_count = tmp.texture_binding_count;
 | 
				
			||||||
 | 
					        info->uniform_binding_count = tmp.uniform_binding_count;
 | 
				
			||||||
 | 
					        info->storage_binding_count = tmp.storage_binding_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vy_attribute_binding *texture_bindings = NULL;
 | 
				
			||||||
 | 
					        if (tmp.texture_binding_count > 0) {
 | 
				
			||||||
 | 
					            texture_bindings = (vy_attribute_binding *)(info + 1);
 | 
				
			||||||
 | 
					            memcpy(texture_bindings,
 | 
				
			||||||
 | 
					                   tmp.texture_bindings,
 | 
				
			||||||
 | 
					                   sizeof(vy_attribute_binding) * tmp.texture_binding_count);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vy_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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vy_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);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        vySetRelptr(&info->texture_bindings, texture_bindings);
 | 
				
			||||||
 | 
					        vySetRelptr(&info->uniform_bindings, uniform_bindings);
 | 
				
			||||||
 | 
					        vySetRelptr(&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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        output->data      = out_buffer;
 | 
				
			||||||
 | 
					        output->size      = outbuffer_size;
 | 
				
			||||||
 | 
					        output->asset_uid = vyCalculateUID(vyGetFilePath(file));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
#ifndef VY_ASSETC_PROCESSING_H
 | 
					#ifndef VY_ASSETC_PROCESSING_H
 | 
				
			||||||
#define VY_ASSETC_PROCESSING_H
 | 
					#define VY_ASSETC_PROCESSING_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime/file_tab.h"
 | 
					 | 
				
			||||||
#include "runtime/assets.h"
 | 
					#include "runtime/assets.h"
 | 
				
			||||||
 | 
					#include "runtime/file_tab.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum {
 | 
					enum {
 | 
				
			||||||
    VY_PROCESSING_FAILED = VY_SUCCESS + 1,
 | 
					    VY_PROCESSING_FAILED = VY_SUCCESS + 1,
 | 
				
			||||||
@ -10,22 +10,35 @@ enum {
 | 
				
			|||||||
    VY_PROCESSING_TRY_AGAIN,
 | 
					    VY_PROCESSING_TRY_AGAIN,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_file_id output_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} vy_asset_options;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    vy_uid asset_uid;
 | 
					    vy_uid asset_uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* Allocated via the vyAllocBuffer API */
 | 
				
			||||||
 | 
					    void *data;
 | 
				
			||||||
 | 
					    size_t size;
 | 
				
			||||||
} vy_processor_output;
 | 
					} vy_processor_output;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef vy_result vy_processor_fn(vy_file_id file, void *buffer, size_t size, vy_processor_output *output);
 | 
					typedef vy_result vy_processor_fn(vy_file_id file,
 | 
				
			||||||
 | 
					                                  void *buffer,
 | 
				
			||||||
 | 
					                                  size_t size,
 | 
				
			||||||
 | 
					                                  uint32_t flags,
 | 
				
			||||||
 | 
					                                  vy_processor_output *output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_result vyAddAssetProcessor(const char *file_extension, vy_processor_fn fn);
 | 
					vy_result vyAddAssetProcessor(const char *file_extension, vy_processor_fn fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_result vyAddFileToProcessingQueue(vy_file_id file);
 | 
					/* Flags are file type specific */
 | 
				
			||||||
 | 
					vy_result vyAddFileToProcessingQueue(vy_file_id file, uint32_t flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_result vyStartProcessing(void);
 | 
					vy_result vyStartProcessing(void);
 | 
				
			||||||
void vyStopProcessing(void);
 | 
					void vyStopProcessing(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_uid vyCalculateUID(const char *name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void vyInitUIDMap(void);
 | 
					void vyWaitUntilProcessingIsFinished(void);
 | 
				
			||||||
void vyAddUIDMapping(vy_file_id fid, vy_uid uid);
 | 
					 | 
				
			||||||
vy_uid vyLookupUID(vy_file_id fid);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								src/tools/assetc/processing_flags.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/tools/assetc/processing_flags.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					#ifndef VY_ASSETC_PROCESSING_FLAGS_H
 | 
				
			||||||
 | 
					#define VY_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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VY_SHADER_FLAG_TYPE_MASK =
 | 
				
			||||||
 | 
					        VY_SHADER_FLAG_VERTEX | VY_SHADER_FLAG_FRAGMENT | VY_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,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@ -1,17 +1,25 @@
 | 
				
			|||||||
#include "processing.h"
 | 
					#include "processing.h"
 | 
				
			||||||
#include "utils.h"
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					#include "description_parser.h"
 | 
				
			||||||
 | 
					#include "packages.h"
 | 
				
			||||||
 | 
					#include "assetmeta.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "runtime/file_tab.h"
 | 
					 | 
				
			||||||
#include "runtime/threading.h"
 | 
					 | 
				
			||||||
#include "runtime/aio.h"
 | 
					#include "runtime/aio.h"
 | 
				
			||||||
#include "runtime/buffer_manager.h"
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
 | 
					#include "runtime/file_tab.h"
 | 
				
			||||||
 | 
					#include "runtime/threading.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <assert.h>
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef struct {
 | 
					typedef struct {
 | 
				
			||||||
    vy_file_id fid;
 | 
					    vy_file_id fid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* How many times has this file been added? */
 | 
					    /* How many times has this file been added? */
 | 
				
			||||||
    unsigned int turn;
 | 
					    unsigned int turn;
 | 
				
			||||||
} vy_file_processing_queue_entry;
 | 
					} vy_file_processing_queue_entry;
 | 
				
			||||||
@ -23,40 +31,94 @@ typedef struct {
 | 
				
			|||||||
    unsigned int tail;
 | 
					    unsigned int tail;
 | 
				
			||||||
} vy_file_processing_queue;
 | 
					} vy_file_processing_queue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_file_processing_queue _processing_queue;
 | 
					static vy_file_processing_queue _queues[2];
 | 
				
			||||||
 | 
					static vy_file_processing_queue *_processing_queue;
 | 
				
			||||||
 | 
					static vy_file_processing_queue *_retry_queue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_mutex *_guard;
 | 
					static vy_mutex *_guard;
 | 
				
			||||||
static bool _keep_running;
 | 
					static bool _keep_running;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* A single file could have a lot of dependencies. */
 | 
				
			||||||
 | 
					#define MAX_TURNS 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static vy_result vyAddFileToProcessingQueueImpl(vy_file_id file, unsigned int turn) {
 | 
					#define MAX_PROCESSING_THREADS 16
 | 
				
			||||||
    if (!_guard)
 | 
					 | 
				
			||||||
        _guard = vyCreateMutex();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define FORCE_SINGLE_THREAD 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int _num_processing_threads = 0;
 | 
				
			||||||
 | 
					static vy_thread *_processing_threads[MAX_PROCESSING_THREADS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned int _processing_thread_count = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    unsigned int package;
 | 
				
			||||||
 | 
					} vy_asset_settings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_result ParseAssetSettings(const char *text,
 | 
				
			||||||
 | 
					                                    size_t length,
 | 
				
			||||||
 | 
					                                    const char *file_path,
 | 
				
			||||||
 | 
					                                    vy_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);
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    settings->package = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const vy_parsed_stmt *package_stmt = vyFindStatement(&state, root_list, "package");
 | 
				
			||||||
 | 
					    if (package_stmt) {
 | 
				
			||||||
 | 
					        if (package_stmt->form != VY_STMT_FORM_VALUE) {
 | 
				
			||||||
 | 
					            vyReportError("ASSETC",
 | 
				
			||||||
 | 
					                          "Expected a package name as the value of 'package' in %s.",
 | 
				
			||||||
 | 
					                          file_path);
 | 
				
			||||||
 | 
					            res = VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					            goto out;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        settings->package = vyAddPackageFile(package_stmt->value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
 | 
					    vyReleaseParseState(&state);
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static vy_result vyAddFileToProcessingQueueImpl(vy_file_processing_queue *queue,
 | 
				
			||||||
 | 
					                                                vy_file_id file,
 | 
				
			||||||
 | 
					                                                uint32_t flags,
 | 
				
			||||||
 | 
					                                                unsigned int turn) {
 | 
				
			||||||
    vy_result result = VY_SUCCESS;
 | 
					    vy_result result = VY_SUCCESS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vyLog("ASSETC", "Adding %s to processing queue.", vyGetFilePath(file));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    vy_file_processing_queue_entry entry = {
 | 
					    vy_file_processing_queue_entry entry = {
 | 
				
			||||||
        .fid  = file,
 | 
					        .fid           = file,
 | 
				
			||||||
        .turn = turn,
 | 
					        .flags         = flags,
 | 
				
			||||||
 | 
					        .turn          = turn,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    vyLockMutex(_guard);
 | 
					    if ((queue->head + 1) % QUEUE_LENGTH != queue->tail) {
 | 
				
			||||||
    if ((_processing_queue.tail + 1) % QUEUE_LENGTH != _processing_queue.head) {
 | 
					        unsigned int slot                = queue->head;
 | 
				
			||||||
        unsigned int slot               = _processing_queue.head;
 | 
					        queue->entries[slot]    = entry;
 | 
				
			||||||
        _processing_queue.entries[slot] = entry;
 | 
					        queue->head                      = (queue->head + 1) % QUEUE_LENGTH;
 | 
				
			||||||
        _processing_queue.head = (_processing_queue.head + 1) % QUEUE_LENGTH;
 | 
					 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        vyReportError("ASSETC", "The processing queue is full!");
 | 
					        vyReportError("ASSETC", "The processing queue is full!");
 | 
				
			||||||
        result = 1;
 | 
					        result = 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vyUnlockMutex(_guard);
 | 
					 | 
				
			||||||
    return result;
 | 
					    return result;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyAddFileToProcessingQueue(vy_file_id file, uint32_t flags) {
 | 
				
			||||||
 | 
					    assert(_guard != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
vy_result vyAddFileToProcessingQueue(vy_file_id file) {
 | 
					    vyLockMutex(_guard);
 | 
				
			||||||
    return vyAddFileToProcessingQueueImpl(file, 1);
 | 
					    vy_result res = vyAddFileToProcessingQueueImpl(_processing_queue, file, flags, 1);
 | 
				
			||||||
 | 
					    vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MAX_PROCESSORS 256
 | 
					#define MAX_PROCESSORS 256
 | 
				
			||||||
static vy_processor_fn *_processor_fns[MAX_PROCESSORS];
 | 
					static vy_processor_fn *_processor_fns[MAX_PROCESSORS];
 | 
				
			||||||
static const char *_processor_exts[MAX_PROCESSORS];
 | 
					static const char *_processor_exts[MAX_PROCESSORS];
 | 
				
			||||||
@ -68,7 +130,7 @@ vy_result vyAddAssetProcessor(const char *file_extension, vy_processor_fn fn) {
 | 
				
			|||||||
        vyReportError("ASSETC", "Too many asset processor functions!");
 | 
					        vyReportError("ASSETC", "Too many asset processor functions!");
 | 
				
			||||||
        return 1;
 | 
					        return 1;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    _processor_fns[_processor_count] = fn;
 | 
					    _processor_fns[_processor_count]  = fn;
 | 
				
			||||||
    _processor_exts[_processor_count] = file_extension;
 | 
					    _processor_exts[_processor_count] = file_extension;
 | 
				
			||||||
    ++_processor_count;
 | 
					    ++_processor_count;
 | 
				
			||||||
    return VY_SUCCESS;
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
@ -89,10 +151,10 @@ static void PopAndSwapSubmittedData(unsigned int at,
 | 
				
			|||||||
    *count = *count - 1;
 | 
					    *count = *count - 1;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ProcessLoadedFile(vy_file_processing_queue_entry entry, void *buffer, size_t size) {
 | 
					static vy_result ProcessLoadedFile(vy_file_processing_queue_entry entry, void *buffer, size_t size) {
 | 
				
			||||||
    /* Search for a matching processor function */
 | 
					    /* Search for a matching processor function */
 | 
				
			||||||
    const char *path = vyGetFilePath(entry.fid);
 | 
					    const char *path = vyGetFilePath(entry.fid);
 | 
				
			||||||
    size_t path_len = strlen(path);
 | 
					    size_t path_len  = strlen(path);
 | 
				
			||||||
    for (unsigned int i = 0; i < _processor_count; ++i) {
 | 
					    for (unsigned int i = 0; i < _processor_count; ++i) {
 | 
				
			||||||
        size_t ext_len = strlen(_processor_exts[i]);
 | 
					        size_t ext_len = strlen(_processor_exts[i]);
 | 
				
			||||||
        if (ext_len > path_len)
 | 
					        if (ext_len > path_len)
 | 
				
			||||||
@ -100,30 +162,102 @@ static void ProcessLoadedFile(vy_file_processing_queue_entry entry, void *buffer
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const char *path_end = &path[path_len - ext_len];
 | 
					        const char *path_end = &path[path_len - ext_len];
 | 
				
			||||||
        if (memcmp(path_end, _processor_exts[i], ext_len) == 0) {
 | 
					        if (memcmp(path_end, _processor_exts[i], ext_len) == 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Load the corresponding .as file.
 | 
				
			||||||
 | 
					             * TODO: Using malloc here is probably relatively slow.
 | 
				
			||||||
 | 
					             */
 | 
				
			||||||
 | 
					            vy_asset_settings settings;
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                char *as_path = malloc(path_len + 3);
 | 
				
			||||||
 | 
					                if (!as_path) {
 | 
				
			||||||
 | 
					                    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                memcpy(as_path, path, path_len);
 | 
				
			||||||
 | 
					                strcpy(&as_path[path_len - ext_len], ".as");
 | 
				
			||||||
 | 
					                size_t as_size = vyGetFileSize(as_path);
 | 
				
			||||||
 | 
					                if (as_size == 0) {
 | 
				
			||||||
 | 
					                    vyReportError("ASSETC", "Failed to retrieve size of setting file %s", as_path);
 | 
				
			||||||
 | 
					                    free(as_path);
 | 
				
			||||||
 | 
					                    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                void *as_buffer = vyAllocBuffer(as_size);
 | 
				
			||||||
 | 
					                
 | 
				
			||||||
 | 
					                vy_load_batch as_load;
 | 
				
			||||||
 | 
					                as_load.loads[0].file = vyAddFile(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);
 | 
				
			||||||
 | 
					                    free(as_path);
 | 
				
			||||||
 | 
					                    return VY_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);
 | 
				
			||||||
 | 
					                    free(as_path);
 | 
				
			||||||
 | 
					                    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (vyWaitForAIOCompletion(as_handle) != VY_AIO_STATE_FINISHED) {
 | 
				
			||||||
 | 
					                    vyReportError("ASSETC", "Failed to load setting file %s", as_path);
 | 
				
			||||||
 | 
					                    free(as_path);
 | 
				
			||||||
 | 
					                    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                vyReleaseAIO(as_handle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (ParseAssetSettings(as_buffer, as_size, as_path, &settings) != VY_SUCCESS) {
 | 
				
			||||||
 | 
					                    free(as_path);
 | 
				
			||||||
 | 
					                    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                free(as_path);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Process the asset */
 | 
				
			||||||
            vy_processor_output out;
 | 
					            vy_processor_output out;
 | 
				
			||||||
            vy_result res = _processor_fns[i](entry.fid, buffer, size, &out);
 | 
					            vy_result res = _processor_fns[i](entry.fid, buffer, size, entry.flags, &out);
 | 
				
			||||||
            if (res == VY_PROCESSING_FAILED) {
 | 
					            if (res == VY_SUCCESS) {
 | 
				
			||||||
                vyLog("ASSETC", "Failed to process file: %s", path);
 | 
					                /* Add the output to the appropriate package file */
 | 
				
			||||||
 | 
					                vy_assetmeta meta;
 | 
				
			||||||
 | 
					                meta.compiled_ts  = vyGetCurrentTimestamp();
 | 
				
			||||||
 | 
					                meta.last_changed = vyGetFileModificationTimestamp(entry.fid);
 | 
				
			||||||
 | 
					                vyAddUIDMapping(entry.fid, out.asset_uid, &meta);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                vyAddAssetToPackage(settings.package, out.asset_uid, out.data, out.size);
 | 
				
			||||||
            } else if (res == VY_PROCESSING_TRY_AGAIN) {
 | 
					            } else if (res == VY_PROCESSING_TRY_AGAIN) {
 | 
				
			||||||
                if (entry.turn < 2) {
 | 
					                if (entry.turn < MAX_TURNS) {
 | 
				
			||||||
                    vyAddFileToProcessingQueueImpl(entry.fid, entry.turn + 1);
 | 
					                    vyLockMutex(_guard);
 | 
				
			||||||
 | 
					                    vyAddFileToProcessingQueueImpl(_retry_queue, entry.fid, entry.flags, entry.turn + 1);
 | 
				
			||||||
 | 
					                    vyUnlockMutex(_guard);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    vyLog("ASSETC",
 | 
					                    vyLog("ASSETC",
 | 
				
			||||||
                          "File '%s' took too many turns to process: %u",
 | 
					                          "File '%s' took too many turns to process: %u",
 | 
				
			||||||
                          path,
 | 
					                          path,
 | 
				
			||||||
                          entry.turn);
 | 
					                          entry.turn);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                vyLog("ASSETC", "Failed to process file: %s  (Result %u)", path, res);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return;
 | 
					            return res;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    vyLog("ASSETC", "No asset processor for file: %s", path);
 | 
					    vyLog("ASSETC", "No asset processor for file: %s", path);
 | 
				
			||||||
 | 
					    return VY_UNKNOWN_ERROR;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void ProcessingThread(void *_param) {
 | 
					static void ProcessingThread(void *_param) {
 | 
				
			||||||
    VY_UNUSED(_param);
 | 
					    VY_UNUSED(_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    vy_file_processing_queue_entry submitted_entries[VY_LOAD_BATCH_MAX_SIZE];
 | 
					    vy_file_processing_queue_entry submitted_entries[VY_LOAD_BATCH_MAX_SIZE];
 | 
				
			||||||
    vy_aio_handle submitted_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
					    vy_aio_handle submitted_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
				
			||||||
    void *submitted_buffers[VY_LOAD_BATCH_MAX_SIZE];
 | 
					    void *submitted_buffers[VY_LOAD_BATCH_MAX_SIZE];
 | 
				
			||||||
@ -140,16 +274,23 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
        bool got_entry = false;
 | 
					        bool got_entry = false;
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
            got_entry = false;
 | 
					            got_entry = false;
 | 
				
			||||||
            vy_file_processing_queue_entry entry;
 | 
					            vy_file_processing_queue_entry entry = {0};
 | 
				
			||||||
            vyLockMutex(_guard);
 | 
					            vyLockMutex(_guard);
 | 
				
			||||||
            if (_processing_queue.head != _processing_queue.tail) {
 | 
					            if (_processing_queue->head != _processing_queue->tail) {
 | 
				
			||||||
                unsigned int next = _processing_queue.tail;
 | 
					                entry                  = _processing_queue->entries[_processing_queue->tail];
 | 
				
			||||||
                entry             = _processing_queue.entries[next];
 | 
					                _processing_queue->tail = (_processing_queue->tail + 1) % QUEUE_LENGTH;
 | 
				
			||||||
                _processing_queue.tail =
 | 
					                got_entry              = true;
 | 
				
			||||||
                    (_processing_queue.tail + 1) % QUEUE_LENGTH;
 | 
					            } else if (load_batch.num_loads == 0) {
 | 
				
			||||||
                got_entry = true;
 | 
					                /* Switch the queues -> Retry all the entries that returned VY_PROCESSING_TRY_AGAIN */
 | 
				
			||||||
 | 
					                if (_retry_queue->head != _retry_queue->tail) {
 | 
				
			||||||
 | 
					                    vy_file_processing_queue *tmp = _retry_queue;
 | 
				
			||||||
 | 
					                    _retry_queue                  = _processing_queue;
 | 
				
			||||||
 | 
					                    _processing_queue             = tmp;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            vyUnlockMutex(_guard);
 | 
					            vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
 | 
					            /* Retry, if we did not get an entry */
 | 
				
			||||||
            if (!got_entry)
 | 
					            if (!got_entry)
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -159,14 +300,15 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            vyLog("ASSETC", "Processing %s", path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            size_t fsz = vyGetFileSize(path);
 | 
					            size_t fsz = vyGetFileSize(path);
 | 
				
			||||||
            void *dest = vyAllocBuffer(fsz);
 | 
					            void *dest = vyAllocBuffer(fsz);
 | 
				
			||||||
            if (!dest) {
 | 
					            if (!dest) {
 | 
				
			||||||
                vyLog("ASSETC",
 | 
					                vyLog("ASSETC", "Ran out of memory for loading the file: %s", path);
 | 
				
			||||||
                      "Ran out of memory for loading the file: %s",
 | 
					 | 
				
			||||||
                      path);
 | 
					 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            memset(dest, 0, fsz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            load_sizes[load_batch.num_loads]                 = fsz;
 | 
					            load_sizes[load_batch.num_loads]                 = fsz;
 | 
				
			||||||
            load_buffers[load_batch.num_loads]               = dest;
 | 
					            load_buffers[load_batch.num_loads]               = dest;
 | 
				
			||||||
@ -176,22 +318,23 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
            load_batch.loads[load_batch.num_loads].offset    = 0;
 | 
					            load_batch.loads[load_batch.num_loads].offset    = 0;
 | 
				
			||||||
            load_entries[load_batch.num_loads]               = entry;
 | 
					            load_entries[load_batch.num_loads]               = entry;
 | 
				
			||||||
            ++load_batch.num_loads;
 | 
					            ++load_batch.num_loads;
 | 
				
			||||||
        }
 | 
					        } while (got_entry && load_batch.num_loads < VY_LOAD_BATCH_MAX_SIZE);
 | 
				
			||||||
        while (got_entry && load_batch.num_loads < VY_LOAD_BATCH_MAX_SIZE);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        vy_aio_handle load_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
					        vy_aio_handle load_handles[VY_LOAD_BATCH_MAX_SIZE];
 | 
				
			||||||
        if (load_batch.num_loads > 0) {
 | 
					        if (load_batch.num_loads > 0) {
 | 
				
			||||||
            vy_result submit_result =
 | 
					            vy_result submit_result = vySubmitLoadBatch(&load_batch, load_handles);
 | 
				
			||||||
                vySubmitLoadBatch(&load_batch, load_handles);
 | 
					 | 
				
			||||||
            if (submit_result != VY_SUCCESS) {
 | 
					            if (submit_result != VY_SUCCESS) {
 | 
				
			||||||
                vyLog("ASSETC", "SubmitLoadBatch failed: %u", submit_result);
 | 
					                vyLog("ASSETC", "SubmitLoadBatch failed: %u", submit_result);
 | 
				
			||||||
                continue;
 | 
					                continue;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
        /* Process the previously submitted loads */
 | 
					        /* Process the previously submitted loads */
 | 
				
			||||||
        while (submitted_outstanding > 0) {
 | 
					        while (submitted_outstanding > 0) {
 | 
				
			||||||
 | 
					            vyLockMutex(_guard);
 | 
				
			||||||
 | 
					            _processing_thread_count += 1;
 | 
				
			||||||
 | 
					            vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (unsigned int i = 0; i < submitted_outstanding; ++i) {
 | 
					            for (unsigned int i = 0; i < submitted_outstanding; ++i) {
 | 
				
			||||||
                vy_aio_state state = vyGetAIOState(submitted_handles[i]);
 | 
					                vy_aio_state state = vyGetAIOState(submitted_handles[i]);
 | 
				
			||||||
                switch (state) {
 | 
					                switch (state) {
 | 
				
			||||||
@ -201,6 +344,7 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
                    vyLog("ASSETC",
 | 
					                    vyLog("ASSETC",
 | 
				
			||||||
                          "Loading file %s failed.",
 | 
					                          "Loading file %s failed.",
 | 
				
			||||||
                          vyGetFilePath(submitted_entries[i].fid));
 | 
					                          vyGetFilePath(submitted_entries[i].fid));
 | 
				
			||||||
 | 
					                    vyReleaseAIO(submitted_handles[i]);
 | 
				
			||||||
                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
					                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
				
			||||||
                    PopAndSwapSubmittedData(i,
 | 
					                    PopAndSwapSubmittedData(i,
 | 
				
			||||||
                                            &submitted_outstanding,
 | 
					                                            &submitted_outstanding,
 | 
				
			||||||
@ -227,6 +371,7 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
                    ProcessLoadedFile(submitted_entries[i],
 | 
					                    ProcessLoadedFile(submitted_entries[i],
 | 
				
			||||||
                                      submitted_buffers[i],
 | 
					                                      submitted_buffers[i],
 | 
				
			||||||
                                      submitted_sizes[i]);
 | 
					                                      submitted_sizes[i]);
 | 
				
			||||||
 | 
					                    vyReleaseAIO(submitted_handles[i]);
 | 
				
			||||||
                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
					                    vyReleaseBuffer(submitted_buffers[i], submitted_sizes[i]);
 | 
				
			||||||
                    PopAndSwapSubmittedData(i,
 | 
					                    PopAndSwapSubmittedData(i,
 | 
				
			||||||
                                            &submitted_outstanding,
 | 
					                                            &submitted_outstanding,
 | 
				
			||||||
@ -237,6 +382,10 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
                    --i;
 | 
					                    --i;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            vyLockMutex(_guard);
 | 
				
			||||||
 | 
					            _processing_thread_count -= 1;
 | 
				
			||||||
 | 
					            vyUnlockMutex(_guard);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /* Start new round */
 | 
					        /* Start new round */
 | 
				
			||||||
@ -252,17 +401,24 @@ static void ProcessingThread(void *_param) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NUM_PROCESSING_THREADS 8
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vy_thread *_processing_threads[NUM_PROCESSING_THREADS];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vy_result vyStartProcessing(void) {
 | 
					vy_result vyStartProcessing(void) {
 | 
				
			||||||
    if (!_guard)
 | 
					    if (!_guard)
 | 
				
			||||||
        _guard = vyCreateMutex();
 | 
					        _guard = vyCreateMutex();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _keep_running = true;
 | 
					#if !FORCE_SINGLE_THREAD
 | 
				
			||||||
    for (unsigned int i = 0; i < NUM_PROCESSING_THREADS; ++i) {
 | 
					    _num_processing_threads     = vyGetCPUCoreCount();
 | 
				
			||||||
        _processing_threads[i] = vySpawnThread(ProcessingThread, NULL);
 | 
					    if (_num_processing_threads > MAX_PROCESSING_THREADS)
 | 
				
			||||||
 | 
					        _num_processing_threads = MAX_PROCESSING_THREADS;
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    _num_processing_threads = 1;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _processing_queue = &_queues[0];
 | 
				
			||||||
 | 
					    _retry_queue      = &_queues[1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _keep_running               = true;
 | 
				
			||||||
 | 
					    for (unsigned int i = 0; i < _num_processing_threads; ++i) {
 | 
				
			||||||
 | 
					        _processing_threads[i] = vySpawnThread(ProcessingThread, NULL, "Processor");
 | 
				
			||||||
        if (!_processing_threads[i]) {
 | 
					        if (!_processing_threads[i]) {
 | 
				
			||||||
            vyReportError("ASSETC", "Failed to spawn processing thread %u!", i);
 | 
					            vyReportError("ASSETC", "Failed to spawn processing thread %u!", i);
 | 
				
			||||||
            _keep_running = false;
 | 
					            _keep_running = false;
 | 
				
			||||||
@ -274,6 +430,35 @@ vy_result vyStartProcessing(void) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void vyStopProcessing(void) {
 | 
					void vyStopProcessing(void) {
 | 
				
			||||||
    _keep_running = false;
 | 
					    _keep_running = false;
 | 
				
			||||||
    for (unsigned int i = 0; i < NUM_PROCESSING_THREADS; ++i)
 | 
					    for (unsigned int i = 0; i < _num_processing_threads; ++i)
 | 
				
			||||||
        vyJoinThread(_processing_threads[i]);
 | 
					        vyJoinThread(_processing_threads[i]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vyWaitUntilProcessingIsFinished(void) {
 | 
				
			||||||
 | 
					    unsigned int done_counter = 0;
 | 
				
			||||||
 | 
					    while (done_counter < 3) {
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					        Sleep(1000);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					        sleep(1);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					        vyLockMutex(_guard);
 | 
				
			||||||
 | 
					        volatile bool done = _processing_queue->head == _processing_queue->tail &&
 | 
				
			||||||
 | 
					                             _retry_queue->head == _retry_queue->tail &&
 | 
				
			||||||
 | 
					                             _processing_thread_count == 0;
 | 
				
			||||||
 | 
					        vyUnlockMutex(_guard);
 | 
				
			||||||
 | 
					        if (done)
 | 
				
			||||||
 | 
					            ++done_counter;
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            done_counter = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,16 +1,122 @@
 | 
				
			|||||||
 | 
					#include "assetmeta.h"
 | 
				
			||||||
#include "processing.h"
 | 
					#include "processing.h"
 | 
				
			||||||
 | 
					#include "processing_flags.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern vy_result vyProcessShaderFile(vy_file_id file,
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
                                     void *buffer,
 | 
					
 | 
				
			||||||
                                     size_t size,
 | 
					#include <shaderc/shaderc.h>
 | 
				
			||||||
                                     vy_processor_output *output) {
 | 
					#include <string.h>
 | 
				
			||||||
    /* Scan the first line for the shader type */
 | 
					
 | 
				
			||||||
    char *text = buffer;
 | 
					static shaderc_include_result *ResolveInclude(void *user_data,
 | 
				
			||||||
    for (size_t i = 0; i < size; ++i) {
 | 
					                                              const char *requested_source,
 | 
				
			||||||
        if (text[i] == '\n' || text[i] == '\r') {
 | 
					                                              int type,
 | 
				
			||||||
            vyLog("ASSETC", "First Line");
 | 
					                                              const char *requesting_source,
 | 
				
			||||||
        }
 | 
					                                              size_t include_depth) {
 | 
				
			||||||
 | 
					    shaderc_include_result *result = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return result;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void ReleaseIncludeResult(void *user_data, shaderc_include_result *result) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_result vyProcessShaderFile(vy_file_id file,
 | 
				
			||||||
 | 
					                              void *buffer,
 | 
				
			||||||
 | 
					                              size_t size,
 | 
				
			||||||
 | 
					                              uint32_t flags,
 | 
				
			||||||
 | 
					                              vy_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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char *path = vyGetFilePath(file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shaderc_compile_options_t options = shaderc_compile_options_initialize();
 | 
				
			||||||
 | 
					    if (!options) {
 | 
				
			||||||
 | 
					        vyLog("ASSETC", "Failed to initialize shader compile options.");
 | 
				
			||||||
 | 
					        shaderc_compiler_release(compiler);
 | 
				
			||||||
 | 
					        return VY_PROCESSING_FAILED;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shaderc_compile_options_set_include_callbacks(options,
 | 
				
			||||||
 | 
					                                                  ResolveInclude,
 | 
				
			||||||
 | 
					                                                  ReleaseIncludeResult,
 | 
				
			||||||
 | 
					                                                  NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t optimize_from_flags = flags & VY_SHADER_FLAG_OPTIMIZE_MASK;
 | 
				
			||||||
 | 
					    if (optimize_from_flags == VY_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)
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					    shaderc_shader_kind shaderc_kind;
 | 
				
			||||||
 | 
					    switch (type_from_flags) {
 | 
				
			||||||
 | 
					    case VY_SHADER_FLAG_VERTEX:
 | 
				
			||||||
 | 
					        shaderc_kind = shaderc_glsl_vertex_shader;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VY_SHADER_FLAG_FRAGMENT:
 | 
				
			||||||
 | 
					        shaderc_kind = shaderc_glsl_fragment_shader;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    case VY_SHADER_FLAG_COMPUTE:
 | 
				
			||||||
 | 
					        shaderc_kind = shaderc_glsl_compute_shader;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					    default:
 | 
				
			||||||
 | 
					        vyLog("ASSETC", "Invalid shader stage flag %u", type_from_flags);
 | 
				
			||||||
 | 
					        shaderc_compile_options_release(options);
 | 
				
			||||||
 | 
					        shaderc_compiler_release(compiler);
 | 
				
			||||||
 | 
					        return VY_PROCESSING_FAILED;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shaderc_compilation_result_t result = shaderc_compile_into_spv(compiler,
 | 
				
			||||||
 | 
					                                                                   (const char *)buffer,
 | 
				
			||||||
 | 
					                                                                   size,
 | 
				
			||||||
 | 
					                                                                   shaderc_kind,
 | 
				
			||||||
 | 
					                                                                   path,
 | 
				
			||||||
 | 
					                                                                   "main",
 | 
				
			||||||
 | 
					                                                                   options);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    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",
 | 
				
			||||||
 | 
					              "Compilation of %s failed: %s",
 | 
				
			||||||
 | 
					              path,
 | 
				
			||||||
 | 
					              shaderc_result_get_error_message(result));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        shaderc_result_release(result);
 | 
				
			||||||
 | 
					        shaderc_compile_options_release(options);
 | 
				
			||||||
 | 
					        shaderc_compiler_release(compiler);
 | 
				
			||||||
 | 
					        return VY_PROCESSING_FAILED;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t output_size = shaderc_result_get_length(result);
 | 
				
			||||||
 | 
					    output->data       = vyAllocBuffer(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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const uint32_t *spv_bytes = (uint32_t *)shaderc_result_get_bytes(result);
 | 
				
			||||||
 | 
					    memcpy(output->data, spv_bytes, output_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shaderc_result_release(result);
 | 
				
			||||||
 | 
					    shaderc_compile_options_release(options);
 | 
				
			||||||
 | 
					    shaderc_compiler_release(compiler);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    output->asset_uid = vyCalculateUID(path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return VY_SUCCESS;
 | 
					    return VY_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,57 +0,0 @@
 | 
				
			|||||||
#include "processing.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "runtime/threading.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define MAP_SIZE 2048
 | 
					 | 
				
			||||||
typedef struct {
 | 
					 | 
				
			||||||
    vy_file_id fids[MAP_SIZE];
 | 
					 | 
				
			||||||
    vy_uid uids[MAP_SIZE];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    unsigned int used_slots;
 | 
					 | 
				
			||||||
} vy_uid_map;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static vy_uid_map _map;
 | 
					 | 
				
			||||||
static vy_mutex *_guard;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void vyInitUIDMap(void) {
 | 
					 | 
				
			||||||
    _guard = vyCreateMutex();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
vy_uid vyLookupUID(vy_file_id fid) {
 | 
					 | 
				
			||||||
    vyLockMutex(_guard);
 | 
					 | 
				
			||||||
    unsigned int i = 0;
 | 
					 | 
				
			||||||
    vy_uid result  = VY_INVALID_UID;
 | 
					 | 
				
			||||||
    while (i < MAP_SIZE) {
 | 
					 | 
				
			||||||
        unsigned int slot = (fid + i) % MAP_SIZE;
 | 
					 | 
				
			||||||
        if (_map.fids[slot] == fid) {
 | 
					 | 
				
			||||||
            _map.fids[slot] = fid;
 | 
					 | 
				
			||||||
            result          = _map.uids[slot];
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        } else if (_map.fids[slot] == VY_INVALID_FILE_ID) {
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    vyUnlockMutex(_guard);
 | 
					 | 
				
			||||||
    return result;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void vyAddUIDMapping(vy_file_id fid, vy_uid uid) {
 | 
					 | 
				
			||||||
    vyLockMutex(_guard);
 | 
					 | 
				
			||||||
    float fill_rate = (float)_map.used_slots / MAP_SIZE;
 | 
					 | 
				
			||||||
    if (fill_rate >= .5f) {
 | 
					 | 
				
			||||||
        vyLog("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] == 0) {
 | 
					 | 
				
			||||||
            _map.fids[slot] = fid;
 | 
					 | 
				
			||||||
            _map.uids[slot] = uid;
 | 
					 | 
				
			||||||
            break;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    if (i == MAP_SIZE) {
 | 
					 | 
				
			||||||
        vyReportError("ASSETC", "Failed to insert entry into UID map.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    vyUnlockMutex(_guard);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										32
									
								
								src/tools/assetc/uidtable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/tools/assetc/uidtable.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					#include "processing.h"
 | 
				
			||||||
 | 
					#include "utils.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/threading.h"
 | 
				
			||||||
 | 
					#include "runtime/aio.h"
 | 
				
			||||||
 | 
					#include "runtime/buffer_manager.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <xxhash/xxhash.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <assert.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					#define WIN32_LEAN_AND_MEAN
 | 
				
			||||||
 | 
					#include <Windows.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma pack(push, 1)
 | 
				
			||||||
 | 
					typedef struct {
 | 
				
			||||||
 | 
					    vy_file_id file;
 | 
				
			||||||
 | 
					    uint64_t offset;
 | 
				
			||||||
 | 
					    uint64_t size;
 | 
				
			||||||
 | 
					    uint64_t last_changed;
 | 
				
			||||||
 | 
					} vy_uidtab_entry;
 | 
				
			||||||
 | 
					#pragma pack(pop)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					vy_uid vyCalculateUID(const char *name) {
 | 
				
			||||||
 | 
					    assert(sizeof(XXH32_hash_t) == sizeof(vy_uid));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t len = strlen(name);
 | 
				
			||||||
 | 
					    return (vy_uid)XXH32(name, len, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -5,19 +5,49 @@
 | 
				
			|||||||
#include <Windows.h>
 | 
					#include <Windows.h>
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
size_t vyGetFileSize(const char *path) {
 | 
					size_t vyGetFileSize(const char *path) {
 | 
				
			||||||
#ifdef _WIN32
 | 
					#ifdef _WIN32
 | 
				
			||||||
    WCHAR wpath[MAX_PATH];
 | 
					    WCHAR wpath[MAX_PATH];
 | 
				
			||||||
    MultiByteToWideChar(CP_UTF8,
 | 
					    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
 | 
				
			||||||
                        MB_PRECOMPOSED,
 | 
					 | 
				
			||||||
                        path,
 | 
					 | 
				
			||||||
                        -1,
 | 
					 | 
				
			||||||
                        wpath,
 | 
					 | 
				
			||||||
                        MAX_PATH);
 | 
					 | 
				
			||||||
    WIN32_FILE_ATTRIBUTE_DATA attribs;
 | 
					    WIN32_FILE_ATTRIBUTE_DATA attribs;
 | 
				
			||||||
    if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &attribs))
 | 
					    if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &attribs))
 | 
				
			||||||
        return 0;
 | 
					        return 0;
 | 
				
			||||||
    return (size_t)attribs.nFileSizeHigh << 32 | (size_t)attribs.nFileSizeLow;
 | 
					    return (size_t)attribs.nFileSizeHigh << 32 | (size_t)attribs.nFileSizeLow;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vySetWorkingDirectory(const char *path) {
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					    WCHAR wpath[MAX_PATH];
 | 
				
			||||||
 | 
					    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
 | 
				
			||||||
 | 
					    SetCurrentDirectoryW(wpath);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t vyGetCurrentTimestamp(void) {
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					    FILETIME ft;
 | 
				
			||||||
 | 
					    GetSystemTimeAsFileTime(&ft);
 | 
				
			||||||
 | 
					    uint64_t ts = ft.dwLowDateTime;
 | 
				
			||||||
 | 
					    ts |= (uint64_t)ft.dwHighDateTime << 32;
 | 
				
			||||||
 | 
					    return ts;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t vyGetFileModificationTimestamp(vy_file_id fid) {
 | 
				
			||||||
 | 
					#ifdef _WIN32
 | 
				
			||||||
 | 
					    const char *path = vyGetFilePath(fid);
 | 
				
			||||||
 | 
					    if (!path) {
 | 
				
			||||||
 | 
					        vyLog("ASSETC", "Tried to get modification timestamp of unknown file.");
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    WCHAR wpath[MAX_PATH];
 | 
				
			||||||
 | 
					    MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, path, -1, wpath, MAX_PATH);
 | 
				
			||||||
 | 
					    WIN32_FILE_ATTRIBUTE_DATA attribs;
 | 
				
			||||||
 | 
					    if (!GetFileAttributesExW(wpath, GetFileExInfoStandard, &attribs))
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					    uint64_t ts = attribs.ftLastWriteTime.dwLowDateTime;
 | 
				
			||||||
 | 
					    ts |= (uint64_t)attribs.ftLastWriteTime.dwHighDateTime << 32;
 | 
				
			||||||
 | 
					    return ts;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,6 +1,16 @@
 | 
				
			|||||||
#ifndef VY_ASSETC_UTILS_H
 | 
					#ifndef VY_ASSETC_UTILS_H
 | 
				
			||||||
#define VY_ASSETC_UTILS_H
 | 
					#define VY_ASSETC_UTILS_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "runtime/file_tab.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
size_t vyGetFileSize(const char *path);
 | 
					size_t vyGetFileSize(const char *path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void vySetWorkingDirectory(const char *path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t vyGetCurrentTimestamp(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint64_t vyGetFileModificationTimestamp(vy_file_id fid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user