diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2024-09-19 01:24:27 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2024-09-19 01:39:07 -0700 |
commit | 0d277f1d91f755aecafdcb6145eddf4f17fb8db8 (patch) | |
tree | 0e9f2c669936bac2d278557df6960b94a78266d9 /src | |
parent | 97281be7bb92ca1c1c5f089b1242cf6e673688ee (diff) |
vcr: densify+deduplicate mem_to_png palette
This introduces a LUT indirection table for mapping the raw layer
values to a dense, deduplicated palette used with the PNG.
This should help with compression ratios at basically no cost.
Before `1800x8000 --headless --snapshot 10 --hertz 60`:
-rw-r--r-- 1 vc vc 87873 Sep 19 01:36 09.19.24-01:36:43-0.png
-rw-r--r-- 1 vc vc 215719 Sep 19 01:36 09.19.24-01:36:43-1.png
-rw-r--r-- 1 vc vc 219323 Sep 19 01:37 09.19.24-01:36:43-2.png
-rw-r--r-- 1 vc vc 221979 Sep 19 01:37 09.19.24-01:36:43-3.png
After:
-rw-r--r-- 1 vc vc 72303 Sep 19 01:37 09.19.24-01:37:30-0.png
-rw-r--r-- 1 vc vc 174100 Sep 19 01:37 09.19.24-01:37:30-1.png
-rw-r--r-- 1 vc vc 177430 Sep 19 01:37 09.19.24-01:37:30-2.png
-rw-r--r-- 1 vc vc 178711 Sep 19 01:38 09.19.24-01:37:30-3.png
Without any increase in compression level used. Which while it
would improve ratios further, substantially increases CPU cost.
Diffstat (limited to 'src')
-rw-r--r-- | src/vcr.c | 100 |
1 files changed, 62 insertions, 38 deletions
@@ -2034,53 +2034,77 @@ static int vcr_present_xlib_to_png(vcr_t *vcr, vcr_dest_t *dest) #define VCR_PNG_DARK_RED {0x80, 0x00, 0x00} #define VCR_PNG_DARK_CYAN {0x00, 0x5b, 0x5b} +enum { + VCR_LUT_BLACK = 0, + VCR_LUT_WHITE, + VCR_LUT_RED, + VCR_LUT_CYAN, + VCR_LUT_DARK_GRAY, + VCR_LUT_DARKER_GRAY, + VCR_LUT_DARK_WHITE, + VCR_LUT_DARK_RED, + VCR_LUT_DARK_CYAN, +}; + static int vcr_present_mem_to_png(vcr_t *vcr, vcr_dest_t *dest) { - static png_color pal[256] = { /* programming gfx like it's 1990 can be such a joy */ + static png_color pal[] = { /* programming gfx like it's 1990 can be such a joy */ + [VCR_LUT_BLACK] = {}, + [VCR_LUT_WHITE] = VCR_PNG_WHITE, + [VCR_LUT_RED] = VCR_PNG_RED, + [VCR_LUT_CYAN] = VCR_PNG_CYAN, + [VCR_LUT_DARK_GRAY] = VCR_PNG_DARK_GRAY, + [VCR_LUT_DARKER_GRAY] = VCR_PNG_DARKER_GRAY, + [VCR_LUT_DARK_WHITE] = VCR_PNG_DARK_WHITE, + [VCR_LUT_DARK_RED] = VCR_PNG_DARK_RED, + [VCR_LUT_DARK_CYAN] = VCR_PNG_DARK_CYAN, + }; + /* lut is an indirection table for mapping layer bit combinations to the above deduplicated denser color palette */ + static uint8_t lut[256] = { /* text solid white above all layers */ - [VCR_TEXT] = VCR_PNG_WHITE, - [VCR_TEXT_SEP] = VCR_PNG_WHITE, - [VCR_TEXT_SEP_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHA] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHB] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHAB] = VCR_PNG_WHITE, - [VCR_TEXT_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHA_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHB_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_GRAPHAB_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_ODD] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_SEP] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_SEP_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHA] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHB] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHAB] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHA_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHB_SHADOW] = VCR_PNG_WHITE, - [VCR_TEXT_ODD_GRAPHAB_SHADOW] = VCR_PNG_WHITE, + [VCR_TEXT] = VCR_LUT_WHITE, + [VCR_TEXT_SEP] = VCR_LUT_WHITE, + [VCR_TEXT_SEP_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHA] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHB] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHAB] = VCR_LUT_WHITE, + [VCR_TEXT_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHA_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHB_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_GRAPHAB_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_ODD] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_SEP] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_SEP_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHA] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHB] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHAB] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHA_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHB_SHADOW] = VCR_LUT_WHITE, + [VCR_TEXT_ODD_GRAPHAB_SHADOW] = VCR_LUT_WHITE, /* no shadow or text, plain graph colors */ - [VCR_GRAPHA] = VCR_PNG_RED, - [VCR_GRAPHB] = VCR_PNG_CYAN, - [VCR_GRAPHAB] = VCR_PNG_WHITE, - [VCR_GRAPHA_ODD] = VCR_PNG_RED, - [VCR_GRAPHB_ODD] = VCR_PNG_CYAN, - [VCR_GRAPHAB_ODD] = VCR_PNG_WHITE, + [VCR_GRAPHA] = VCR_LUT_RED, + [VCR_GRAPHB] = VCR_LUT_CYAN, + [VCR_GRAPHAB] = VCR_LUT_WHITE, + [VCR_GRAPHA_ODD] = VCR_LUT_RED, + [VCR_GRAPHB_ODD] = VCR_LUT_CYAN, + [VCR_GRAPHAB_ODD] = VCR_LUT_WHITE, /* shadowed same but dark */ - [VCR_SHADOW_GRAPHA] = VCR_PNG_DARK_RED, - [VCR_SHADOW_GRAPHB] = VCR_PNG_DARK_CYAN, - [VCR_SHADOW_GRAPHAB] = VCR_PNG_DARK_WHITE, - [VCR_SHADOW_ODD_GRAPHA] = VCR_PNG_DARK_RED, - [VCR_SHADOW_ODD_GRAPHB] = VCR_PNG_DARK_CYAN, - [VCR_SHADOW_ODD_GRAPHAB] = VCR_PNG_DARK_WHITE, + [VCR_SHADOW_GRAPHA] = VCR_LUT_DARK_RED, + [VCR_SHADOW_GRAPHB] = VCR_LUT_DARK_CYAN, + [VCR_SHADOW_GRAPHAB] = VCR_LUT_DARK_WHITE, + [VCR_SHADOW_ODD_GRAPHA] = VCR_LUT_DARK_RED, + [VCR_SHADOW_ODD_GRAPHB] = VCR_LUT_DARK_CYAN, + [VCR_SHADOW_ODD_GRAPHAB] = VCR_LUT_DARK_WHITE, /* the rest get defaulted to black, which is great. */ - [VCR_SEP] = VCR_PNG_DARK_GRAY, - [VCR_ODD] = VCR_PNG_DARKER_GRAY, - [VCR_SEP_ODD] = VCR_PNG_DARK_GRAY, + [VCR_SEP] = VCR_LUT_DARK_GRAY, + [VCR_ODD] = VCR_LUT_DARKER_GRAY, + [VCR_SEP_ODD] = VCR_LUT_DARK_GRAY, }; png_bytepp row_pointers; @@ -2148,7 +2172,7 @@ static int vcr_present_mem_to_png(vcr_t *vcr, vcr_dest_t *dest) unsigned sg_shift = (phase_k_mod_width & 0x1) << 2; uint8_t *sg = &vcr->mem.bits[(i * VCR_ROW_HEIGHT + j) * vcr->mem.pitch + (phase_k_mod_width >> 1)]; - *d = (*s & (~mask & 0xf)) | ((*sg & (mask << sg_shift)) >> sg_shift) | border | odd; + *d = lut[(*s & (~mask & 0xf)) | ((*sg & (mask << sg_shift)) >> sg_shift) | border | odd]; /* this copy pasta unrolls the loop to unpack two pixels from the nibbles at a time */ d++; @@ -2162,7 +2186,7 @@ static int vcr_present_mem_to_png(vcr_t *vcr, vcr_dest_t *dest) sg_shift = (phase_k_mod_width & 0x1) << 2; sg = &vcr->mem.bits[(i * VCR_ROW_HEIGHT + j) * vcr->mem.pitch + (phase_k_mod_width >> 1)]; - *d = ((*s & ~(mask << 4)) >> 4) | ((*sg & (mask << sg_shift)) >> sg_shift) | border | odd; + *d = lut[((*s & ~(mask << 4)) >> 4) | ((*sg & (mask << sg_shift)) >> sg_shift) | border | odd]; } } |