summaryrefslogtreecommitdiff
path: root/reduced_system_layer.c
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-02-09 07:16:49 +0100
committerMitya Selivanov <automainint@guattari.tech>2025-02-09 07:16:49 +0100
commitb7b092a08dd3a61abcd7f9daabfc21fd3a392fa9 (patch)
tree6aac5e00d5c7c2bd60df11e2ea63a03a8c45c598 /reduced_system_layer.c
parent27b4343c2a7e2583881485a5ac667894fec729f0 (diff)
downloadreduced_system_layer-b7b092a08dd3a61abcd7f9daabfc21fd3a392fa9.zip
Naming; blake2b hash; allocator
Diffstat (limited to 'reduced_system_layer.c')
-rwxr-xr-x[-rw-r--r--]reduced_system_layer.c919
1 files changed, 748 insertions, 171 deletions
diff --git a/reduced_system_layer.c b/reduced_system_layer.c
index fff4f44..847edae 100644..100755
--- a/reduced_system_layer.c
+++ b/reduced_system_layer.c
@@ -1,149 +1,176 @@
-// ================================================================
-//
-// reduced_system_layer.c
-//
-// This is a reduced system layer.
-// It allows you to create a window, draw graphics in it, handle
-// input events, write samples to audio output, send and receive
-// UDP packets, etc. All code is single-threaded.
-//
-// Primary target platforms: Linux (X11), Windows, Web.
-//
-// ----------------------------------------------------------------
-//
-// DESIGN PRINCIPLES
-//
-// - Minimalistic feature set. For graphics, you have access to the
-// pixel buffer, and that's it.
-//
-// - No implicit control flow. No callbacks. You write your own
-// main and call everything explicitly. But the number of things
-// you have to call to do something is as little as possible.
-//
-// - Optimized to use in a single source file.
-// Installation process? Ctrl+C, Ctrl+V, done.
-//
-// STYLE CONVENTIONS
-//
-// - Capitalized_Snake_Case - Type name.
-// - snake_case - Non-type name.
-// - UPPER_SNAKE_CASE - Macro or constant.
-// - g_ prefix - Global variable name.
-//
-// Most procedures have long and descriptive names.
-// Some procedures have prefixes according to their domain.
-//
-// There may be exceptions if convenient.
-//
-// ----------------------------------------------------------------
-//
-// To-Do list
-//
-// - Work in progress
-// - Clipboard
-// - Images
-// - Sound
-// - Seldom allocator
-// - Logging
-// - Graphics perf - request cache
-// Requires:
-// + [ ] Graphics tests
-// + [x] Graphics requests
-// + [ ] Seldom allocator
-// + [ ] Blake2 hash
-// + [ ] Requests cache
-// + [ ] Incremental rendering
-// - Examples
-// - Conway's Game of Life
-// - Julia Set
-// - Labyrinth
-// - Chat
-// - Graphics
-// - UI
-// - Icons
-// - Vector math
-// - CMYK color
-// - Textures
-// - Test suite
-// - Improve microbenchmarks library
-// - System
-// - Window
-// - Wayland
-// - Windows graphics
-// - Sound
-// - Windows audio
-// - Recording
-// - Device selection
-// - Switching canvases - Web
-// - Networking
-// - Windows sockets
-// - TCP
-// - fetch - via libcurl on native platforms
-// - Cross-platform networking - UDP + TCP + WebSocket
-// Requires:
-// - [ ] Sockets - UDP, TCP
-// - [ ] HTTP client
-// - [ ] HTTP server
-// - [ ] Web sockets
-// - [ ] Key exchange
-// - [ ] Cipher suite (Lattice-based?)
-// - [ ] TLS
-// - [ ] Web sockets over TLS
-// - Long term
-// - dlopen - load libraries conditionally
-// - X11
-// - Wayland
-// - ALSA
-// - Allocator
-// - Parsing
-// - Printing
-// - File system
-// - Secure random
-// - Process
-// - Shared memory
-// - Shared mutex
-// - Big integer
-// - Mersenne Twister 64
-// - Arithmetic coding
-// - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper
-// - Cryptography - https://github.com/jedisct1/supercop
-// - macOS support
-// - Mobile devices support
-//
-// Done
-//
-// - Examples
-// - Echo
-// - UI
-// - Particles
-// - Graph
-// - Sine Wave
-// - Utility
-// - UTF-8
-// - Testing
-// - Stackless coroutines
-// - Graphics
-// - Font
-// - Adaptive resolution
-// - Oklab color
-// - Relative coordinates
-// - Alpha blending
-// - Self-contained impl
-// - Anti-aliasing
-// - System
-// - Window - X11, Web
-// - Screenshot - X11, Wayland
-// - Clipboard
-// - Text - X11, Web
-// - Sound - ALSA, Web
-// - Networking
-// - Unix UDP sockets
-// - Drop files - X11, Web
-//
-// ----------------------------------------------------------------
-//
-// (C) 2025 Mitya Selivanov <guattari.tech>
-//
+#if 0 /*
+#/ ================================================================
+#/
+#/ reduced_system_layer.c
+#/
+#/ This is a reduced system layer.
+#/ It allows you to create a window, draw graphics in it, handle
+#/ input events, write samples to audio output, send and receive
+#/ UDP packets, etc. All code is single-threaded.
+#/
+#/ Primary target platforms: Linux (X11), Windows, Web.
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ DESIGN PRINCIPLES
+#/
+#/ - Minimalistic feature set. For graphics, you have access to the
+#/ pixel buffer, and that's it.
+#/
+#/ - No implicit control flow. No callbacks. You write your own
+#/ main and call everything explicitly. But the number of things
+#/ you have to call to do something is as little as possible.
+#/
+#/ - Optimized to use in a single source file.
+#/ Installation process? Ctrl+C, Ctrl+V, done.
+#/
+#/ STYLE CONVENTIONS
+#/
+#/ - Pascal_Snake_Case - Type name.
+#/ - snake_case - Non-type name.
+#/ - UPPER_SNAKE_CASE - Macro or constant.
+#/ - g_ prefix - Global variable name.
+#/
+#/ Most procedures have long and descriptive names.
+#/ Some procedures have prefixes according to their domain.
+#/
+#/ There may be exceptions if convenient.
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ To-Do list
+#/
+#/ - Work in progress
+#/ - Clipboard
+#/ - Images
+#/ - Sound
+#/ - Logging
+#/ - Graphics perf - request cache
+#/ Requires:
+#/ + [ ] Graphics tests
+#/ + [x] Graphics requests
+#/ + [x] Memory buffer allocator
+#/ + [x] Blake2 hash
+#/ + [ ] Requests cache
+#/ + [ ] Incremental rendering
+#/ - Examples
+#/ - Conway's Game of Life
+#/ - Julia Set
+#/ - Labyrinth
+#/ - Chat
+#/ - Graphics
+#/ - UI
+#/ - Icons
+#/ - Vector math
+#/ - CMYK color
+#/ - Textures
+#/ - Test suite
+#/ - Improve microbenchmarks library
+#/ - System
+#/ - Window
+#/ - Wayland
+#/ - Windows graphics
+#/ - Sound
+#/ - Windows audio
+#/ - Recording
+#/ - Device selection
+#/ - Switching canvases - Web
+#/ - Networking
+#/ - Windows sockets
+#/ - TCP
+#/ - fetch - via libcurl on native platforms
+#/ - Cross-platform networking - UDP + TCP + WebSocket
+#/ Requires:
+#/ - [ ] Sockets - UDP, TCP
+#/ - [ ] HTTP client
+#/ - [ ] HTTP server
+#/ - [ ] Web sockets
+#/ - [ ] Key exchange
+#/ - [ ] Cipher suite
+#/ - TLS_AES_128_GCM_SHA256
+#/ - Lattice-based ?
+#/ - [ ] TLS
+#/ - [ ] Web sockets over TLS
+#/ - Long term
+#/ - dlopen - load libraries conditionally
+#/ - X11
+#/ - Wayland
+#/ - ALSA
+#/ - Allocator
+#/ - Parsing
+#/ - Printing
+#/ - File system
+#/ - Secure random
+#/ - Process
+#/ - Shared memory
+#/ - Shared mutex
+#/ - Big integer
+#/ - Mersenne Twister 64
+#/ - Arithmetic coding
+#/ - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper
+#/ - Cryptography - https://github.com/jedisct1/supercop
+#/ - macOS support
+#/ - Mobile devices support
+#/
+#/ Done
+#/
+#/ - Examples
+#/ - Echo
+#/ - UI
+#/ - Particles
+#/ - Graph
+#/ - Sine Wave
+#/ - Utility
+#/ - UTF-8
+#/ - Testing
+#/ - Stackless coroutines
+#/ - Graphics
+#/ - Font
+#/ - Adaptive resolution
+#/ - Oklab color
+#/ - Relative coordinates
+#/ - Alpha blending
+#/ - Self-contained impl
+#/ - Anti-aliasing
+#/ - System
+#/ - Window - X11, Web
+#/ - Screenshot - X11, Wayland
+#/ - Clipboard
+#/ - Text - X11, Web
+#/ - Sound - ALSA, Web
+#/ - Networking
+#/ - Unix UDP sockets
+#/ - Drop files - X11, Web
+#/
+#/ ----------------------------------------------------------------
+#/
+#/ (C) 2025 Mitya Selivanov <guattari.tech>
+#/
+#/ ================================================================
+#/
+#/ Self-testing shell script
+#/
+#/ ================================================================
+
+SRC=${0##*./}
+BIN=${SRC%.*}
+gcc \
+ -Wall -Wextra -Werror -pedantic \
+ -Wno-missing-braces \
+ -Wno-old-style-declaration \
+ -Wno-overlength-strings \
+ -O3 -D NDEBUG \
+ -fsanitize=undefined,address,leak \
+ -D REDUCED_SYSTEM_LAYER_TEST_SUITE \
+ -lm -lX11 -lasound \
+ -lwayland-client \
+ -o $BIN $SRC && \
+ ./$BIN $@
+STATUS=$?
+rm -f $BIN
+exit $STATUS # */
+#endif
+
// ================================================================
//
// Types
@@ -187,6 +214,10 @@ typedef struct { f64 v[16]; } mat4;
#ifndef REDUCED_SYSTEM_LAYER_HEADER_GUARD_
#define REDUCED_SYSTEM_LAYER_HEADER_GUARD_
+#ifdef EVERY_TEST_SUITE
+#define GRAPHICS_TEST_SUITE
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -210,18 +241,22 @@ i32 main(i32 argc, c8 **argv);
//
// ================================================================
-#ifndef NO_WAYLAND
-#define NO_WAYLAND 0
+#ifndef ENABLE_WAYLAND
+#define ENABLE_WAYLAND 1
#endif
-#ifndef NO_X11
-#define NO_X11 0
+#ifndef ENABLE_X11
+#define ENABLE_X11 1
#endif
#ifndef STATIC_MEMORY_BUFFER_SIZE
#define STATIC_MEMORY_BUFFER_SIZE (10 * 1024 * 1024)
#endif
+#ifndef MEMORY_CHUNK_SIZE
+#define MEMORY_CHUNK_SIZE 1024
+#endif
+
// ----------------------------------------------------------------
// TEMP: Static buffers.
@@ -672,7 +707,7 @@ i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_po
void shutdown_all_systems(void);
// Memory
-void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data);
+void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data);
#ifdef REDUCED_SYSTEM_LAYER_HEADER
extern Platform g_platform;
@@ -736,14 +771,18 @@ void run_main_window_event_loop(void) {
// ================================================================
//
-// Seldom memory allocator
+// Memory buffer allocator
//
// ================================================================
+enum {
+ OCCUPIED_SIZE_ = (STATIC_MEMORY_BUFFER_SIZE + 64 * MEMORY_CHUNK_SIZE - 1) / (64 * MEMORY_CHUNK_SIZE),
+};
+
typedef struct {
- i64 offset;
- i64 size;
-} Memory_Slot_;
+ i64 next_chunk;
+ u64 occupied[OCCUPIED_SIZE_];
+} Memory_Buffer_Header_;
static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0};
@@ -751,20 +790,537 @@ static i64 num_memory_slots_(void) {
return *(i64 *) &g_platform.memory_buffer[g_platform.memory_buffer_size - 8];
}
-void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) {
- if (g_platform.memory_buffer_size < 0)
+static i64 align_(i64 x, i64 alignment) {
+ return ((x + (alignment - 1)) / alignment) * alignment;
+}
+
+void *memory_buffer_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) {
+ if (g_platform.memory_buffer_size < 0) {
LOG_ERROR("Invalid memory buffer size.");
- if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0)
+ return NULL;
+ }
+
+ if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) {
LOG_ERROR("Invalid memory buffer.");
+ return NULL;
+ }
if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) {
g_platform.memory_buffer_size = sizeof memory_buffer_;
g_platform.memory_buffer = memory_buffer_;
}
- // TODO
- LOG_ERROR("Not implemented.");
- return NULL;
+ if (g_platform.memory_buffer_size <= (i64) sizeof(Memory_Buffer_Header_)) {
+ LOG_ERROR("Memory buffer too small.");
+ return NULL;
+ }
+
+ Memory_Buffer_Header_ *h = (Memory_Buffer_Header_ *) g_platform.memory_buffer;
+ u8 * data = g_platform.memory_buffer + sizeof(Memory_Buffer_Header_);
+
+ i64 prev_num_chunks = (align_(previous_size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ i64 prev_chunk = ((u8 *) previous_data - data) / MEMORY_CHUNK_SIZE;
+
+ i64 num_chunks = (align_(size, alignment) + MEMORY_CHUNK_SIZE - 1) / MEMORY_CHUNK_SIZE;
+ i64 chunk = 0;
+
+ // Find free space
+ for (i64 i = h->next_chunk; i < OCCUPIED_SIZE_ * 64; ++i) {
+ b8 occupied = 0;
+
+ for (i64 j = i; j < i + num_chunks; ++j) {
+ if (j >= prev_chunk && j < prev_chunk + prev_num_chunks) continue;
+ if ((h->occupied[j / 64] & (1ull << (j % 64))) == 0) continue;
+ occupied = 1;
+ break;
+ }
+
+ if (occupied) {
+ chunk = i;
+ break;
+ }
+ }
+
+ u8 *src = data + prev_chunk * MEMORY_CHUNK_SIZE;
+ u8 *dst = data + chunk * MEMORY_CHUNK_SIZE;
+ i64 len = size < previous_size ? size : previous_size;
+
+ // Check if out of memory
+ if (data + size > g_platform.memory_buffer + g_platform.memory_buffer_size) {
+ LOG_ERROR("Out of memory.");
+ return NULL;
+ }
+
+ // Claim required space
+ for (i64 j = chunk; j < chunk + num_chunks; ++j)
+ h->occupied[j / 64] |= 1ull << (j % 64);
+
+ // Copy data
+ if (dst > src)
+ for (i64 k = len - 1; k >= 0; --k)
+ dst[k] = src[k];
+ else
+ for (i64 k = 0; k < len; ++k)
+ dst[k] = src[k];
+
+ // Free previous space
+ for (i64 j = prev_chunk; j < prev_chunk + prev_num_chunks; ++j) {
+ if (j >= chunk && j < chunk + num_chunks) continue;
+ h->occupied[j / 64] &= ~(1ull << (j % 64));
+ }
+
+ if (num_chunks == 0)
+ return NULL;
+
+ return dst;
+}
+
+// ================================================================
+//
+// BLAKE2B
+//
+// ================================================================
+
+enum blake2b_constant {
+ BLAKE2B_BLOCKBYTES = 128,
+ BLAKE2B_OUTBYTES = 64,
+ BLAKE2B_KEYBYTES = 64,
+ BLAKE2B_SALTBYTES = 16,
+ BLAKE2B_PERSONALBYTES = 16
+};
+
+typedef struct {
+ u8 digest_length;
+ u8 key_length;
+ u8 fanout;
+ u8 depth;
+ u32 leaf_length;
+ u64 node_offset;
+ u8 node_depth;
+ u8 inner_length;
+ u8 reserved[14];
+ u8 salt[BLAKE2B_SALTBYTES];
+ u8 personal[BLAKE2B_PERSONALBYTES];
+} Blake2b_Param;
+
+typedef struct {
+ u64 h[8];
+ u64 t[2];
+ u64 f[2];
+ u8 buf[2 * BLAKE2B_BLOCKBYTES];
+ u64 buflen;
+ u8 last_node;
+} Blake2b_State;
+
+static u64 blake2b_IV[8] = {
+ 0x6a09e667f3bcc908ull, 0xbb67ae8584caa73bull,
+ 0x3c6ef372fe94f82bull, 0xa54ff53a5f1d36f1ull,
+ 0x510e527fade682d1ull, 0x9b05688c2b3e6c1full,
+ 0x1f83d9abfb41bd6bull, 0x5be0cd19137e2179ull
+};
+
+static u8 blake2b_sigma[12][16] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
+};
+
+static void mem_set_(void *dst, u8 x, u32 size) {
+ for (u32 i = 0; i < size; ++i)
+ ((u8 *) dst)[i] = x;
+}
+
+static void mem_cpy_(void *dst, void *src, u32 size) {
+ for (u32 i = 0; i < size; ++i)
+ ((u8 *) dst)[i] = ((u8 *) src)[i];
+}
+
+static b8 native_little_endian_(void) {
+ return ((u8 *) &(u32) { 1 })[0] == 1;
+}
+
+static u32 load32_(void *src) {
+ if (native_little_endian_())
+ return *( u32 * )( src );
+ else {
+ u8 *p = ( u8 * )src;
+ u32 w = *p++;
+ w |= ( u32 )( *p++ ) << 8;
+ w |= ( u32 )( *p++ ) << 16;
+ w |= ( u32 )( *p++ ) << 24;
+ return w;
+ }
+}
+
+static u64 load64_(void *src) {
+ if (native_little_endian_())
+ return *( u64 * )( src );
+ else {
+ u8 *p = ( u8 * )src;
+ u64 w = *p++;
+ w |= ( u64 )( *p++ ) << 8;
+ w |= ( u64 )( *p++ ) << 16;
+ w |= ( u64 )( *p++ ) << 24;
+ w |= ( u64 )( *p++ ) << 32;
+ w |= ( u64 )( *p++ ) << 40;
+ w |= ( u64 )( *p++ ) << 48;
+ w |= ( u64 )( *p++ ) << 56;
+ return w;
+ }
+}
+
+static void store32_(void *dst, u32 w) {
+ if (native_little_endian_())
+ *( u32 * )( dst ) = w;
+ else {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+ }
+}
+
+static void store64_(void *dst, u64 w) {
+ if (native_little_endian_())
+ *( u64 * )( dst ) = w;
+ else {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+ }
+}
+
+static u64 load48_(void *src) {
+ u8 *p = ( u8 * )src;
+ u64 w = *p++;
+ w |= ( u64 )( *p++ ) << 8;
+ w |= ( u64 )( *p++ ) << 16;
+ w |= ( u64 )( *p++ ) << 24;
+ w |= ( u64 )( *p++ ) << 32;
+ w |= ( u64 )( *p++ ) << 40;
+ return w;
+}
+
+static void store48_(void *dst, u64 w) {
+ u8 *p = ( u8 * )dst;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w; w >>= 8;
+ *p++ = ( u8 )w;
+}
+
+static u32 rotl32_(u32 w, u32 c) {
+ return ( w << c ) | ( w >> ( 32 - c ) );
+}
+
+static u64 rotl64_(u64 w, u32 c) {
+ return ( w << c ) | ( w >> ( 64 - c ) );
+}
+
+static u32 rotr32_(u32 w, u32 c) {
+ return ( w >> c ) | ( w << ( 32 - c ) );
+}
+
+static u64 rotr64_(u64 w, u32 c) {
+ return ( w >> c ) | ( w << ( 64 - c ) );
+}
+
+static void secure_zero_memory_(void *v, u64 n) {
+ volatile u8 *p = ( volatile u8 * )v;
+ while( n-- ) *p++ = 0;
+}
+
+static i32 blake2b_set_lastnode_(Blake2b_State *S) {
+ S->f[1] = ~0ull;
+ return 0;
+}
+
+static i32 blake2b_clear_lastnode_(Blake2b_State *S) {
+ S->f[1] = 0ull;
+ return 0;
+}
+
+static i32 blake2b_set_lastblock_(Blake2b_State *S) {
+ if( S->last_node ) blake2b_set_lastnode_( S );
+
+ S->f[0] = ~0ull;
+ return 0;
+}
+
+static i32 blake2b_clear_lastblock_(Blake2b_State *S) {
+ if( S->last_node ) blake2b_clear_lastnode_( S );
+
+ S->f[0] = 0ull;
+ return 0;
+}
+
+static i32 blake2b_increment_counter_(Blake2b_State *S, u64 inc) {
+ S->t[0] += inc;
+ S->t[1] += ( S->t[0] < inc );
+ return 0;
+}
+
+static i32 blake2b_param_set_digest_length_(Blake2b_Param *P, u8 digest_length) {
+ P->digest_length = digest_length;
+ return 0;
+}
+
+static i32 blake2b_param_set_fanout_(Blake2b_Param *P, u8 fanout) {
+ P->fanout = fanout;
+ return 0;
+}
+
+static i32 blake2b_param_set_max_depth_(Blake2b_Param *P, u8 depth) {
+ P->depth = depth;
+ return 0;
+}
+
+static i32 blake2b_param_set_leaf_length_(Blake2b_Param *P, u32 leaf_length) {
+ store32_( &P->leaf_length, leaf_length );
+ return 0;
+}
+
+static i32 blake2b_param_set_node_offset_(Blake2b_Param *P, u64 node_offset) {
+ store64_( &P->node_offset, node_offset );
+ return 0;
+}
+
+static i32 blake2b_param_set_node_depth_(Blake2b_Param *P, u8 node_depth) {
+ P->node_depth = node_depth;
+ return 0;
+}
+
+static i32 blake2b_param_set_inner_length_(Blake2b_Param *P, u8 inner_length) {
+ P->inner_length = inner_length;
+ return 0;
+}
+
+static i32 blake2b_param_set_salt_(Blake2b_Param *P, u8 salt[BLAKE2B_SALTBYTES]) {
+ mem_cpy_( P->salt, salt, BLAKE2B_SALTBYTES );
+ return 0;
+}
+
+static i32 blake2b_param_set_personal_(Blake2b_Param *P, u8 personal[BLAKE2B_PERSONALBYTES]) {
+ mem_cpy_( P->personal, personal, BLAKE2B_PERSONALBYTES );
+ return 0;
+}
+
+static i32 blake2b_init0_(Blake2b_State *S) {
+ i32 i;
+ mem_set_( S, 0, sizeof( Blake2b_State ) );
+
+ for(i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i];
+
+ return 0;
+}
+
+static i32 blake2b_init_param_(Blake2b_State *S, Blake2b_Param *P) {
+ blake2b_init0_( S );
+ u8 *p = ( u8 * )( P );
+ u64 i;
+
+ for( i = 0; i < 8; ++i )
+ S->h[i] ^= load64_( p + sizeof( S->h[i] ) * i );
+
+ return 0;
+}
+
+i32 blake2b_init(Blake2b_State *S, u8 outlen) {
+ Blake2b_Param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = 0;
+ P->fanout = 1;
+ P->depth = 1;
+ store32_( &P->leaf_length, 0 );
+ store64_( &P->node_offset, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ mem_set_( P->reserved, 0, sizeof( P->reserved ) );
+ mem_set_( P->salt, 0, sizeof( P->salt ) );
+ mem_set_( P->personal, 0, sizeof( P->personal ) );
+ return blake2b_init_param_( S, P );
+}
+
+static i32 blake2b_compress_(Blake2b_State *S, u8 block[BLAKE2B_BLOCKBYTES]) {
+ u64 m[16];
+ u64 v[16];
+ i32 i;
+
+ for( i = 0; i < 16; ++i )
+ m[i] = load64_( block + i * sizeof( m[i] ) );
+
+ for( i = 0; i < 8; ++i )
+ v[i] = S->h[i];
+
+ v[ 8] = blake2b_IV[0];
+ v[ 9] = blake2b_IV[1];
+ v[10] = blake2b_IV[2];
+ v[11] = blake2b_IV[3];
+ v[12] = S->t[0] ^ blake2b_IV[4];
+ v[13] = S->t[1] ^ blake2b_IV[5];
+ v[14] = S->f[0] ^ blake2b_IV[6];
+ v[15] = S->f[1] ^ blake2b_IV[7];
+#define G(r,i,a,b,c,d) \
+ do { \
+ a = a + b + m[blake2b_sigma[r][2*i+0]]; \
+ d = rotr64_(d ^ a, 32); \
+ c = c + d; \
+ b = rotr64_(b ^ c, 24); \
+ a = a + b + m[blake2b_sigma[r][2*i+1]]; \
+ d = rotr64_(d ^ a, 16); \
+ c = c + d; \
+ b = rotr64_(b ^ c, 63); \
+ } while(0)
+#define ROUND(r) \
+ do { \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]); \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]); \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]); \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]); \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \
+ } while(0)
+ ROUND( 0 );
+ ROUND( 1 );
+ ROUND( 2 );
+ ROUND( 3 );
+ ROUND( 4 );
+ ROUND( 5 );
+ ROUND( 6 );
+ ROUND( 7 );
+ ROUND( 8 );
+ ROUND( 9 );
+ ROUND( 10 );
+ ROUND( 11 );
+
+ for( i = 0; i < 8; ++i )
+ S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
+
+#undef G
+#undef ROUND
+ return 0;
+}
+
+i32 blake2b_update(Blake2b_State *S, u8 *in, u64 inlen) {
+ while( inlen > 0 ) {
+ u64 left = S->buflen;
+ u64 fill = 2 * BLAKE2B_BLOCKBYTES - left;
+
+ if( inlen > fill ) {
+ mem_cpy_( S->buf + left, in, fill );
+ S->buflen += fill;
+ blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES );
+ blake2b_compress_( S, S->buf );
+ mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, BLAKE2B_BLOCKBYTES );
+ S->buflen -= BLAKE2B_BLOCKBYTES;
+ in += fill;
+ inlen -= fill;
+ } else {
+ mem_cpy_( S->buf + left, in, inlen );
+ S->buflen += inlen;
+ in += inlen;
+ inlen -= inlen;
+ }
+ }
+
+ return 0;
+}
+
+i32 blake2b_init_key(Blake2b_State *S, u8 outlen, void *key, u8 keylen) {
+ Blake2b_Param P[1];
+
+ if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1;
+
+ if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1;
+
+ P->digest_length = outlen;
+ P->key_length = keylen;
+ P->fanout = 1;
+ P->depth = 1;
+ store32_( &P->leaf_length, 0 );
+ store64_( &P->node_offset, 0 );
+ P->node_depth = 0;
+ P->inner_length = 0;
+ mem_set_( P->reserved, 0, sizeof( P->reserved ) );
+ mem_set_( P->salt, 0, sizeof( P->salt ) );
+ mem_set_( P->personal, 0, sizeof( P->personal ) );
+
+ if( blake2b_init_param_( S, P ) < 0 ) return -1;
+
+ {
+ u8 block[BLAKE2B_BLOCKBYTES];
+ mem_set_( block, 0, BLAKE2B_BLOCKBYTES );
+ mem_cpy_( block, key, keylen );
+ blake2b_update( S, block, BLAKE2B_BLOCKBYTES );
+ secure_zero_memory_( block, BLAKE2B_BLOCKBYTES );
+ }
+ return 0;
+}
+
+i32 blake2b_final(Blake2b_State *S, u8 *out, u8 outlen) {
+ u8 buffer[BLAKE2B_OUTBYTES];
+ i32 i;
+
+ if( S->buflen > BLAKE2B_BLOCKBYTES ) {
+ blake2b_increment_counter_( S, BLAKE2B_BLOCKBYTES );
+ blake2b_compress_( S, S->buf );
+ S->buflen -= BLAKE2B_BLOCKBYTES;
+ mem_cpy_( S->buf, S->buf + BLAKE2B_BLOCKBYTES, S->buflen );
+ }
+
+ blake2b_increment_counter_( S, S->buflen );
+ blake2b_set_lastblock_( S );
+ mem_set_( S->buf + S->buflen, 0, 2 * BLAKE2B_BLOCKBYTES - S->buflen );
+ blake2b_compress_( S, S->buf );
+
+ for( i = 0; i < 8; ++i )
+ store64_( buffer + sizeof( S->h[i] ) * i, S->h[i] );
+
+ mem_cpy_( out, buffer, outlen );
+ return 0;
+}
+
+i32 blake2b(u8 *out, void *in, void *key, u8 outlen, u64 inlen, u8 keylen) {
+ Blake2b_State S[1];
+
+ if ( NULL == in ) return -1;
+ if ( NULL == out ) return -1;
+ if ( NULL == key ) keylen = 0;
+
+ if ( keylen > 0 ) {
+ if ( blake2b_init_key( S, outlen, key, keylen ) < 0 )
+ return -1;
+ } else {
+ if ( blake2b_init( S, outlen ) < 0 )
+ return -1;
+ }
+
+ blake2b_update( S, ( u8 * )in, inlen );
+ blake2b_final( S, out, outlen );
+ return 0;
}
// ================================================================
@@ -1556,7 +2112,7 @@ void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) {
//
// ================================================================
-#if defined(__linux__) && !NO_WAYLAND
+#if defined(__linux__) && ENABLE_WAYLAND
#include <sys/mman.h>
#include <wayland-client.h>
@@ -2088,7 +2644,7 @@ finalize:
return ok;
}
-#endif // defined(__linux__) && !NO_WAYLAND
+#endif // defined(__linux__) && ENABLE_WAYLAND
// ================================================================
//
@@ -2096,7 +2652,7 @@ finalize:
//
// ================================================================
-#if defined(__linux__) && !NO_X11
+#if defined(__linux__) && ENABLE_X11
#include <sys/stat.h>
#include <X11/Xlib.h>
@@ -2137,7 +2693,6 @@ static Window _dnd_source = 0;
static b8 _mapped = 0;
static b8 _requested_clipboard = 0;
-
static i16 _key_table [MAX_NUM_KEYS] = {0};
static b8 _key_repeat [MAX_NUM_KEYS] = {0};
static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0};
@@ -2151,7 +2706,7 @@ static b8 sub_str_eq_(c8 *a, c8 *b, i64 len) {
return 1;
}
-i32 x11_error_handler_(Display *display, XErrorEvent *event) {
+static i32 x11_error_handler_(Display *display, XErrorEvent *event) {
XGetErrorText(display, event->error_code, _error_buffer, sizeof _error_buffer - 1);
LOG_ERROR("%s", _error_buffer);
return 0;
@@ -3024,23 +3579,23 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels
return 1;
}
-#endif // defined(__linux__) && !NO_X11
+#endif // defined(__linux__) && ENABLE_X11
// ================================================================
-#if defined(__linux__) && (!NO_X11 || !NO_WAYLAND)
+#if defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND)
void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) {
if (width == NULL || height == NULL) {
LOG_ERROR("Invalid arguments.");
return;
}
- #if !NO_X11
+ #if ENABLE_X11
if (x11_screenshot_(max_num_pixels, width, height, pixels))
return;
#endif
- #if !NO_WAYLAND
+ #if ENABLE_WAYLAND
if (wayland_screenshot_(max_num_pixels, width, height, pixels))
return;
#endif
@@ -3048,7 +3603,7 @@ void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixe
*width = 0;
*height = 0;
}
-#endif // defined(__linux__) && (!NO_X11 || !NO_WAYLAND)
+#endif // defined(__linux__) && (ENABLE_X11 || ENABLE_WAYLAND)
// ================================================================
//
@@ -3541,6 +4096,28 @@ __attribute__((export_name("js_drop"))) void js_drop(i32 name_len, i32 data_size
#endif // defined(__wasm__)
// ================================================================
+//
+// Test suite
+//
+// ================================================================
+
+#ifdef REDUCED_SYSTEM_LAYER_TEST_SUITE
+
+#define TEST_FILE reduced_system_layer
+#include "test.c"
+
+#ifndef EVERY_TEST_SUITE
+void update_and_render_frame(void) {}
+
+i32 main(i32 argc, c8 **argv) {
+ return run_tests(argc, argv);
+}
+#endif
+
+#undef TEST_FILE
+#endif // REDUCED_SYSTEM_LAYER_TEST_SUITE
+
+// ================================================================
#undef LOG_ERROR