From 8d502173a2dda33ef50605ec47da6940600c5583 Mon Sep 17 00:00:00 2001 From: veclavtlica Date: Wed, 7 Oct 2026 11:21:21 +0300 Subject: [PATCH] some progress --- Common/Std/linux.c | 35 +++++---- Common/Std/stub.c | 10 +++ Common/Timer/stub.c | 2 +- Common/bin.c | 64 ++++++++++++++++ Common/bin.h | 45 +++++++++++ Common/bits.h | 33 ++++---- Common/buf.c | 13 ++++ Common/buf.h | 57 ++++++++++++++ Common/cfg.h | 12 +++ Common/def.h | 48 ++++++++---- Common/fix.c | 160 +++++++++++++++++++-------------------- Common/gem.h | 40 +++++----- Common/mat.h | 22 +++--- Common/pnt.h | 2 +- Common/std.h | 31 ++++++-- Common/str.h | 61 +++++++++++++++ Common/vec.h | 17 ++--- Player/Display/display.h | 2 +- Player/Display/x11.c | 129 ++++++++++++++++++++++++++++--- Player/Main/libc.c | 3 + Player/Main/linux.c | 22 +++--- Player/Makefile | 39 +++++++++- Player/amalgam.c | 4 + Player/draw.c | 13 ++-- Player/index.html | 5 +- Player/tiny.ld | 48 ++++++++++++ 26 files changed, 705 insertions(+), 212 deletions(-) create mode 100644 Common/bin.c create mode 100644 Common/bin.h create mode 100644 Common/buf.c create mode 100644 Common/buf.h create mode 100644 Common/cfg.h create mode 100644 Common/str.h create mode 100644 Player/Main/libc.c create mode 100644 Player/tiny.ld diff --git a/Common/Std/linux.c b/Common/Std/linux.c index 94cd865..07777d5 100644 --- a/Common/Std/linux.c +++ b/Common/Std/linux.c @@ -1,16 +1,8 @@ +#include "../def.h" #include "../std.h" +#include "../str.h" #include -#include - -static inline long com_std_syscall(long number, long arg1, long arg2, - long arg3) { - long ret; - __asm__ volatile("syscall" - : "=a"(ret) - : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3) - : "rcx", "r11", "memory"); - return ret; -} +#include void *com_std_alloc(void *ptr, size_t size) { return NULL; } void com_std_assert(bool holds) { @@ -21,13 +13,26 @@ void com_std_assert(bool holds) { /* TODO: Figure out a way to make it easy to deal with. */ void com_std_printf(char const *fmt, ...) { - // va_list args; - // va_start(args, fmt); - // vprintf(fmt, args); - // va_end(args); + com_std_syscall(1, 1, (intptr_t)fmt, com_str_ext_len(fmt)); +} + +void com_std_print_str(char const *str, uint32_t len, bool newline) { + com_std_syscall(1, 1, (intptr_t)str, len); + if (newline) + com_std_syscall(1, 1, (intptr_t)"\n", 1); } double com_std_sqrt(double v) { return __builtin_sqrt(v); } double com_std_fabs(double v) { return __builtin_fabs(v); } +#if COM_DEF_COMPILER == COM_DEF_COMPILER_CLANG double com_std_sin(double v) { return __builtin_sin(v); } double com_std_cos(double v) { return __builtin_cos(v); } +#else +/* TODO: Use fsin/fcos, no matter how slow. */ +double com_std_sin(double v) { return 0; } +double com_std_cos(double v) { return 0; } +#endif + +// void memcpy(void *__restrict dest, const void *__restrict src, size_t n) { +// __builtin_memcpy(dest, src, n); +// }; diff --git a/Common/Std/stub.c b/Common/Std/stub.c index 6d99041..55b156f 100644 --- a/Common/Std/stub.c +++ b/Common/Std/stub.c @@ -6,5 +6,15 @@ void com_std_printf(char const *fmt, ...) {} double com_std_sqrt(double v) { return __builtin_sqrt(v); } double com_std_fabs(double v) { return __builtin_fabs(v); } +#if COM_DEF_COMPILER == COM_DEF_COMPILER_CLANG double com_std_sin(double v) { return __builtin_sin(v); } double com_std_cos(double v) { return __builtin_cos(v); } +#else +/* TODO: Use fsin/fcos, no matter how slow. */ +double com_std_sin(double v) { return 0; } +double com_std_cos(double v) { return 0; } +#endif + +// void memcpy(void *__restrict dest, const void *__restrict src, size_t n) { +// __builtin_memcpy(dest, src, n); +// }; diff --git a/Common/Timer/stub.c b/Common/Timer/stub.c index 0be7d8e..3f3865f 100644 --- a/Common/Timer/stub.c +++ b/Common/Timer/stub.c @@ -1,4 +1,4 @@ -#include "time.h" +#include "../time.h" #include uint64_t com_timer_count_ns(void) { return 0; } diff --git a/Common/bin.c b/Common/bin.c new file mode 100644 index 0000000..4728d59 --- /dev/null +++ b/Common/bin.c @@ -0,0 +1,64 @@ +#include +#include + +#include "bin.h" +#include "bits.h" +#include "buf.h" +#include "def.h" +#include "std.h" + +bool com_bin_read_i16(com_bin *b, int16_t *value) { + int16_t buf; + if (!b->interface.readn(b->ctx, (char *)&buf, 2)) + return false; + if (COM_DEF_CPU_LITEND && (b->flags & COM_BIN_BIG_ENDIAN)) { + *value = __builtin_bswap16(buf); + } else + *value = buf; + return true; +} + +/* Same thing, really. */ +bool com_bin_read_u16(com_bin *b, uint16_t *value) { + return (com_bin_read_i16(b, (int16_t *)value)); +} + +bool com_bin_read_bufb(com_bin *b, struct com_buf *buf, uint32_t bytes) { + com_std_assert(buf->typesz == 1); + + if (!com_buf_make_room(buf, bytes)) + return false; + bool s = b->interface.readn(b->ctx, (char *)&buf->data[buf->len], bytes); + if (s) + buf->len += bytes; + return s; +} + +bool com_bin_read_bufbi(com_bin *b, struct com_buf *buf, uint32_t *index, + uint32_t bytes) { + com_std_assert(buf->typesz == 1); + + uint32_t const alignextra = + com_bits_nalign(buf->len, COM_DEF_ALIGNMENT) - buf->len; + + if (!com_buf_make_room(buf, alignextra + sizeof(struct com_buf) + bytes)) + return false; + + buf->len += alignextra; + struct com_buf *in = (struct com_buf *)&buf->data[buf->len]; + buf->len += sizeof(struct com_buf); + bool s = b->interface.readn(b->ctx, (char *)&buf->data[buf->len], bytes); + if (s) { + buf->len += bytes; + *in = (struct com_buf){.cap = bytes, + .len = bytes, + .typesz = 1, + .flags = (buf->flags & COM_BUF_STACK) | COM_BUF_SUB}; + *index = ((ptrdiff_t)in - (ptrdiff_t)buf->data) / sizeof(struct com_buf); + } + return s; +} + +bool com_bin_skip(com_bin *b, uint32_t bytes) { + return b->interface.skipn(b->ctx, bytes); +} diff --git a/Common/bin.h b/Common/bin.h new file mode 100644 index 0000000..7461865 --- /dev/null +++ b/Common/bin.h @@ -0,0 +1,45 @@ +/* + Generic interface for binary data parsing. +*/ + +#ifndef COM_BIN_H +#define COM_BIN_H + +#include + +#include "buf.h" + +#define COM_BIN_LIT_ENDIAN (1 << 0) +#define COM_BIN_BIG_ENDIAN (1 << 1) +#define COM_BIN_NAT_ENDIAN (1 << 2) + +typedef struct com_bin_interface { + /* Attempts to read exactly N bytes, returns false if it cannot. */ + bool (*readn)(void *ctx, char *into, uint32_t bytes); + bool (*skipn)(void *ctx, uint32_t bytes); +} com_bin_interface; + +typedef struct com_bin { + struct com_bin_interface interface; + void *ctx; + uint32_t flags; +} com_bin; + +bool com_bin_read_i16(com_bin *b, int16_t *value); +bool com_bin_read_u16(com_bin *b, uint16_t *value); +/* + Read untyped bytes appending them to buffer. + NOTE: Buffer must have typesz of 1. */ +bool com_bin_read_bufb(com_bin *b, struct com_buf *buf, uint32_t bytes); +/* + Inline byte buffer read, making a new buffer inside. + Resulted index can be safely used in case of future reallocations. + NOTE: Buffer must have typesz of 1. */ +bool com_bin_read_bufbi(com_bin *b, struct com_buf *buf, uint32_t *index, + uint32_t bytes); + +/* TODO: Typed variant, use buf for typesz? */ +/* Skip N bytes. */ +bool com_bin_skip(com_bin *b, uint32_t n); + +#endif diff --git a/Common/bits.h b/Common/bits.h index ae84e6a..0dee408 100644 --- a/Common/bits.h +++ b/Common/bits.h @@ -6,23 +6,28 @@ /* How many bits needed to represent a given number */ /* Alternitive semntic: nearest upper power of two */ -static inline int com_bits_needed(uint32_t v) { -#ifdef COM_DEF_COMPILE_MODERN +static inline uint8_t com_bits_needed(uint32_t v) { + // #ifdef COM_DEF_COMPILE_MODERN return v == 0 ? 1 : 32 - __builtin_clz(v); -#else -#endif - if (v == 0) - return 1; + // #else + // #endif + // if (v == 0) + // return 1; - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; + // v--; + // v |= v >> 1; + // v |= v >> 2; + // v |= v >> 4; + // v |= v >> 8; + // v |= v >> 16; + // v++; - return v; + // return v; +} + +/* Next aligned value. */ +static inline uint32_t com_bits_nalign(uint32_t v, uint8_t a) { + return (v + (a - 1)) & ~(a - 1); } #endif diff --git a/Common/buf.c b/Common/buf.c new file mode 100644 index 0000000..b114eaf --- /dev/null +++ b/Common/buf.c @@ -0,0 +1,13 @@ +#include "buf.h" +#include +#include + +struct com_buf *com_buf_make(uint32_t cap, uint32_t flags) { return NULL; } + +bool com_buf_make_room(struct com_buf *b, uint32_t n) { + if (b->cap - b->len >= n) + return true; + return false; +} + +void com_buf_free(struct com_buf *b) {} diff --git a/Common/buf.h b/Common/buf.h new file mode 100644 index 0000000..6f153ca --- /dev/null +++ b/Common/buf.h @@ -0,0 +1,57 @@ +/* + Generic buffer structure, both dynamic and static. + + Underlying implementation is very simplistic, but it's done so + in assumption that we always bulk allocate, with no fragmentation. +*/ + +#ifndef COM_BUF_H +#define COM_BUF_H + +#include "def.h" +#include "str.h" +#include +#include + +#define COM_BUF_GROWABLE (1 << 0) /* Potentially growable. */ +#define COM_BUF_STACK (1 << 1) /* Stack residing. */ +#define COM_BUF_RING (1 << 2) /* Cycling memory. */ +#define COM_BUF_SUB (1 << 3) /* Buffer inside of a buffer. */ + +typedef struct com_buf { + uint32_t len; /* Length in typed number of elements. */ + uint32_t cap; /* Capacity in typed number of elements. */ + uint32_t flags; + union { + uint32_t needle; /* Present for ring type. */ + } type; + uint8_t typesz; + char data[] __attribute__((aligned(COM_DEF_ALIGNMENT))); +} com_buf; + +/* Creates a stack local buffer. It can grow if is set growable, one must still + * free it. */ +#define com_buf_make_on_stack(p_t, p_v, p_c, p_f) \ + char p_v##_buf[sizeof(p_t) * (p_c)] \ + __attribute__((aligned(COM_DEF_ALIGNMENT))); \ + struct com_buf *p_v = (struct com_buf *)&p_v##_buf; \ + p_v->cap = (p_c); \ + p_v->flags = p_f | COM_BUF_STACK; \ + p_v->typesz = sizeof(p_t); + +#define com_buf_index(p_t, p_v, p_i) \ + (p_t *)(&(p_v)->data[(p_v)->typesz * (p_i)]) + +/* Dynamic allocation to persist no matter the function flow. */ +struct com_buf *com_buf_make(uint32_t cap, uint32_t flags); + +/* Makes sure there's N elements of capacity at least. Returns false if it + * cannot do so. */ +bool com_buf_make_room(struct com_buf *b, uint32_t n); + +/* Drops the memory, not touching the cap. */ +static inline void com_buf_clear(struct com_buf *b) { b->len = 0; } + +void com_buf_free(struct com_buf *b); + +#endif diff --git a/Common/cfg.h b/Common/cfg.h new file mode 100644 index 0000000..fb8187d --- /dev/null +++ b/Common/cfg.h @@ -0,0 +1,12 @@ +/* + Configuration file. +*/ + +#ifndef COM_CFG_H +#define COM_CFG_H + +/* Render resolution. */ +#define COM_CFG_WIDTH 640 +#define COM_CFG_HEIGHT 480 + +#endif diff --git a/Common/def.h b/Common/def.h index 41d77a1..84997e1 100644 --- a/Common/def.h +++ b/Common/def.h @@ -1,37 +1,57 @@ /* Compiler definitions helpers, for portability. + We assume only modern GCC and Clang here. */ #ifndef COM_DEF_H #define COM_DEF_H -#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L) || \ - defined(__GNUC__) || defined(__clang__) -#define COM_DEF_COMPILE_MODERN 1 +#define COM_DEF_COMPILER_CLANG 1 +#define COM_DEF_COMPILER_GCC 2 + +#if defined(__GNUC__) && !defined(__clang__) +#define COM_DEF_COMPILER COM_DEF_COMPILER_GCC +#elif defined(__clang__) +#define COM_DEF_COMPILER COM_DEF_COMPILER_CLANG #endif -#define COM_DEF_TARGET_LINUX 0 -#define COM_DEF_TARGET_WASM 1 +#define COM_DEF_TARGET_LINUX 1 +#define COM_DEF_TARGET_WASM 2 #if defined(__wasm__) #define COM_DEF_TARGET COM_DEF_TARGET_WASM #define com_def_export_sym(m_s) __attribute__((export_name(m_s))) -#else +#elif defined(__linux__) #define COM_DEF_TARGET COM_DEF_TARGET_LINUX #define com_def_export_sym(m_s) __attribute__((visibility("default"))) +#else +#error Unknown target. #endif -/* TODO: uppercase? */ -#ifdef COM_DEF_COMPILE_MODERN -#define com_def_alignedas(v_as) _Alignas(v_as) -#define com_def_vector(v_t, v_v, v_n) \ - v_t v_v __attribute__((vector_size(sizeof(v_t) * v_n))) +#define COM_DEF_CPU_AMD64 1 +#define COM_DEF_CPU_X86 2 +#define COM_DEF_CPU_WASM32 3 + +#if defined(__wasm__) +#define COM_DEF_CPU COM_DEF_CPU_WASM32 +#define COM_DEF_ALIGNMENT 16 +#define COM_DEF_CPU_LITEND 1 +#elif defined(__x86_64__) || defined(__amd64__) +#define COM_DEF_CPU COM_DEF_CPU_AMD64 +#define COM_DEF_CPU_LITEND 1 +#define COM_DEF_ALIGNMENT 32 +#elif defined(__i386__) +#define COM_DEF_CPU COM_DEF_CPU_X86 +#define COM_DEF_ALIGNMENT 16 +#define COM_DEF_CPU_LITEND 1 #else -#define com_def_alignedas(v_as) -#define com_def_vector(v_t, v_v, v_n) v_t v_v[v_n] +#error Unknown cpu. #endif +#define com_def_alignedas(v_as) _Alignas(v_as) +#define com_def_vector(v_t, v_v, v_b) v_t v_v __attribute__((vector_size(v_b))) + // #define COM_DEF_PROFILE_VAR volatile /* Sadly, doesn't work in some cases */ -#define COM_DEF_PROFILE_SINK(m_v) __asm__ volatile("" ::"r"(m_v) : "memory") +#define com_def_profile_sink(m_v) __asm__ volatile("" ::"r"(m_v) : "memory") #endif diff --git a/Common/fix.c b/Common/fix.c index 10d4832..27cb460 100644 --- a/Common/fix.c +++ b/Common/fix.c @@ -51,12 +51,7 @@ com_fix_t com_fix_sqrt(com_fix_t a) { if (shift & 1) shift -= 1; - uint32_t normalized_a; - if (shift > 0) { - normalized_a = a >> shift; - } else { - normalized_a = a << (-shift); - } + uint32_t normalized_a = shift > 0 ? a >> shift : a << (-shift); // 3. LUT Lookup using 4 MSBs of the normalized value // Extracted index corresponds to the interval [0.5, 2.0) @@ -72,11 +67,8 @@ com_fix_t com_fix_sqrt(com_fix_t a) { // 5. Denormalize back to the target scale: result = x * 2^(shift / 2) int32_t final_shift = shift / 2; - if (final_shift > 0) { - return (int32_t)(x << final_shift); - } else { - return (int32_t)(x >> (-final_shift)); - } + return final_shift > 0 ? (int32_t)(x << final_shift) + : (int32_t)(x >> (-final_shift)); } void com_fix_print(com_fix_t a) { @@ -97,21 +89,21 @@ void com_fix_run_bench(void) { uint64_t start = com_timer_count_ns(); for (int i = 5000000; i--;) { com_fix_t sqrt = com_fix_sqrt(i); - COM_DEF_PROFILE_SINK(sqrt); + com_def_profile_sink(sqrt); } com_timer_profile(start, "fixed: sqrt"); start = com_timer_count_ns(); for (int i = 50000000; i--;) { com_fix_t sin = com_fix_sin(i); - COM_DEF_PROFILE_SINK(sin); + com_def_profile_sink(sin); } com_timer_profile(start, "fixed: sin"); start = com_timer_count_ns(); for (int i = 50000000; i--;) { com_fix_t cos = com_fix_cos(i); - COM_DEF_PROFILE_SINK(cos); + com_def_profile_sink(cos); } com_timer_profile(start, "fixed: cos"); @@ -121,82 +113,82 @@ void com_fix_run_bench(void) { com_fix_sincos(i, &sin, &cos); com_fix_t sinv = sin; com_fix_t cosv = cos; - COM_DEF_PROFILE_SINK(sinv); - COM_DEF_PROFILE_SINK(cosv); + com_def_profile_sink(sinv); + com_def_profile_sink(cosv); } com_timer_profile(start, "fixed: sincos"); } void com_fix_run_tests(void) { - // { - // double max_sqrt_deviation = 0.0f; - // com_fix_t sqrt_accumulator = 0; - // com_fix_t sqrt_test_step = COM_FIX_FRACUNIT >> 2; /* Quarter step */ - // for (int i = 0; i < COM_FIX_FRACUNIT << 1; ++i) { - // com_fix_t sqrt = com_fix_sqrt(sqrt_accumulator); - // double const deviation = - // com_std_sqrt(com_fix_as_float(sqrt_accumulator)) - - // com_fix_as_float(sqrt); - // if (deviation > max_sqrt_deviation) - // max_sqrt_deviation = deviation; - // sqrt_accumulator += sqrt_test_step; - // } - // com_std_printf("max sqrt deviation: %f\n", max_sqrt_deviation); - // } + { + double max_sqrt_deviation = 0.0f; + com_fix_t sqrt_accumulator = 0; + com_fix_t sqrt_test_step = COM_FIX_FRACUNIT >> 2; /* Quarter step */ + for (int i = 0; i < COM_FIX_FRACUNIT << 1; ++i) { + com_fix_t sqrt = com_fix_sqrt(sqrt_accumulator); + double const deviation = + com_std_sqrt(com_fix_as_float(sqrt_accumulator)) - + com_fix_as_float(sqrt); + if (deviation > max_sqrt_deviation) + max_sqrt_deviation = deviation; + sqrt_accumulator += sqrt_test_step; + } + com_std_printf("max sqrt deviation: %f\n", max_sqrt_deviation); + } - // { - // double max_sin_deviation = 0.0f; - // com_fix_t sin_accumulator = -COM_FIX_PI * 4; - // com_fix_t sin_test_step = (COM_FIX_PI << 1) >> 10; - // for (int i = 0; i < 1024 * 32; ++i) { - // com_fix_t sin = com_fix_sin(sin_accumulator); - // double const deviation = - // com_std_fabs(com_std_sin(com_fix_as_float(sin_accumulator)) - - // com_fix_as_float(sin)); - // if (deviation > max_sin_deviation) - // max_sin_deviation = deviation; - // sin_accumulator += sin_test_step; - // } - // com_std_printf("max sin deviation: %f\n", max_sin_deviation); - // } + { + double max_sin_deviation = 0.0f; + com_fix_t sin_accumulator = -COM_FIX_PI * 4; + com_fix_t sin_test_step = (COM_FIX_PI << 1) >> 10; + for (int i = 0; i < 1024 * 32; ++i) { + com_fix_t sin = com_fix_sin(sin_accumulator); + double const deviation = + com_std_fabs(com_std_sin(com_fix_as_float(sin_accumulator)) - + com_fix_as_float(sin)); + if (deviation > max_sin_deviation) + max_sin_deviation = deviation; + sin_accumulator += sin_test_step; + } + com_std_printf("max sin deviation: %f\n", max_sin_deviation); + } - // { - // double max_cos_deviation = 0.0f; - // com_fix_t cos_accumulator = -COM_FIX_PI * 4; - // com_fix_t cos_test_step = (COM_FIX_PI << 1) >> 10; - // for (int i = 0; i < 1024 * 32; ++i) { - // com_fix_t cos = com_fix_cos(cos_accumulator); - // double const deviation = - // com_std_fabs(com_std_cos(com_fix_as_float(cos_accumulator)) - - // com_fix_as_float(cos)); - // if (deviation > max_cos_deviation) - // max_cos_deviation = deviation; - // cos_accumulator += cos_test_step; - // } - // com_std_printf("max cos deviation: %f\n", max_cos_deviation); - // } + { + double max_cos_deviation = 0.0f; + com_fix_t cos_accumulator = -COM_FIX_PI * 4; + com_fix_t cos_test_step = (COM_FIX_PI << 1) >> 10; + for (int i = 0; i < 1024 * 32; ++i) { + com_fix_t cos = com_fix_cos(cos_accumulator); + double const deviation = + com_std_fabs(com_std_cos(com_fix_as_float(cos_accumulator)) - + com_fix_as_float(cos)); + if (deviation > max_cos_deviation) + max_cos_deviation = deviation; + cos_accumulator += cos_test_step; + } + com_std_printf("max cos deviation: %f\n", max_cos_deviation); + } - // { - // double max_sin_deviation = 0.0f; - // double max_cos_deviation = 0.0f; - // com_fix_t sincos_accumulator = -COM_FIX_PI * 4; - // com_fix_t sincos_test_step = (COM_FIX_PI << 1) >> 10; - // for (int i = 0; i < 1024 * 32; ++i) { - // com_fix_t sin, cos; - // com_fix_sincos(sincos_accumulator, &sin, &cos); - // double const sin_deviation = - // com_std_fabs(com_std_sin(com_fix_as_float(sincos_accumulator)) - - // com_fix_as_float(sin)); - // double const cos_deviation = - // com_std_fabs(com_std_cos(com_fix_as_float(sincos_accumulator)) - - // com_fix_as_float(cos)); - // if (sin_deviation > max_sin_deviation) - // max_sin_deviation = sin_deviation; - // if (cos_deviation > max_cos_deviation) - // max_cos_deviation = cos_deviation; - // sincos_accumulator += sincos_test_step; - // } - // com_std_printf("max sincos deviations: %f %f\n", max_sin_deviation, - // max_cos_deviation); - // } + { + double max_sin_deviation = 0.0f; + double max_cos_deviation = 0.0f; + com_fix_t sincos_accumulator = -COM_FIX_PI * 4; + com_fix_t sincos_test_step = (COM_FIX_PI << 1) >> 10; + for (int i = 0; i < 1024 * 32; ++i) { + com_fix_t sin, cos; + com_fix_sincos(sincos_accumulator, &sin, &cos); + double const sin_deviation = + com_std_fabs(com_std_sin(com_fix_as_float(sincos_accumulator)) - + com_fix_as_float(sin)); + double const cos_deviation = + com_std_fabs(com_std_cos(com_fix_as_float(sincos_accumulator)) - + com_fix_as_float(cos)); + if (sin_deviation > max_sin_deviation) + max_sin_deviation = sin_deviation; + if (cos_deviation > max_cos_deviation) + max_cos_deviation = cos_deviation; + sincos_accumulator += sincos_test_step; + } + com_std_printf("max sincos deviations: %f %f\n", max_sin_deviation, + max_cos_deviation); + } } diff --git a/Common/gem.h b/Common/gem.h index 46eee77..b94d7a0 100644 --- a/Common/gem.h +++ b/Common/gem.h @@ -5,13 +5,13 @@ #ifndef COM_GEM_H #define COM_GEM_H +#include "cfg.h" #include "fix.h" #include "mat.h" #include "pnt.h" #include "vec.h" #include "zord.h" #include -#include /* Projects vertex position to a clip space via reordered row-major MVP matrix. It skips calculation of z depth component, as we assume to never use it. @@ -24,10 +24,10 @@ static inline com_vec_t com_gem_vec_project_clip(com_mat_t a, com_vec_t b) { com_vec_t result; #define CASE(m_c, m_n) \ - result.a[m_c] = (((int64_t)a.a[m_n * 4 + 0] * b.a[0]) + \ - ((int64_t)a.a[m_n * 4 + 1] * b.a[1]) + \ - ((int64_t)a.a[m_n * 4 + 2] * b.a[2]) + a.a[m_n * 4 + 3]) >> \ - COM_FIX_FRACBITS; + result.a[m_c] = \ + ((com_fix_mul(a.a[m_n * 4 + 0], b.a[0])) + \ + (com_fix_mul(a.a[m_n * 4 + 1], b.a[1])) + \ + (com_fix_mul(a.a[m_n * 4 + 2], b.a[2])) + a.a[m_n * 4 + 3]); CASE(0, 0); CASE(1, 1); @@ -59,18 +59,18 @@ static inline uint8_t com_gem_clip_vis_project(com_vec_t a, com_pnt_t *out) { mask ^= COM_GEM_VERTEX_CLIPPED_Y; // out->a[0] = com_fix_mul((com_fix_div(a.a[0], a.a[2]) + COM_FIX_FRACUNIT) >> // 1, - // 640 * COM_FIX_FRACUNIT); + // COM_CFG_WIDTH * COM_FIX_FRACUNIT); // out->a[1] = com_fix_mul((com_fix_div(a.a[1], a.a[2]) + COM_FIX_FRACUNIT) >> // 1, - // 480 * COM_FIX_FRACUNIT); - out->a[0] = - (com_fix_mul(com_fix_div(a.a[0], a.a[2]), 640 * COM_FIX_FRACUNIT) >> - COM_FIX_FRACBITS) + - 320; - out->a[1] = - (com_fix_mul(com_fix_div(a.a[1], a.a[2]), 480 * COM_FIX_FRACUNIT) >> - COM_FIX_FRACBITS) + - 240; + // COM_CFG_HEIGHT * COM_FIX_FRACUNIT); + out->a[0] = (com_fix_mul(com_fix_div(a.a[0], a.a[2]), + COM_CFG_WIDTH * COM_FIX_FRACUNIT) >> + COM_FIX_FRACBITS) + + (COM_CFG_WIDTH / 2); + out->a[1] = (com_fix_mul(com_fix_div(a.a[1], a.a[2]), + COM_CFG_HEIGHT * COM_FIX_FRACUNIT) >> + COM_FIX_FRACBITS) + + (COM_CFG_HEIGHT / 2); return mask; } @@ -91,9 +91,9 @@ static inline void com_gem_draw_triangle(com_pnt_t v0, com_pnt_t v1, // If the point is inside or on all edges, draw the pixel // (Assumes Counter Clockwise vertex ordering) if (ws.a[0] >= 0 && ws.a[1] >= 0 && ws.a[2] >= 0) { - out[(y * 640 + x) * 4 + 0] = 125; - out[(y * 640 + x) * 4 + 1] = 125; - out[(y * 640 + x) * 4 + 2] = 125; + out[(y * COM_CFG_WIDTH + x) * 4 + 0] = 125; + out[(y * COM_CFG_WIDTH + x) * 4 + 1] = 125; + out[(y * COM_CFG_WIDTH + x) * 4 + 2] = 125; } } } @@ -145,7 +145,7 @@ com_gem_draw_triangle_textured_edge(com_pnt_t v0, com_pnt_t v1, com_pnt_t v2, // uint32_t idx = com_zord_order(tx, ty); uint32_t idx = ty * 32 + tx; // uint32_t bidx = com_zord_order(x, y); - uint32_t bidx = y * 640 + x; + uint32_t bidx = y * COM_CFG_WIDTH + x; out[bidx * 4 + 0] = tex[idx * 3 + 0]; out[bidx * 4 + 1] = tex[idx * 3 + 1]; @@ -169,7 +169,7 @@ static inline void draw_span(int32_t x_start_fp, int32_t x_end_fp, int y, for (int x = x1; x < x2; x++) { uint32_t idx = 0 * 32 + 0; - uint32_t bidx = y * 640 + x; + uint32_t bidx = y * COM_CFG_WIDTH + x; out[bidx * 4 + 0] = tex[idx * 3 + 0]; out[bidx * 4 + 1] = tex[idx * 3 + 1]; out[bidx * 4 + 2] = tex[idx * 3 + 2]; diff --git a/Common/mat.h b/Common/mat.h index 9834cc4..4b61c76 100644 --- a/Common/mat.h +++ b/Common/mat.h @@ -22,7 +22,7 @@ #include typedef struct { - com_def_alignedas(64) com_def_vector(com_fix_t, a, 4 * 4); + com_def_alignedas(64) com_def_vector(com_fix_t, a, 4 * 4 * sizeof(com_fix_t)); } com_mat_t; void com_mat_run_bench(void); @@ -30,7 +30,7 @@ void com_mat_run_bench(void); #define COM_MAT_PROFILE_SINK(m_m) \ do { \ for (int i = 0; i < 16; ++i) \ - COM_DEF_PROFILE_SINK((m_m).a[i]); \ + com_def_profile_sink((m_m).a[i]); \ } while (0) static inline com_mat_t com_mat_identity(void) { @@ -60,11 +60,10 @@ static inline com_mat_t com_mat_mul(com_mat_t a, com_mat_t b) { for (int c = 0; c < 4; ++c) { for (int r = 0; r < 4; ++r) { - result.a[r + c * 4] = (((int64_t)a.a[r + 0 * 4] * b.a[0 + c * 4]) + - ((int64_t)a.a[r + 1 * 4] * b.a[1 + c * 4]) + - ((int64_t)a.a[r + 2 * 4] * b.a[2 + c * 4]) + - ((int64_t)a.a[r + 3 * 4] * b.a[3 + c * 4])) >> - COM_FIX_FRACBITS; + result.a[r + c * 4] = ((com_fix_mul(a.a[r + 0 * 4], b.a[0 + c * 4])) + + (com_fix_mul(a.a[r + 1 * 4], b.a[1 + c * 4])) + + (com_fix_mul(a.a[r + 2 * 4], b.a[2 + c * 4])) + + (com_fix_mul(a.a[r + 3 * 4], b.a[3 + c * 4]))); } } @@ -80,11 +79,10 @@ static inline com_mat_t com_mat_mul_reodered(com_mat_t a, com_mat_t b) { for (int c = 0; c < 4; ++c) { for (int r = 0; r < 4; ++r) { - result.a[r + c * 4] = (((int64_t)a.a[0 + r * 4] * b.a[0 + c * 4]) + - ((int64_t)a.a[1 + r * 4] * b.a[1 + c * 4]) + - ((int64_t)a.a[2 + r * 4] * b.a[2 + c * 4]) + - ((int64_t)a.a[3 + r * 4] * b.a[3 + c * 4])) >> - COM_FIX_FRACBITS; + result.a[r + c * 4] = ((com_fix_mul(a.a[0 + r * 4], b.a[0 + c * 4])) + + (com_fix_mul(a.a[1 + r * 4], b.a[1 + c * 4])) + + (com_fix_mul(a.a[2 + r * 4], b.a[2 + c * 4])) + + (com_fix_mul(a.a[3 + r * 4], b.a[3 + c * 4]))); } } diff --git a/Common/pnt.h b/Common/pnt.h index 99088e0..e62d9c9 100644 --- a/Common/pnt.h +++ b/Common/pnt.h @@ -11,7 +11,7 @@ #include typedef struct { - com_def_alignedas(16) com_def_vector(com_fix_t, a, 2); + com_def_alignedas(16) com_def_vector(com_fix_t, a, 2 * sizeof(com_fix_t)); } com_pnt_t; static inline com_pnt_t com_pnt_from(com_fix_t x, com_fix_t y) { diff --git a/Common/std.h b/Common/std.h index 7e8bb14..93556fa 100644 --- a/Common/std.h +++ b/Common/std.h @@ -8,18 +8,35 @@ #include #include +#include +#if COM_DEF_TARGET == COM_DEF_TARGET_LINUX +#include + +static inline long com_std_syscall(long number, long arg1, long arg2, + long arg3) { + long ret; + __asm__ volatile("syscall" + : "=a"(ret) + : "a"(number), "D"(arg1), "S"(arg2), "d"(arg3) + : "rcx", "r11", "memory"); + return ret; +} +#endif + +/* TODO: Remove, use buffer semantics instead. */ /* Note: Freeing is done by passing 0 size to pointer. */ -extern void *com_std_alloc(void *ptr, size_t size); +void *com_std_alloc(void *ptr, size_t size); /* Note: Functions listed below are only available for dev builds. */ /* Trigonometry functions are for reference testing of our own fixed point * implementations. Do not use otherwise. */ -extern void com_std_assert(bool holds); -extern void com_std_printf(char const *fmt, ...); -extern double com_std_sqrt(double v); -extern double com_std_fabs(double v); -extern double com_std_sin(double v); -extern double com_std_cos(double v); +void com_std_assert(bool holds); +void com_std_printf(char const *fmt, ...); +void com_std_print_str(char const *str, uint32_t len, bool newline); +double com_std_sqrt(double v); +double com_std_fabs(double v); +double com_std_sin(double v); +double com_std_cos(double v); #endif diff --git a/Common/str.h b/Common/str.h new file mode 100644 index 0000000..3e63125 --- /dev/null +++ b/Common/str.h @@ -0,0 +1,61 @@ +/* + Routines for string processing. + + *_ext_* functions are provided for foreign strings we're not in control of. +*/ + +#ifndef COM_STR_H +#define COM_STR_H + +#include "def.h" +#include +#include + +#define COM_STR_GROWABLE (1 << 0) /* Data can grow and be reallocated. */ +#define COM_STR_STACK (1 << 1) /* Stack residing. */ +#define COM_STR_SUB (1 << 2) /* Substring of an existing one. */ +#define COM_STR_NULL_TERMINATED (1 << 3) /* Whether there's NULL at last. */ + +/* Internal strings are assumed to have vectorizable alignment. */ +/* Instead of growing strings on joining we implement ropes. */ +typedef struct com_str { + struct com_str *next; + /* Actual size is +1, to fit NULL terminator. */ + uint32_t len; + uint32_t flags; + char data[] __attribute__((aligned(COM_DEF_ALIGNMENT))); + +} com_str; + +/* NOTE: Have to be moved to static or global memory. */ +#define com_str_lit(p_l) {NULL, sizeof(p_l) - 1, COM_STR_NULL_TERMINATED, (p_l)} + +static inline uint32_t com_str_ext_len(char const *s) { + char const *p = s; + for (; *p != 0; ++p) { + } + return p - s; +} + +/* Returns index of a char or -1 if it's not found. */ +static inline int32_t com_str_ext_find_char(char const *s, char ch) { + for (char const *p = s; *p != 0; ++p) + if (*p == ch) + return p - s; + return -1; +} + +/* Returns true if string 'a' is prefixed by 'b'. */ +static inline bool com_str_ext_prefixed(char const *__restrict a, + struct com_str prefix) { + uint32_t n = prefix.len; + char *b = prefix.data; + while (n && *a && (*a == *b)) { + ++a; + ++b; + --n; + } + return n == 0; +} + +#endif diff --git a/Common/vec.h b/Common/vec.h index 241e932..789d0db 100644 --- a/Common/vec.h +++ b/Common/vec.h @@ -12,7 +12,7 @@ #include typedef struct { - com_def_alignedas(16) com_def_vector(com_fix_t, a, 3); + com_def_alignedas(16) com_def_vector(com_fix_t, a, 4 * sizeof(com_fix_t)); } com_vec_t; static inline com_vec_t com_vec_from(com_fix_t x, com_fix_t y, com_fix_t z) { @@ -63,20 +63,17 @@ static inline com_vec_t com_vec_scl(com_vec_t a, com_fix_t b) { /* Resulted range depends on input, it's in -1 to 1 for normalized * input and otherwise is -ab to +ab */ static inline com_fix_t com_vec_dot(com_vec_t a, com_vec_t b) { - return (((int64_t)a.a[0] * b.a[0]) + ((int64_t)a.a[1] * b.a[1]) + - ((int64_t)a.a[2] * b.a[2])) >> - COM_FIX_FRACBITS; + return ((com_fix_mul(a.a[0], b.a[0])) + (com_fix_mul(a.a[1], b.a[1])) + + (com_fix_mul(a.a[2], b.a[2]))); } /* Cross product produces a perpendicular for normalized vectors, or 0 for * parallel vectors */ static inline com_vec_t com_vec_crs(com_vec_t a, com_vec_t b) { - int64_t const cx = ((int64_t)a.a[1] * b.a[2]) - ((int64_t)a.a[2] - b.a[1]); - int64_t const cy = ((int64_t)a.a[2] * b.a[0]) - ((int64_t)a.a[0] - b.a[2]); - int64_t const cz = ((int64_t)a.a[0] * b.a[1]) - ((int64_t)a.a[1] - b.a[0]); - return (com_vec_t){.a = {(com_fix_t)(cx >> COM_FIX_FRACBITS), - (com_fix_t)(cy >> COM_FIX_FRACBITS), - (com_fix_t)(cz >> COM_FIX_FRACBITS)}}; + return (com_vec_t){ + .a = {(com_fix_mul(a.a[1], b.a[2])) - (com_fix_mul(a.a[2], b.a[1])), + (com_fix_mul(a.a[2], b.a[0])) - (com_fix_mul(a.a[0], b.a[2])), + (com_fix_mul(a.a[0], b.a[1])) - (com_fix_mul(a.a[1], b.a[0]))}}; } /* Normalize vector, making it a unit one (of length 1). */ diff --git a/Player/Display/display.h b/Player/Display/display.h index 6af90a3..f815f52 100644 --- a/Player/Display/display.h +++ b/Player/Display/display.h @@ -1,7 +1,7 @@ #ifndef PLR_DISPLAY_H #define PLR_DISPLAY_H -extern int plr_display_x11_main(int argc, char *argv[]); +__attribute__((used)) extern int plr_display_x11_main(int argc, char *argv[]); extern int plr_display_dos_main(int argc, char *argv[]); #endif diff --git a/Player/Display/x11.c b/Player/Display/x11.c index e262541..d06dd5a 100644 --- a/Player/Display/x11.c +++ b/Player/Display/x11.c @@ -1,22 +1,79 @@ #include #include #include +#include #include #include +#include +#include +#include "../../Common/bin.h" +#include "../../Common/buf.h" +#include "../../Common/cfg.h" #include "../../Common/lzw.h" #include "../../Common/mat.h" #include "../../Common/std.h" +#include "../../Common/str.h" #include "../draw.h" #include "display.h" /* https://hereket.com/posts/from-scratch-x11-windowing/ */ +/* https://gaultier.github.io/blog/write_a_video_game_from_scratch_like_1987.html + */ bool quited = false; -/* TODO: Have a cfg.h configuration header setting those. */ -#define WIDTH 640 -#define HEIGHT 480 +bool fileread(void *ctx, char *into, uint32_t bytes) { + return com_std_syscall(0, (intptr_t)ctx, (intptr_t)into, bytes); +} + +bool fileskip(void *ctx, uint32_t bytes) { + return com_std_syscall(8, (intptr_t)ctx, bytes, 1) >= 0; +} + +static struct plr_x11_auth_entry { + uint16_t family; + struct com_buf *auth_name; + struct com_buf *auth_data; + bool success; +} plr_x11_read_auth_entry(struct com_bin *b, struct com_buf *buf) { + struct plr_x11_auth_entry result = {0}; + + if (!com_bin_read_u16(b, &result.family)) { + com_std_printf("Failure to initialize X11\n"); + goto BREAK; + } + uint16_t addres_len; + if (!com_bin_read_u16(b, &addres_len)) + goto BREAK; + if (!com_bin_skip(b, addres_len)) + goto BREAK; + uint16_t display_len; + if (!com_bin_read_u16(b, &display_len)) + goto BREAK; + if (!com_bin_skip(b, display_len)) + goto BREAK; + uint16_t name_len; + if (!com_bin_read_u16(b, &name_len)) + goto BREAK; + uint32_t name_idx; + if (!com_bin_read_bufbi(b, buf, &name_idx, name_len)) + goto BREAK; + uint16_t data_len; + if (!com_bin_read_u16(b, &data_len)) + goto BREAK; + uint32_t data_idx; + if (!com_bin_read_bufbi(b, buf, &data_idx, name_len)) + goto BREAK; + + result.auth_name = com_buf_index(struct com_buf, buf, name_idx); + result.auth_data = com_buf_index(struct com_buf, buf, data_idx); + result.success = true; + return result; +BREAK: + com_std_printf("Failure to initialize X11\n"); + return result; +} // TODO: correct error handling. extern int plr_display_x11_main(int argc, char *argv[]) { @@ -43,9 +100,61 @@ extern int plr_display_x11_main(int argc, char *argv[]) { // com_vec_t v0 = com_mat_vec_project(com_mat_reoder(m0), com_vec_identity()); // com_fix_print(v0.a[0]); - com_fix_run_tests(); - com_fix_run_bench(); - com_mat_run_bench(); + // com_fix_run_tests(); + // com_fix_run_bench(); + // com_mat_run_bench(); + + /* TODO: Move init to separate func. */ + /* Open X11 socket for communication. */ + int const xfd = com_std_syscall(41, AF_UNIX, SOCK_STREAM, 0); + if (xfd < 0) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } + + struct sockaddr_un const addr = {.sun_family = AF_UNIX, + .sun_path = "/tmp/.X11-unix/X0"}; + if (com_std_syscall(42, xfd, (intptr_t)&addr, sizeof addr)) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } + + /* First we need to authenticate X11 connection, which requires some funk. */ + /* We assume that $XAUTHORITY is set and I hope it is true. */ + char *xauthpath = NULL; + for (char **envp = &argv[argc + 1]; *envp != NULL; ++envp) { + static const struct com_str xauthlit = com_str_lit("XAUTHORITY="); + if (com_str_ext_prefixed(*envp, xauthlit)) { + xauthpath = &((*envp)[xauthlit.len]); + break; + } + } + + /* Open it and parse. */ + int const xauthfd = com_std_syscall(2, (intptr_t)xauthpath, O_RDONLY, 0); + if (xauthfd < 0) { + com_std_printf("Failure to initialize X11\n"); + return -1; + } + + com_buf_make_on_stack(char, xauthbuf, 1024, 0); + struct com_bin xauthbin = { + .ctx = (void *)(int64_t)xauthfd, + .flags = COM_BIN_BIG_ENDIAN, + .interface = {.readn = fileread, .skipn = fileskip}}; + + struct plr_x11_auth_entry auth_entry = + plr_x11_read_auth_entry(&xauthbin, xauthbuf); + + com_std_print_str(auth_entry.auth_name->data, auth_entry.auth_name->len, + true); + com_std_print_str(auth_entry.auth_data->data, auth_entry.auth_data->len, + true); + + com_buf_free(xauthbuf); + + char sendbuf[16 * 1024] = {}; + char readbuf[16 * 1024] = {}; // Display *display = XOpenDisplay(NULL); // if (NULL == display) { @@ -90,13 +199,13 @@ extern int plr_display_x11_main(int argc, char *argv[]) { // GC gc = XCreateGC(display, window, 0, NULL); - // Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False); - // XSetWMProtocols(display, window, &wm_delete_window, 1); + // Atom wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", + // False); XSetWMProtocols(display, window, &wm_delete_window, 1); // // TODO: can't be not true // int bytes_per_pixel = 4; - // // char *pixel_buffer = (char *)malloc(WIDTH * HEIGHT * bytes_per_pixel); - // char pixel_buffer[WIDTH * HEIGHT * bytes_per_pixel]; + // // char *pixel_buffer = (char *)malloc(WIDTH * HEIGHT * + // bytes_per_pixel); char pixel_buffer[WIDTH * HEIGHT * bytes_per_pixel]; // XImage *ximage = XCreateImage(display, visual, depth, ZPixmap, 0, // pixel_buffer, WIDTH, HEIGHT, 32, 0); diff --git a/Player/Main/libc.c b/Player/Main/libc.c new file mode 100644 index 0000000..9669a80 --- /dev/null +++ b/Player/Main/libc.c @@ -0,0 +1,3 @@ +#include "../Display/display.h" + +extern int main(int argc, char **argv) { plr_display_x11_main(argc, argv); } diff --git a/Player/Main/linux.c b/Player/Main/linux.c index bc60502..209bb56 100644 --- a/Player/Main/linux.c +++ b/Player/Main/linux.c @@ -1,15 +1,13 @@ -#include "../Display/display.h" -__attribute__((force_align_arg_pointer)) __attribute__((noreturn)) extern void +/* No libc starting point. Jump straight into action! */ +__attribute__((naked)) __attribute__((force_align_arg_pointer)) +__attribute__((noreturn)) extern void _start(void) { - - plr_display_x11_main(0, 0); - - __asm__ volatile("mov $60, %%rax\n\t" - "xor %%rdi, %%rdi\n\t" - "syscall" - : - : - : "%rax", "%rdi"); - __builtin_unreachable(); + __asm__ volatile("xor %rbp, %rbp\n" + "movq (%rsp), %rdi\n" + "leaq 8(%rsp), %rsi\n" + "call plr_display_x11_main\n" + "movq %rax, %rdi\n" + "movq $60, %rax\n" + "syscall"); } diff --git a/Player/Makefile b/Player/Makefile index 1b27d1c..d9ccf35 100644 --- a/Player/Makefile +++ b/Player/Makefile @@ -1,6 +1,37 @@ CC = clang -# todo: Only link to libm on debug. -CFLAGS = -Wall -std=c99 -g3 -O3 -flto=full +RELEASE ?= 0 +SQUEEZE ?= 0 +BITS ?= 64 +CFLAGS = -Wall -std=gnu99 -flto=thin -ffast-math -fno-ident -fvisibility=hidden +ifeq ($(MAKECMDGOALS),linux) + ifeq ($(RELEASE), 1) + CFLAGS += -Wl,--ignore-data-address-equality -Wl,--ignore-function-address-equality \ + -Wl,--optimize-bb-jumps + endif + ifeq ($(SQUEEZE), 1) + CFLAGS += -Wl,-T,tiny.ld -Wl,--icf=all -Wl,--bp-compression-sort=both \ + -Wl,--nmagic + endif + ifeq ($(BITS), 64) + CFLAGS += -m64 -march=x86-64-v3 -mpopcnt + else + CFLAGS += -m32 -msse2 + endif +endif +ifeq ($(MAKECMDGOALS),wasm) + ifeq ($(RELEASE), 1) + CFLAGS += -Wl,--compress-relocations + endif +endif +ifeq ($(RELEASE), 0) + CFLAGS += -g3 -O1 +else + CFLAGS += -Wl,--strip-all -DNDEBUG -O3 -fuse-ld=lld -fmerge-all-constants -Wl,-O3 \ + -ffunction-sections -fdata-sections -Wl,--gc-sections \ + -Wl,-mllvm,--vectorize-slp=true \ + -Wl,-mllvm,--enable-gvn-hoist=true +endif +# TODO: Just use amalgam build for all? DEPS = ../Common/lzw.h ../Common/mat.h ../Common/vec.h ../Common/fix.h ../Common/def.h ../Common/bits.h \ ../Common/gem.h \ ../Common/Timer/time.h \ @@ -15,12 +46,12 @@ DOS = maindos.c Display/dos.c $(CC) -c -o $@ $< $(CFLAGS) # TODO: Make it work with no stdlib. -linux: CFLAGS += -msse2 -mbmi2 -nostdlib +linux: CFLAGS += -static -mbmi2 -nostdlib linux: $(LINUX) | $(SRC) $(CC) -o player $^ $(CFLAGS) # Note: lld package might need to be downloaded. -wasm: CFLAGS += --target=wasm32 -nostdlib -Wl,--no-entry -msimd128 +wasm: CFLAGS += --target=wasm32 -nostdlib -Wl,--no-entry -msimd128 -mbulk-memory wasm: $(CC) -o player.wasm $(WASM) $(CFLAGS) diff --git a/Player/amalgam.c b/Player/amalgam.c index 8b91c7b..c4a04ef 100644 --- a/Player/amalgam.c +++ b/Player/amalgam.c @@ -2,6 +2,8 @@ Amalgamation file, compiling all in single unit. */ +#include "../Common/bin.c" +#include "../Common/buf.c" #include "../Common/def.h" #include "../Common/fix.c" #include "../Common/lzw.c" @@ -14,6 +16,8 @@ #include "../Common/Timer/stub.c" #include "./Display/x11.c" #include "./Main/linux.c" +// #include "./Main/libc.c" #elif COM_DEF_TARGET == COM_DEF_TARGET_WASM #include "../Common/Std/stub.c" +#include "../Common/Timer/stub.c" #endif diff --git a/Player/draw.c b/Player/draw.c index f1b9e23..9458854 100644 --- a/Player/draw.c +++ b/Player/draw.c @@ -1,4 +1,5 @@ +#include "../Common/cfg.h" #include "../Common/def.h" #include "../Common/gem.h" #include "../Common/std.h" @@ -6,7 +7,7 @@ #include #if COM_DEF_TARGET == COM_DEF_TARGET_WASM -uint8_t plr_draw_buffer[640 * 480 * 4]; +uint8_t plr_draw_buffer[COM_CFG_WIDTH * COM_CFG_HEIGHT * 4]; com_def_export_sym( "plr_draw_get_pixel_buffer") uint8_t *plr_draw_get_pixel_buffer(void) { @@ -16,9 +17,9 @@ com_def_export_sym( com_def_export_sym("plr_draw_screen") void plr_draw_screen( uint8_t *pixel_buffer) { - for (int y = 0; y < 480; y++) { - for (int x = 0; x < 640; x++) { - int pixel_index = (y * 640 + x) * 4; + for (int y = 0; y < COM_CFG_HEIGHT; y++) { + for (int x = 0; x < COM_CFG_WIDTH; x++) { + int pixel_index = (y * COM_CFG_WIDTH + x) * 4; // Assuming standard Little-Endian 32-bit BGRA format pixel_buffer[pixel_index + 0] = (x) % 256; // Blue @@ -28,8 +29,8 @@ com_def_export_sym("plr_draw_screen") void plr_draw_screen( } } - com_mat_t proj = - com_mat_perspective(640, 480, 1, 100 * COM_FIX_FRACUNIT, COM_FIX_PIHALF); + com_mat_t proj = com_mat_perspective(COM_CFG_WIDTH, COM_CFG_HEIGHT, 1, + 100 * COM_FIX_FRACUNIT, COM_FIX_PIHALF); com_mat_t view = com_mat_look_at(com_vec_from(0, 0, 0), com_vec_from(0, COM_FIX_FRACUNIT, 0), com_vec_from(-COM_FIX_FRACUNIT, 0, 0)); diff --git a/Player/index.html b/Player/index.html index 2547474..4c5d43a 100644 --- a/Player/index.html +++ b/Player/index.html @@ -1,4 +1,5 @@ + @@ -16,6 +17,8 @@ const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); + // TODO: Throttle FPS. + async function main() { const wasm = await WebAssembly.instantiateStreaming(fetch("player.wasm")); const { memory, plr_draw_screen, plr_draw_get_pixel_buffer } = wasm.instance.exports; @@ -24,7 +27,7 @@ const wasmBuffer = new Uint8ClampedArray( memory.buffer, bufferPtr, - 640 * 480 * 4 + 640 * 480 * 4 // TODO: Retrieve actual values. ); const imgData = new ImageData(wasmBuffer, 640, 480); diff --git a/Player/tiny.ld b/Player/tiny.ld new file mode 100644 index 0000000..bf39ff0 --- /dev/null +++ b/Player/tiny.ld @@ -0,0 +1,48 @@ +OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64") +OUTPUT_ARCH(i386:x86-64) +ENTRY(_start) + +PHDRS +{ + text PT_LOAD FLAGS(5); /* RX: Read/Execute */ +} + +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); + . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + + .text ALIGN(16) : { + *(.text*) + } + + .rodata : { + *(.rodata*) + } + + .data : { + *(.data*) + } + + .bss : { + *(.bss*) + *(COMMON) + } + + /* Discard bloat and unnecessary ELF sections */ + /DISCARD/ : { + *(.note.GNU-stack) + *(.gnu_debuglink) + *(.gnu.lto_*) + *(.note.gnu.build-id) + *(.eh_frame_hdr) + *(.eh_frame_entry) + *(.eh_frame) + *(.comment) + *(.interp) + *(.dynsym) + *(.dynstr) + *(.hash) + *(.gnu.hash) + } +}