diff options
Diffstat (limited to 'graphics.c')
-rwxr-xr-x | graphics.c | 285 |
1 files changed, 54 insertions, 231 deletions
@@ -56,10 +56,6 @@ exit $STATUS # */ #define EPSILON (1e-9) #endif -#ifndef ANTIALIASING_SCALE -#define ANTIALIASING_SCALE 3 -#endif - #ifndef GRAPHICS_CACHE_DEPTH #define GRAPHICS_CACHE_DEPTH 4 #endif @@ -68,18 +64,6 @@ exit $STATUS # */ #define GRAPHICS_CACHE_SIZE (128 * GRAPHICS_CACHE_DEPTH) #endif -#ifndef GRAPHICS_FRAME_BUDGET -#define GRAPHICS_FRAME_BUDGET (100.0) -#endif - -#ifndef GRAPHICS_RENDER_COST -#define GRAPHICS_RENDER_COST (0.1) -#endif - -#ifndef GRAPHICS_DOWNSCALE_COST -#define GRAPHICS_DOWNSCALE_COST (0.1) -#endif - // ================================================================ // // Vector math @@ -298,32 +282,17 @@ static b8 same_sign_(f64 a, f64 b) { return 1; } -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; -} - -static void put_pixel_(Pixel_Buffer dst, vec4_f32 color, i64 x, i64 y) { - i64 n = y * dst.stride + x; - +static void put_pixel_(vec4_f32 *dst, vec4_f32 color) { if (color.w == 1.f) - dst.pixels[n] = color; + *dst = color; else { - vec4_f32 dst_color = dst.pixels[n]; - f32 dst_amount = 1. - color.w; - - dst.pixels[n] = (vec4_f32) { - .x = dst_color.x * dst_amount + color.x * color.w, - .y = dst_color.y * dst_amount + color.y * color.w, - .z = dst_color.z * dst_amount + color.z * color.w, - .w = max2_f32_(dst_color.w, color.w), + f32 dst_amount = 1. - color.w; + + *dst = (vec4_f32) { + .x = dst->x * dst_amount + color.x * color.w, + .y = dst->y * dst_amount + color.y * color.w, + .z = dst->z * dst_amount + color.z * color.w, + .w = max2_f32_(dst->w, color.w), }; } } @@ -342,43 +311,28 @@ void draw_pixels_to_buffer(Pixel_Buffer dst, Box area, Pixel_Buffer src) { if (j0 < 0) j0 = 0; if (j1 > dst.height) j1 = dst.height; - f64 w_inv = 1. / area.width; - f64 h_inv = 1. / area.height; + f64 w_coeff = src.width / area.width; + f64 h_coeff = src.height / area.height; for (i64 j = j0; j < j1; ++j) { - i64 src_j = (i64) floor(((j - area.y + .5) * src.height) * h_inv); + i64 src_j = (i64) floor((j - area.y + .5) * h_coeff); if (src_j < 0 || src_j >= src.height) continue; vec4_f32 *q = src.pixels + src_j * src.stride; vec4_f32 *p = dst.pixels + j * dst.stride + i0; for (i64 i = i0; i < i1; ++i) { - i64 src_i = (i64) floor(((i - area.x + .5) * src.width) * w_inv); + i64 src_i = (i64) floor((i - area.x + .5) * w_coeff); if (src_i < 0 || src_i >= src.width) continue; - vec4_f32 color = q[src_i]; - if (color.w == 1.f) - *p = color; - else { - vec4_f32 dst_color = *p; - f32 dst_amount = 1. - color.w; - *p = (vec4_f32) { - .x = dst_color.x * dst_amount + color.x * color.w, - .y = dst_color.y * dst_amount + color.y * color.w, - .z = dst_color.z * dst_amount + color.z * color.w, - .w = max2_f32_(dst_color.w, color.w), - }; - } + put_pixel_(p, q[src_i]); ++p; } } } void fill_rectangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) { - f64 x1 = area.x + area.width; - f64 y1 = area.y + area.height; - - i64 i0 = (i64) ceil (area.x); - i64 i1 = (i64) floor(x1); - i64 j0 = (i64) ceil (area.y); - i64 j1 = (i64) floor(y1); + i64 i0 = (i64) floor(area.x); + i64 i1 = (i64) floor(area.x + area.width); + i64 j0 = (i64) floor(area.y); + i64 j1 = (i64) floor(area.y + area.height); i64 i00 = i0; i64 j00 = j0; @@ -390,73 +344,11 @@ void fill_rectangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) { if (j0 < 0) j0 = 0; if (j1 > dst.height) j1 = dst.height; - f64 kx0 = i00 - area.x; - f64 kx1 = x1 - i10; - f64 ky0 = j00 - area.y; - f64 ky1 = y1 - j10; - - for (i64 j = j0; j < j1; ++j) - for (i64 i = i0; i < i1; ++i) - put_pixel_(dst, color, i, j); - - if (i00 > i10) { - kx0 *= kx1; - kx1 = 0.; - } - - if (j00 > j10) { - ky0 *= ky1; - ky1 = 0.; - } - - f64 alpha = color.w; - - if (i00 - 1 >= 0 && i00 - 1 < dst.width) { - color.w = gamma_(gamma_re_(alpha) * kx0); - for (i64 j = j0; j < j1; ++j) - put_pixel_(dst, color, i00 - 1, j); - } - - if (i10 >= 0 && i10 < dst.width) { - color.w = gamma_(gamma_re_(alpha) * kx1); - for (i64 j = j0; j < j1; ++j) - put_pixel_(dst, color, i10, j); - } - - if (j00 - 1 >= 0 && j00 - 1 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * ky0); - for (i64 i = i0; i < i1; ++i) - put_pixel_(dst, color, i, j00 - 1); - } - - if (j10 >= 0 && j10 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * ky1); - for (i64 i = i0; i < i1; ++i) - put_pixel_(dst, color, i, j10); - } - - if ( i00 - 1 >= 0 && i00 - 1 < dst.width - && j00 - 1 >= 0 && j00 - 1 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * kx0 * ky0); - put_pixel_(dst, color, i00 - 1, j00 - 1); - } - - if ( i10 >= 0 && i10 < dst.width - && j00 - 1 >= 0 && j00 - 1 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * kx1 * ky0); - put_pixel_(dst, color, i10, j00 - 1); - } - - if ( i00 - 1 >= 0 && i00 - 1 < dst.width - && j10 >= 0 && j10 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * kx0 * ky1); - put_pixel_(dst, color, i00 - 1, j10); - } - - if ( i10 >= 0 && i10 < dst.width - && j10 >= 0 && j10 < dst.height) { - color.w = gamma_(gamma_re_(alpha) * kx1 * ky1); - put_pixel_(dst, color, i10, j10); + for (i64 j = j0; j < j1; ++j) { + vec4_f32 *p = dst.pixels + j * dst.stride + i0; + vec4_f32 *p_end = dst.pixels + j * dst.stride + i1; + for (; p < p_end; ++p) + put_pixel_(p, color); } } @@ -496,8 +388,10 @@ void fill_triangle_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[3]) break; } - for (i64 i = left; i <= right; ++i) - put_pixel_(dst, color, i, j); + vec4_f32 *p = dst.pixels + j * dst.stride + left; + vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1; + for (; p < p_end; ++p) + put_pixel_(p, color); } } @@ -539,8 +433,10 @@ void fill_quad_to_buffer(Pixel_Buffer dst, vec4_f32 color, vec2 vertices[4]) { break; } - for (i64 i = left; i <= right; ++i) - put_pixel_(dst, color, i, j); + vec4_f32 *p = dst.pixels + j * dst.stride + left; + vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1; + for (; p < p_end; ++p) + put_pixel_(p, color); } } @@ -576,8 +472,10 @@ void fill_ellipse_to_buffer(Pixel_Buffer dst, vec4_f32 color, Box area) { if (left < 0) left = 0; if (right >= dst.width) right = dst.width - 1; - for (i64 i = left; i <= right; ++i) - put_pixel_(dst, color, i, j); + vec4_f32 *p = dst.pixels + j * dst.stride + left; + vec4_f32 *p_end = dst.pixels + j * dst.stride + right + 1; + for (; p < p_end; ++p) + put_pixel_(p, color); } } @@ -810,13 +708,13 @@ static void draw_text_(Pixel_Buffer dst, vec4_f32 color, f64 x0, f64 y0, f64 sca f64 h_inv = 1. / h; for (i64 i = i0; i <= i1; ++i) { - i64 column = (i64) floor(((i - x) * num_cols) * w_inv + .5); + i64 column = (i64) floor(((i - x + .5) * num_cols) * w_inv); i64 offset = char_column_offset_(text[n], column); for (i64 j = j0; j <= j1; ++j) { - i64 row = (i64) floor(((j - y) * CHAR_NUM_BITS_Y_) * h_inv + .5); + i64 row = (i64) floor(((j - y + .5) * CHAR_NUM_BITS_Y_) * h_inv); if (char_bit_(offset, row)) - put_pixel_(dst, color, i, j); + put_pixel_(dst.pixels + j * dst.stride + i, color); } } } @@ -1433,33 +1331,17 @@ typedef union { typedef struct { b8 occupied; - b8 done_rendering; - b8 done_downscaling; Graphics_Request_Id_ id; Graphics_Request req; i64 width; i64 height; i64 buffer_len; vec4_f32 * buffer; - i64 upscaled_buffer_len; - vec4_f32 * upscaled_buffer; } Graphics_Cache_Slot_; static Graphics_Cache_Slot_ _graphics_cache[GRAPHICS_CACHE_SIZE] = {0}; -static i64 _graphics_cache_gc_index = 0; -static f64 _graphics_rendering_budget = .0; - -static f64 _graphics_costs[] = { - [GRAPHICS_DRAW_PIXELS] = 2., - [GRAPHICS_FILL_RECTANGLE] = 1., - [GRAPHICS_FILL_TRIANGLE] = 2., - [GRAPHICS_FILL_QUAD] = 2., - [GRAPHICS_FILL_ELLIPSE] = 2., - [GRAPHICS_FILL_LINE] = 3., - [GRAPHICS_DRAW_TEXT_AREA] = 2., - [GRAPHICS_DRAW_TEXT_CURSOR] = 2., -}; +static i64 _graphics_cache_gc_index = 0; static void graphics_request_hash_(Blake2b_State *S, Graphics_Request req) { switch (req.op) { @@ -1817,41 +1699,14 @@ static b8 mem_eq_(i64 size, void *x, void *y) { static void copy_pixels_quick_(Pixel_Buffer dst, i64 x, i64 y, Pixel_Buffer src) { for (i64 j = 0; j < src.height; ++j) { - i64 src_n = j * src.stride; - i64 src_n1 = src_n + src.width; - i64 dst_n = (y + j) * dst.stride + x; - - while (src_n < src_n1) { - vec4_f32 *d = dst.pixels + dst_n; - vec4_f32 *s = src.pixels + src_n; + vec4_f32 *s = src.pixels + j * src.stride; + vec4_f32 *d = dst.pixels + (y + j) * dst.stride + x; + vec4_f32 *d_end = d + src.width; + for (; d < d_end; ++d, ++s) { d->x = d->x * (1.f - s->w) + s->x * s->w; d->y = d->y * (1.f - s->w) + s->y * s->w; d->z = d->z * (1.f - s->w) + s->z * s->w; - - ++dst_n; - ++src_n; - } - } -} - -static void downscale_pixels_(vec4_f32 *dst, i64 width, i64 height, vec4_f32 *src) { - f32 k = 1.f / (ANTIALIASING_SCALE * ANTIALIASING_SCALE); - for (i64 j = 0; j < height; ++j) { - for (i64 i = 0; i < width; ++i) { - vec4_f32 color = {0}; - for (i64 jj = 0; jj < ANTIALIASING_SCALE; ++jj) - for (i64 ii = 0; ii < ANTIALIASING_SCALE; ++ii) { - i64 n = (j * ANTIALIASING_SCALE + jj) * width + (i * ANTIALIASING_SCALE + ii); - color.x += gamma_re_(src[n].x); - color.y += gamma_re_(src[n].y); - color.z += gamma_re_(src[n].z); - color.w += gamma_re_(src[n].w); - } - dst[j * width + i].x = gamma_(color.x * k); - dst[j * width + i].y = gamma_(color.y * k); - dst[j * width + i].z = gamma_(color.z * k); - dst[j * width + i].w = gamma_(color.w * k); } } } @@ -1891,14 +1746,10 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request Graphics_Cache_Slot_ *s = _graphics_cache + slot; - i64 num_pixels = norm.width * norm.height; - i64 upscaled_len = num_pixels * (ANTIALIASING_SCALE * ANTIALIASING_SCALE); - + i64 num_pixels = norm.width * norm.height; if (reset_slot) { s->occupied = 1; - s->done_rendering = 0; - s->done_downscaling = 0; s->id = id; s->req = norm.req; s->width = norm.width; @@ -1907,44 +1758,21 @@ static void perform_graphics_request_cached_(Pixel_Buffer dst, Graphics_Request if (num_pixels > s->buffer_len) resize_dynamic_array_exact(&s->buffer_len, (void **) &s->buffer, sizeof *s->buffer, num_pixels); - if (upscaled_len > s->upscaled_buffer_len) - resize_dynamic_array_exact(&s->upscaled_buffer_len, (void **) &s->upscaled_buffer, sizeof *s->upscaled_buffer, upscaled_len); - - if (s->buffer_len < num_pixels || s->upscaled_buffer_len < upscaled_len) + if (s->buffer_len < num_pixels) // Out of memory s->occupied = 0; - } - if (_graphics_rendering_budget > 0 && !s->done_rendering) { - if (s->upscaled_buffer_len >= upscaled_len) { - Pixel_Buffer dst = { - .width = s->width * ANTIALIASING_SCALE, - .height = s->height * ANTIALIASING_SCALE, - .stride = s->width * ANTIALIASING_SCALE, - .pixels = s->upscaled_buffer, - }; - Graphics_Request upscaled = graphics_request_scaled_(s->req, (vec2) { ANTIALIASING_SCALE, ANTIALIASING_SCALE }); - perform_graphics_request_to_buffer_(dst, upscaled); - s->done_rendering = 1; - _graphics_rendering_budget -= num_pixels * GRAPHICS_RENDER_COST * _graphics_costs[req.op]; - } else { - LOG_ERROR("Sanity"); - s->occupied = 0; - } - } + Pixel_Buffer dst = { + .width = s->width, + .height = s->height, + .stride = s->width, + .pixels = s->buffer, + }; - if (_graphics_rendering_budget > 0 && s->done_rendering && !s->done_downscaling) { - if (s->buffer_len >= num_pixels && s->upscaled_buffer_len >= upscaled_len) { - downscale_pixels_(s->buffer, s->width, s->height, s->upscaled_buffer); - s->done_downscaling = 1; - _graphics_rendering_budget -= num_pixels * GRAPHICS_DOWNSCALE_COST; - } else { - LOG_ERROR("Sanity"); - s->occupied = 0; - } + perform_graphics_request_to_buffer_(dst, s->req); } - if (s->done_downscaling) + if (s->occupied) copy_pixels_quick_(dst, norm.x, norm.y, (Pixel_Buffer) { .width = s->width, .height = s->height, @@ -1990,17 +1818,12 @@ void perform_graphics_request(Graphics_Context context, Graphics_Request req) { } void graphics_refresh_frame(void) { - _graphics_rendering_budget = GRAPHICS_FRAME_BUDGET; - Graphics_Cache_Slot_ *s = _graphics_cache + _graphics_cache_gc_index; - i64 required_len = !s->occupied ? 0 : s->width * s->height; - i64 required_upscaled_len = !s->occupied ? 0 : required_len * (ANTIALIASING_SCALE * ANTIALIASING_SCALE); + i64 required_len = !s->occupied ? 0 : s->width * s->height; if (s->buffer_len > required_len) resize_dynamic_array_exact(&s->buffer_len, (void **) &s->buffer, sizeof *s->buffer, required_len); - if (s->upscaled_buffer_len > required_upscaled_len) - resize_dynamic_array_exact(&s->upscaled_buffer_len, (void **) &s->upscaled_buffer, sizeof *s->buffer, required_upscaled_len); _graphics_cache_gc_index = (_graphics_cache_gc_index + 1) % GRAPHICS_CACHE_SIZE; } |