summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2024-09-19 01:24:27 -0700
committerVito Caputo <vcaputo@pengaru.com>2024-09-19 01:39:07 -0700
commit0d277f1d91f755aecafdcb6145eddf4f17fb8db8 (patch)
tree0e9f2c669936bac2d278557df6960b94a78266d9 /src
parent97281be7bb92ca1c1c5f089b1242cf6e673688ee (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.c100
1 files changed, 62 insertions, 38 deletions
diff --git a/src/vcr.c b/src/vcr.c
index 6c4fa8e..c1edaed 100644
--- a/src/vcr.c
+++ b/src/vcr.c
@@ -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];
}
}
© All Rights Reserved