some progress
This commit is contained in:
+20
-15
@@ -1,16 +1,8 @@
|
||||
#include "../def.h"
|
||||
#include "../std.h"
|
||||
#include "../str.h"
|
||||
#include <stdarg.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
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 <stdint.h>
|
||||
|
||||
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);
|
||||
// };
|
||||
|
||||
@@ -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);
|
||||
// };
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#include "time.h"
|
||||
#include "../time.h"
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t com_timer_count_ns(void) { return 0; }
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Generic interface for binary data parsing.
|
||||
*/
|
||||
|
||||
#ifndef COM_BIN_H
|
||||
#define COM_BIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
+19
-14
@@ -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
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "buf.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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) {}
|
||||
@@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
+34
-14
@@ -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
|
||||
|
||||
+76
-84
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -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 <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* 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];
|
||||
|
||||
+10
-12
@@ -22,7 +22,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
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])));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
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) {
|
||||
|
||||
+24
-7
@@ -8,18 +8,35 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#if COM_DEF_TARGET == COM_DEF_TARGET_LINUX
|
||||
#include <sys/syscall.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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 <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
+7
-10
@@ -12,7 +12,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
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). */
|
||||
|
||||
Reference in New Issue
Block a user