summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2025-04-26 02:10:48 +0200
committerMitya Selivanov <automainint@guattari.tech>2025-04-26 02:10:48 +0200
commit72b9fc8c1515c12600513fd9759f9b9034825726 (patch)
tree130972ec171ced5d68cd13a493f185cfd4b4a52d
parent8a4b4bed8259397c6d958766573a0bfa25909b98 (diff)
downloadreduced_system_layer-72b9fc8c1515c12600513fd9759f9b9034825726.zip
Pixels scaling tests and perf
-rw-r--r--graphics.c451
-rwxr-xr-xrun_tests.c2
-rw-r--r--runtime.c173
-rw-r--r--stackless_coroutine.c16
4 files changed, 564 insertions, 78 deletions
diff --git a/graphics.c b/graphics.c
index 5632712..a63f622 100644
--- a/graphics.c
+++ b/graphics.c
@@ -164,9 +164,9 @@ typedef struct {
//
// ================================================================
-Box font_text_area_dispatch(i32 font, vec2 scale, i64 num_chars, c32 *text);
+Box dispatch_font_text_area(i32 font, vec2 scale, i64 num_chars, c32 *text);
-void font_render_to_stencil_dispatch(Stencil_Buffer dst, i32 font, vec2 position, vec2 scale, i64 num_chars, c32 *text);
+void dispatch_font_render_to_stencil(Stencil_Buffer dst, i32 font, vec2 position, vec2 scale, i64 num_chars, c32 *text);
// ================================================================
@@ -431,8 +431,8 @@ vec3_f32 lch_mix(vec3_f32 a, vec3_f32 b, f32 t) {
vec3_f32 lch_lerp(vec3_f32 a, vec3_f32 b, f32 t) {
f32 delta_hue = b.z - a.z;
- if (delta_hue > M_PI) delta_hue -= M_PI * 2;
- if (delta_hue < -M_PI) delta_hue += M_PI * 2;
+ if (delta_hue > M_PI) delta_hue -= M_PI * 2.0;
+ if (delta_hue < -M_PI) delta_hue += M_PI * 2.0;
return (vec3_f32) {
.x = a.x + (b.x - a.x) * t,
@@ -442,9 +442,9 @@ vec3_f32 lch_lerp(vec3_f32 a, vec3_f32 b, f32 t) {
}
u32 rgb_u32_from_f32(vec3_f32 color) {
- i32 ir = (i32) floor(color.x * 255. + .5);
- i32 ig = (i32) floor(color.y * 255. + .5);
- i32 ib = (i32) floor(color.z * 255. + .5);
+ i32 ir = (i32) floor(color.x * 255.0 + 0.5);
+ i32 ig = (i32) floor(color.y * 255.0 + 0.5);
+ i32 ib = (i32) floor(color.z * 255.0 + 0.5);
u32 r = ir < 0 ? 0u : ir > 255 ? 255u : (u32) ir;
u32 g = ig < 0 ? 0u : ig > 255 ? 255u : (u32) ig;
@@ -455,17 +455,17 @@ u32 rgb_u32_from_f32(vec3_f32 color) {
vec3_f32 rgb_f32_from_u32(u32 color) {
return (vec3_f32) {
- .x = ((color & 0xff0000) >> 16) / 255.f,
- .y = ((color & 0x00ff00) >> 8) / 255.f,
- .z = (color & 0x0000ff) / 255.f,
+ .x = ((color & 0xff0000) >> 16) / 255.0f,
+ .y = ((color & 0x00ff00) >> 8) / 255.0f,
+ .z = (color & 0x0000ff) / 255.0f,
};
}
u32 rgba_u32_from_f32(vec4_f32 color) {
- i32 ir = (i32) floor(color.x * 255. + .5);
- i32 ig = (i32) floor(color.y * 255. + .5);
- i32 ib = (i32) floor(color.z * 255. + .5);
- i32 ia = (i32) floor(color.w * 255. + .5);
+ i32 ir = (i32) floor(color.x * 255.0 + 0.5);
+ i32 ig = (i32) floor(color.y * 255.0 + 0.5);
+ i32 ib = (i32) floor(color.z * 255.0 + 0.5);
+ i32 ia = (i32) floor(color.w * 255.0 + 0.5);
u32 r = ir < 0 ? 0u : ir > 255 ? 255u : (u32) ir;
u32 g = ig < 0 ? 0u : ig > 255 ? 255u : (u32) ig;
@@ -477,10 +477,10 @@ u32 rgba_u32_from_f32(vec4_f32 color) {
vec4_f32 rgba_f32_from_u32(u32 color) {
return (vec4_f32) {
- .x = ((color & 0x00ff0000) >> 16) / 255.f,
- .y = ((color & 0x0000ff00) >> 8) / 255.f,
- .z = (color & 0x000000ff) / 255.f,
- .w = ((color & 0xff000000) >> 24) / 255.f,
+ .x = ((color & 0x00ff0000) >> 16) / 255.0f,
+ .y = ((color & 0x0000ff00) >> 8) / 255.0f,
+ .z = (color & 0x000000ff) / 255.0f,
+ .w = ((color & 0xff000000) >> 24) / 255.0f,
};
}
@@ -621,30 +621,31 @@ void draw_pixels_to_buffer(Pixel_Buffer dst, Box area, Pixel_Buffer src) {
PROFILER_begin(PROFILE_DRAW_PIXELS);
- i64 i0 = (i64) floor(area.x + 0.5);
- i64 i1 = (i64) floor(area.x + area.width + 0.5);
- i64 j0 = (i64) floor(area.y + 0.5);
- i64 j1 = (i64) floor(area.y + area.height + 0.5);
+ i64 x0 = (i64) floor(area.x + 0.5);
+ i64 x1 = (i64) floor(area.x + area.width + 0.5);
+ i64 y0 = (i64) floor(area.y + 0.5);
+ i64 y1 = (i64) floor(area.y + area.height + 0.5);
- if (i0 < 0) i0 = 0;
- if (i1 > dst.width) i1 = dst.width;
- if (j0 < 0) j0 = 0;
- if (j1 > dst.height) j1 = dst.height;
+ i64 i0 = max2_i64_(x0, 0);
+ i64 i1 = min2_i64_(x1, dst.width);
+ i64 j0 = max2_i64_(y0, 0);
+ i64 j1 = min2_i64_(y1, dst.height);
+
+ u32 x_ratio = (src.width << 16) / (x1 - x0);
+ u32 y_ratio = (src.height << 16) / (y1 - y0);
- // FIXME, PERF: Use integer arithmetic.
+ u32 x_half = x_ratio / 2;
+ u32 y_half = y_ratio / 2;
- f64 di = src.width / area.width;
- f64 dj = src.height / area.height;
- f64 jj = (j0 - area.y) * dj + dj * .5;
- for (i64 j = j0; j < j1; ++j, jj += dj) {
- if (jj < 0 || jj >= src.height) continue;
+ for (i64 j = j0; j < j1; ++j) {
+ u32 src_j = ((j - y0) * y_ratio + y_half) >> 16;
vec4_f32 *d = dst.pixels + j * dst.stride + i0;
- vec4_f32 *d_end = d + i1 - i0;
- vec4_f32 *s = src.pixels + (i64) jj * src.stride;
- f64 ii = (i0 - area.x) * di + di * .5;
- if (ii < 0 || ii >= src.width) continue;
- for (; d < d_end; ++d, ii += di)
- put_pixel_(d, s[(i64) ii]);
+ vec4_f32 *d_end = d + (i1 - i0);
+ vec4_f32 *s = src.pixels + src_j * src.stride;
+ for (u32 i = i0 - x0; d < d_end; ++d, ++i) {
+ u32 src_i = (i * x_ratio + x_half) >> 16;
+ put_pixel_(d, s[src_i]);
+ }
}
PROFILER_end(PROFILE_DRAW_PIXELS);
@@ -1223,8 +1224,8 @@ static void lcd_draw_text_(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64
}
}
-#if !defined(GRAPHICS_ENABLE_FONT_CUSTOM_DISPATCH)
-Box font_text_area_dispatch(i32 font, vec2 scale, i64 num_chars, c32 *text) {
+#if !defined(ENABLE_FONT_CUSTOM_DISPATCH)
+Box dispatch_font_text_area(i32 font, vec2 scale, i64 num_chars, c32 *text) {
// TODO
(void) font;
@@ -1235,7 +1236,7 @@ Box font_text_area_dispatch(i32 font, vec2 scale, i64 num_chars, c32 *text) {
return (Box) {0};
}
-void font_render_to_stencil_dispatch(Stencil_Buffer dst, i32 font, vec2 position, vec2 scale, i64 num_chars, c32 *text) {
+void dispatch_font_render_to_stencil(Stencil_Buffer dst, i32 font, vec2 position, vec2 scale, i64 num_chars, c32 *text) {
// TODO
(void) dst;
@@ -1245,7 +1246,7 @@ void font_render_to_stencil_dispatch(Stencil_Buffer dst, i32 font, vec2 position
(void) num_chars;
(void) text;
}
-#endif // !defined(GRAPHICS_ENABLE_FONT_CUSTOM_DISPATCH)
+#endif // !defined(ENABLE_FONT_CUSTOM_DISPATCH)
void draw_text_area_to_buffer(Pixel_Buffer dst, i32 font, vec4_f32 color, Box area, vec2 max_size, i64 num_chars, c32 *text) {
(void) font;
@@ -3058,6 +3059,372 @@ TEST("text selection backward") {
REQUIRE(ok);
}
+TEST("scale down exact") {
+ vec4_f32 src[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[4];
+
+ vec4_f32 expect[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = dst, },
+ (Box) { .x = 0.0, .y = 0.0, .width = 2.0, .height = 2.0, },
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 4; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale down aliasing overflow") {
+ vec4_f32 src[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[4];
+
+ vec4_f32 expect[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = dst, },
+ (Box) { .x = 0.4, .y = 0.4, .width = 2.0, .height = 2.0, },
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 4; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale down aliasing underflow") {
+ vec4_f32 src[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[4];
+
+ vec4_f32 expect[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = dst, },
+ (Box) { .x = -0.4, .y = -0.4, .width = 2.0, .height = 2.0, },
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 4; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale down aliasing middle") {
+ vec4_f32 src[9] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 1.0, 1.0 },
+ { 1.0, 0.0, 1.0, 1.0 },
+
+ { 1.0, 0.0, 0.5, 1.0 },
+ { 0.5, 1.0, 0.0, 1.0 },
+ { 0.0, 0.5, 1.0, 1.0 },
+ };
+
+ vec4_f32 dst[1];
+
+ vec4_f32 expect[1] = {
+ { 0.0, 1.0, 1.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 1, .height = 1, .stride = 1, .pixels = dst, },
+ (Box) { .x = 0.0, .y = 0.0, .width = 1.0, .height = 1.0, },
+ (Pixel_Buffer) { .width = 3, .height = 3, .stride = 3, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 1; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale up exact") {
+ vec4_f32 src[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[16];
+
+ vec4_f32 expect[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = dst, },
+ (Box) { .x = 0.0, .y = 0.0, .width = 4.0, .height = 4.0, },
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 16; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale up aliasing overflow") {
+ vec4_f32 src[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[16];
+
+ vec4_f32 expect[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = dst, },
+ (Box) { .x = 0.4, .y = 0.4, .width = 4.0, .height = 4.0, },
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 16; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
+TEST("scale up aliasing underflow") {
+ vec4_f32 src[4] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ vec4_f32 dst[16];
+
+ vec4_f32 expect[16] = {
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 1.0, 0.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+ { 0.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 0.0, 0.0, 1.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ { 1.0, 1.0, 0.0, 1.0 },
+ };
+
+ draw_pixels_to_buffer(
+ (Pixel_Buffer) { .width = 4, .height = 4, .stride = 4, .pixels = dst, },
+ (Box) { .x = -0.4, .y = -0.4, .width = 4.0, .height = 4.0, },
+ (Pixel_Buffer) { .width = 2, .height = 2, .stride = 2, .pixels = src, }
+ );
+
+ // for (i64 i = 0; i < (i64) (sizeof dst / sizeof *dst); ++i) {
+ // printf("%g, %g, %g, %g \n", dst[i].x, dst[i].y, dst[i].z, dst[i].w);
+ // }
+
+ b8 ok = 1;
+
+ for (i64 i = 0; i < 16; ++i)
+ ok = ok && dst[i].x == expect[i].x
+ && dst[i].y == expect[i].y
+ && dst[i].z == expect[i].z
+ && dst[i].w == expect[i].w;
+
+ REQUIRE(ok);
+}
+
#undef TEST_FILE
#endif // ENABLE_TESTING
diff --git a/run_tests.c b/run_tests.c
index 0729304..5acfe45 100755
--- a/run_tests.c
+++ b/run_tests.c
@@ -10,7 +10,7 @@ gcc \
-Wno-unused-variable \
-Wno-unused-but-set-variable \
-Wno-unused-function \
- -O3 -D NDEBUG \
+ -g \
-lm \
-fsanitize=undefined,address,leak \
-o $BIN $SRC && \
diff --git a/runtime.c b/runtime.c
index a00e301..144fbc2 100644
--- a/runtime.c
+++ b/runtime.c
@@ -730,6 +730,7 @@ void resize_dynamic_array_exact(i64 *num, void **data, i64 element_size, i64 new
void resize_dynamic_array_capacity(i64 *num, i64 *capacity, void **data, i64 element_size, i64 new_num);
#ifdef RUNTIME_HEADER
+// NOTE: Platform is a global object because we can't create multiple windows on Web.
extern Platform g_platform;
#endif
@@ -776,14 +777,21 @@ enum {
//
// ================================================================
-static void mem_set_(void *dst, u8 x, i64 size) {
- for (i64 i = 0; i < size; ++i)
- ((u8 *) dst)[i] = x;
+static void mem_set_(void *dst, u8 x, i64 len) {
+ u8 *d = (u8 *) dst;
+ u8 *d_end = d + len;
+
+ for (; d < d_end; ++d)
+ *d = x;
}
-static void mem_cpy_(void *dst, void *src, i64 size) {
- for (i64 i = 0; i < size; ++i)
- ((u8 *) dst)[i] = ((u8 *) src)[i];
+static void mem_cpy_(void *dst, void *src, i64 len) {
+ u8 *s = (u8 *) src;
+ u8 *d = (u8 *) dst;
+ u8 *d_end = d + len;
+
+ for (; d < d_end; ++s, ++d)
+ *d = *s;
}
static i32 min2_i32_(i32 x, i32 y) {
@@ -926,6 +934,10 @@ void log_impl(i32 mode, i32 file_len, c8 const *file, i32 line, i32 func_len, c8
//
// BLAKE2B
//
+// TODO:
+// - Check correctness for arguments.
+// - Change API to be similar to other procs.
+//
// ================================================================
enum blake2b_constant {
@@ -967,17 +979,17 @@ static u64 blake2b_IV[8] = {
};
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 } ,
+ { 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 }
};
@@ -2088,13 +2100,14 @@ static void store_clipboard_text_(i64 size, c8 *data) {
// ================================================================
//
+// PLATFORM-SPECIFIC CODE
+//
+// ================================================================
+//
// Dynamic libraries
//
// ================================================================
-#if defined(__unix__)
-#include <dlfcn.h>
-
typedef struct {
void *handle;
} Dynamic_Library_Slot_;
@@ -2106,6 +2119,9 @@ typedef struct {
static Dynamic_Libraries_ _dynamic_libraries = {0};
+#if defined(__unix__)
+#include <dlfcn.h>
+
void dynamic_library_open(u16 slot, c8 *name) {
if (name == NULL) {
LOG_error("Sanity");
@@ -2155,7 +2171,7 @@ void *dynamic_library_get_proc_address(u16 slot, c8 *proc) {
void *proc_address = dlsym(_dynamic_libraries.slots[slot].handle, proc);
if (proc_address == NULL) {
- LOG_error("Failed to get: %s", proc);
+ LOG_error("Failed to get proc: %s", proc);
LOG_error("%s", dlerror());
}
@@ -2168,10 +2184,100 @@ static void close_all_dynamic_libraries_(void) {
dlclose(_dynamic_libraries.slots[i].handle);
resize_dynamic_array_exact(&_dynamic_libraries.num_slots, (void **) &_dynamic_libraries.slots, sizeof *_dynamic_libraries.slots, 0);
}
-#endif // defined(__unix__)
-#if defined(__wasm__)
+#elif defined(_WIN32)
+
+// Windows definitions
+#if !defined(_INC_WINDOWS)
+ #ifndef WINAPI
+ #if defined(_ARM_)
+ #define WINAPI
+ #else
+ #define WINAPI __stdcall
+ #endif
+ #endif
+
+ typedef c8 const *LPCSTR;
+ typedef void ** HMODULE;
+ typedef int WINBOOL;
+ typedef iptr (WINAPI *FARPROC)();
+
+ // Kernel32.dll
+ HMODULE WINAPI LoadLibraryA (LPCSTR lpLibFileName);
+ WINBOOL WINAPI FreeLibrary (HMODULE hLibModule);
+ FARPROC WINAPI GetProcAddress (HMODULE hModule, LPCSTR lpProcName);
+ DWORD WINAPI GetLastError (void);
+#endif
+
void dynamic_library_open(u16 slot, c8 *name) {
+ if (name == NULL) {
+ LOG_error("Sanity");
+ return;
+ }
+
+ if ((i64) (u64) slot >= _dynamic_libraries.num_slots)
+ resize_dynamic_array_exact(&_dynamic_libraries.num_slots, (void **) &_dynamic_libraries.slots, sizeof *_dynamic_libraries.slots, (i64) slot + 1);
+
+ if ((i64) (u64) slot >= _dynamic_libraries.num_slots) {
+ LOG_error("Invalid slot: %d", (i32) slot);
+ return;
+ }
+
+ if (_dynamic_libraries.slots[slot].handle != NULL) {
+ FreeLibrary((HMODULE) _dynamic_libraries.slots[slot].handle);
+ _dynamic_libraries.slots[slot].handle = NULL;
+ }
+
+ void *h = (void *) LoadLibraryA(name);
+
+ if (h == NULL) {
+ LOG_error("Failed to open: %s", name);
+ LOG_error("%s", dlerror());
+ return;
+ }
+
+ _dynamic_libraries.slots[slot].handle = h;
+}
+
+void *dynamic_library_get_proc_address(u16 slot, c8 *proc) {
+ if ((i64) (u64) slot >= _dynamic_libraries.num_slots) {
+ LOG_error("Invalid slot: %d", (i32) slot);
+ return NULL;
+ }
+
+ if (proc == NULL) {
+ LOG_error("Sanity");
+ return NULL;
+ }
+
+ if (_dynamic_libraries.slots[slot].handle == NULL) {
+ LOG_error("Slot is closed: %d", (i32) slot);
+ return NULL;
+ }
+
+ void *proc_address = GetProcAddress((HMODULE) _dynamic_libraries.slots[slot].handle, proc);
+
+ if (proc_address == NULL)
+ LOG_error("Failed to get proc: %s (error code %d)", proc, GetLastError());
+
+ return proc_address;
+}
+
+static void close_all_dynamic_libraries_(void) {
+ for (i64 i = 0; i < _dynamic_libraries.num_slots; ++i)
+ if (_dynamic_libraries.slots[i].handle != NULL)
+ FreeLibrary((HMODULE) _dynamic_libraries.slots[i].handle);
+ resize_dynamic_array_exact(&_dynamic_libraries.num_slots, (void **) &_dynamic_libraries.slots, sizeof *_dynamic_libraries.slots, 0);
+}
+
+#elif defined(__wasm__)
+
+void dynamic_library_open(u16 slot, c8 *name) {
+ if (name == NULL) {
+ LOG_error("Sanity");
+ return;
+ }
+
(void) slot;
(void) name;
@@ -2179,18 +2285,29 @@ void dynamic_library_open(u16 slot, c8 *name) {
}
void *dynamic_library_get_proc_address(u16 slot, c8 *proc) {
+ if ((i64) (u64) slot >= _dynamic_libraries.num_slots) {
+ LOG_error("Invalid slot: %d", (i32) slot);
+ return NULL;
+ }
+
+ if (proc == NULL) {
+ LOG_error("Sanity");
+ return NULL;
+ }
+
(void) slot;
(void) proc;
LOG_error("Proc address not found: %s", proc);
return NULL;
}
-#endif // defined(__wasm__)
-// ================================================================
-//
-// PLATFORM-SPECIFIC CODE
-//
+static void close_all_dynamic_libraries_(void) {
+ resize_dynamic_array_exact(&_dynamic_libraries.num_slots, (void **) &_dynamic_libraries.slots, sizeof *_dynamic_libraries.slots, 0);
+}
+
+#endif
+
// ================================================================
//
// Time
diff --git a/stackless_coroutine.c b/stackless_coroutine.c
index 73a55e4..79d93ae 100644
--- a/stackless_coroutine.c
+++ b/stackless_coroutine.c
@@ -67,11 +67,13 @@ typedef struct {
#define CORO_PROMISE_FROM(coro_) (*((Coro_Promise_Void *) (coro_)))
-#ifdef CORO_ENABLE_CUSTOM_DISPATCH
+// TODO: Only use static dispatch?
+
+#ifdef ENABLE_CORO_CUSTOM_DISPATCH
// Application should implement this procedure if custom dispatch is enabled.
-void stackless_coroutine_dispatch(void *promise);
+void dispatch_stackless_coroutine(void *promise);
#else
-static void stackless_coroutine_dispatch(void *promise) {
+static void dispatch_stackless_coroutine(void *promise) {
// Dynamic dispatch by default.
CORO_PROMISE_FROM(promise)._state_machine(promise);
}
@@ -131,10 +133,10 @@ static void stackless_coroutine_dispatch(void *promise) {
CORO_STATIC(coro_, Coro_Void_, __VA_ARGS__)
#define coro_resume(promise_) \
- stackless_coroutine_dispatch(&(promise_))
+ dispatch_stackless_coroutine(&(promise_))
#define coro_next(promise_) \
- (stackless_coroutine_dispatch(&(promise_)), (promise_).return_value)
+ (dispatch_stackless_coroutine(&(promise_)), (promise_).return_value)
#define yield(...) \
do { \
@@ -175,7 +177,7 @@ static void stackless_coroutine_dispatch(void *promise) {
case CORO_LINE_(): \
if ((promise_)._index != -1) { \
self->_index = CORO_LINE_(); \
- stackless_coroutine_dispatch(&(promise_)); \
+ dispatch_stackless_coroutine(&(promise_)); \
} \
if ((promise_)._index != -1) \
return; \
@@ -188,7 +190,7 @@ static void stackless_coroutine_dispatch(void *promise) {
case CORO_LINE_(): \
if ((promise_)._index != -1) { \
self->_index = CORO_LINE_(); \
- stackless_coroutine_dispatch(&(promise_)); \
+ dispatch_stackless_coroutine(&(promise_)); \
self->return_value = (promise_).return_value; \
return; \
} \