diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-04-26 02:10:48 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-04-26 02:10:48 +0200 |
commit | 72b9fc8c1515c12600513fd9759f9b9034825726 (patch) | |
tree | 130972ec171ced5d68cd13a493f185cfd4b4a52d | |
parent | 8a4b4bed8259397c6d958766573a0bfa25909b98 (diff) | |
download | reduced_system_layer-72b9fc8c1515c12600513fd9759f9b9034825726.zip |
Pixels scaling tests and perf
-rw-r--r-- | graphics.c | 451 | ||||
-rwxr-xr-x | run_tests.c | 2 | ||||
-rw-r--r-- | runtime.c | 173 | ||||
-rw-r--r-- | stackless_coroutine.c | 16 |
4 files changed, 564 insertions, 78 deletions
@@ -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 && \ @@ -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; \ } \ |