diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2025-04-24 03:58:52 +0200 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2025-04-24 03:58:52 +0200 |
commit | 27291f388b02c6ba88efb79b9728b65f158589ef (patch) | |
tree | d6cce8eccf6101a6ee04bf1b35a2186d050de56e | |
parent | f8bd7cfdb9ed7ec99d612dd03670e50aa0c60db2 (diff) | |
download | reduced_system_layer-27291f388b02c6ba88efb79b9728b65f158589ef.zip |
Global gamma correction
-rw-r--r-- | graphics.c | 85 | ||||
-rw-r--r-- | runtime.c | 40 |
2 files changed, 80 insertions, 45 deletions
@@ -50,13 +50,7 @@ vec4_f32 vec4_f32_lerp (vec4_f32 a, vec4_f32 b, f32 t); // ================================================================ -typedef struct { - // NOTE: Dimensions are in pixels. - i64 width; - i64 height; - i64 stride; - vec4_f32 *pixels; -} Pixel_Buffer; +// NOTE: Dimensions are in pixels. typedef struct { f64 x; @@ -65,6 +59,31 @@ typedef struct { f64 height; } Box; +// TODO: +// typedef struct { +// b8 enabled; +// i64 x; +// i64 y; +// i64 width; +// i64 height; +// } Bounding_Box; + +typedef struct { + i64 width; + i64 height; + i64 stride; + // Bounding_Box bounds; + u8 *pixels; +} Stencil_Buffer; + +typedef struct { + i64 width; + i64 height; + i64 stride; + // Bounding_Box bounds; + vec4_f32 *pixels; +} Pixel_Buffer; + enum { GRAPHICS_DRAW_PIXELS, GRAPHICS_FILL_RECTANGLE, @@ -981,49 +1000,37 @@ vec4_f32 vec4_f32_lerp(vec4_f32 a, vec4_f32 b, f32 t) { // ================================================================ -static f64 gamma_(f64 x) { - if (x >= 0.0031308) - return 1.055 * pow(x, 1.0 / 2.4) - 0.055; - return 12.92 * x; -} - -static f64 gamma_re_(f64 x) { - if (x >= 0.04045) - return pow((x + 0.055) / 1.055, 2.4); - return x / 12.92; -} - vec3_f32 rgb_gamma_add(vec3_f32 rgb) { return (vec3_f32) { - .x = (f32) gamma_(rgb.x), - .y = (f32) gamma_(rgb.y), - .z = (f32) gamma_(rgb.z), + .x = gamma_(rgb.x), + .y = gamma_(rgb.y), + .z = gamma_(rgb.z), }; } vec3_f32 rgb_gamma_remove(vec3_f32 rgb) { return (vec3_f32) { - .x = (f32) gamma_re_(rgb.x), - .y = (f32) gamma_re_(rgb.y), - .z = (f32) gamma_re_(rgb.z), + .x = gamma_re_(rgb.x), + .y = gamma_re_(rgb.y), + .z = gamma_re_(rgb.z), }; } vec4_f32 rgba_gamma_add(vec4_f32 rgba) { return (vec4_f32) { - .x = (f32) gamma_(rgba.x), - .y = (f32) gamma_(rgba.y), - .z = (f32) gamma_(rgba.z), - .w = (f32) gamma_(rgba.w), + .x = gamma_(rgba.x), + .y = gamma_(rgba.y), + .z = gamma_(rgba.z), + .w = gamma_(rgba.w), }; } vec4_f32 rgba_gamma_remove(vec4_f32 rgba) { return (vec4_f32) { - .x = (f32) gamma_re_(rgba.x), - .y = (f32) gamma_re_(rgba.y), - .z = (f32) gamma_re_(rgba.z), - .w = (f32) gamma_re_(rgba.w), + .x = gamma_re_(rgba.x), + .y = gamma_re_(rgba.y), + .z = gamma_re_(rgba.z), + .w = gamma_re_(rgba.w), }; } @@ -2186,7 +2193,7 @@ TEST("colors") { vec3_f32 white = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 1.f, 1.f, })); REQUIRE_EQ(white.x * 100, 100); REQUIRE_EQ(white.y * 100, 100); - REQUIRE_EQ((white.z + 3e-7) * 100, 100); + REQUIRE_EQ((white.z + 6e-7) * 100, 100); vec3_f32 black = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 0.f, 0.f, })); REQUIRE_EQ(black.x * 100, 0); @@ -2205,13 +2212,13 @@ TEST("colors") { vec3_f32 green = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 1.f, 0.f, })); REQUIRE_EQ(green.x * 100, 0); - REQUIRE_EQ(green.y * 100, 100); + REQUIRE_EQ((green.y + 3e-7) * 100, 100); REQUIRE_EQ(green.z * 100, 0); vec3_f32 blue = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 0.f, 1.f, })); REQUIRE_EQ(blue.x * 100, 0); REQUIRE_EQ(blue.y * 100, 0); - REQUIRE_EQ((blue.z + 6e-8) * 100, 100); + REQUIRE_EQ((blue.z + 3e-7) * 100, 100); vec3_f32 yellow = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 1.f, 0.f, })); REQUIRE_EQ(yellow.x * 100, 100); @@ -2220,13 +2227,13 @@ TEST("colors") { vec3_f32 cyan = rgb_from_lch(lch_from_rgb((vec3_f32) { 0.f, 1.f, 1.f, })); REQUIRE_EQ(cyan.x * 100, 0); - REQUIRE_EQ((cyan.y + 2e-7) * 100, 100); - REQUIRE_EQ((cyan.z + 2e-7) * 100, 100); + REQUIRE_EQ((cyan.y + 3e-7) * 100, 100); + REQUIRE_EQ((cyan.z + 3e-7) * 100, 100); vec3_f32 purple = rgb_from_lch(lch_from_rgb((vec3_f32) { 1.f, 0.f, 1.f, })); REQUIRE_EQ(purple.x * 100, 100); REQUIRE_EQ(purple.y * 100, 0); - REQUIRE_EQ((purple.z + 2e-7) * 100, 100); + REQUIRE_EQ((purple.z + 3e-7) * 100, 100); } TEST("rectangle corners") { @@ -612,7 +612,7 @@ typedef struct { i32 antialiasing_scale; b8 exact_resolution : 1; - b8 disable_gamma : 1; // TODO + b8 disable_gamma : 1; b8 graceful_shutdown : 1; b8 enable_clipboard_text : 1; b8 enable_clipboard_image : 1; @@ -1290,6 +1290,18 @@ i8 utf8_write(c32 c, c8 *buffer) { // // ================================================================ +static f32 gamma_(f32 x) { + if (x >= 0.0031308f) + return 1.055f * (f32) pow(x, 1.0 / 2.4) - 0.055f; + return 12.92f * x; +} + +static f32 gamma_re_(f32 x) { + if (x >= 0.04045f) + return (f32) pow((x + 0.055f) / 1.055f, 2.4); + return x / 12.92f; +} + static u32 rgb_u32_from_f32_(vec3_f32 c) { i32 ir = (i32) floor(c.x * 255. + .5); i32 ig = (i32) floor(c.y * 255. + .5); @@ -1765,6 +1777,8 @@ static void convert_pixels_for_window_(void) { return; } + // TODO, PERF: Improve performance. + // Downscale pixels from vec4_f32 pixel buffer to internal u32 pixel buffer. // // FIXME: Check if the scale is 1:1. @@ -1812,11 +1826,27 @@ static void convert_pixels_for_window_(void) { } } - u32 *d_end = d + dst_width; - vec3_f32 *im = _internal_row; + u32 *d_end = d + dst_width; + vec3_f32 *im = _internal_row; + vec3_f32 *im_end = _internal_row + dst_width; + + if (!g_platform.disable_gamma) + for (; im < im_end; ++im) { + im->x = gamma_(im->x * k); + im->y = gamma_(im->y * k); + im->z = gamma_(im->z * k); + } + else + for (; im < im_end; ++im) { + im->x *= k; + im->y *= k; + im->z *= k; + } + + im = _internal_row; for (; d < d_end; ++d, ++im) - *d = rgb_u32_from_f32_((vec3_f32) { .x = im->x * k, .y = im->y * k, .z = im->z * k, }) | 0xff000000; + *d = rgb_u32_from_f32_(*im) | 0xff000000; } PROFILER_end(PROFILE_DOWNSCALE); @@ -1843,8 +1873,6 @@ static void convert_pixels_for_window_(void) { PROFILER_begin(PROFILE_RESIZE); - // TODO, PERF: Improve performance. - u32 x_ratio = (src_width << 16) / dst_width; u32 y_ratio = (src_height << 16) / dst_height; |