termptyesc: cache true color approximations
On my stupid benchmark ( https://github.com/billiob/fire ), this goes from about 45 fps to about 125fps.
This commit is contained in:
parent
f497b9446c
commit
f9b6f88be1
|
@ -654,12 +654,77 @@ _csi_truecolor_arg_get(Termpty *ty, Eina_Unicode **ptr)
|
||||||
return sum;
|
return sum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !defined(ENABLE_FUZZING)
|
||||||
|
/*********************************
|
||||||
|
* cache true color approximations
|
||||||
|
*********************************
|
||||||
|
* Approximating true colors is costly since it needs to compare 256 colors.
|
||||||
|
* The following considers that a few colors are used a lot. For example, one
|
||||||
|
* can consider that a text editor with syntax highlighting would only use a
|
||||||
|
* small palette.
|
||||||
|
* Given that, using the cache needs to be efficient: it needs to speed up the
|
||||||
|
* approximation when the color is already in the cache but not knowing the
|
||||||
|
* color requested is not in the cache needs to be efficient too.
|
||||||
|
*
|
||||||
|
* The cache is an array of @TCC_LEN uint32_t.
|
||||||
|
* Each entry has on the MSB the color as 3 uint8_t (R,G,B) and the LSB is
|
||||||
|
* the approximated color.
|
||||||
|
* Searching a color is simply going through the array and testing the mask on
|
||||||
|
* the 3 most significant bytes.
|
||||||
|
* When a color is found, it is bubbled up towards the start of the array by
|
||||||
|
* swapping this entry with the one above. This way the array is ordered to
|
||||||
|
* get most used colors as fast as possible.
|
||||||
|
* When a color is not found, the slow process of comparing it with the 256
|
||||||
|
* colors is used. Then the result is inserted in the lower half of the
|
||||||
|
* array. This ensures that new entries can live a bit and not be removed by
|
||||||
|
* the next new color. Using a modulo with a prime number makes for a
|
||||||
|
* nice-enough random generator to figure out where to insert.
|
||||||
|
*/
|
||||||
|
#define TCC_LEN 32
|
||||||
|
#define TCC_PRIME 17 /* smallest prime number larger than @TCC_LEN/2 */
|
||||||
|
static struct {
|
||||||
|
uint32_t colors[TCC_LEN];
|
||||||
|
} _truecolor_cache;
|
||||||
|
static int _tcc_random_pos = 0;
|
||||||
|
|
||||||
static int
|
static Eina_Bool
|
||||||
|
_tcc_find(const uint32_t color_msb, uint8_t *chosen_color)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < TCC_LEN; i++)
|
||||||
|
{
|
||||||
|
if ((_truecolor_cache.colors[i] & 0xffffff00) == color_msb)
|
||||||
|
{
|
||||||
|
*chosen_color = _truecolor_cache.colors[i] & 0xff;
|
||||||
|
/* bubble up this result */
|
||||||
|
if (i > 0)
|
||||||
|
{
|
||||||
|
uint32_t prev = _truecolor_cache.colors[i - 1];
|
||||||
|
_truecolor_cache.colors[i - 1] = _truecolor_cache.colors[i];
|
||||||
|
_truecolor_cache.colors[i] = prev;
|
||||||
|
}
|
||||||
|
return EINA_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EINA_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_tcc_insert(const uint32_t color_msb, const uint8_t approximated)
|
||||||
|
{
|
||||||
|
uint32_t c = color_msb | approximated;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = (TCC_LEN / 2) + ((_tcc_random_pos + TCC_PRIME) % (TCC_LEN / 2));
|
||||||
|
|
||||||
|
_truecolor_cache.colors[i] = c;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static uint8_t
|
||||||
_approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0)
|
_approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0)
|
||||||
{
|
{
|
||||||
int chosen_color = COL_DEF;
|
uint8_t chosen_color = COL_DEF;
|
||||||
/* TODO: use the function in tests */
|
|
||||||
#if defined(ENABLE_FUZZING)
|
#if defined(ENABLE_FUZZING)
|
||||||
(void) ty;
|
(void) ty;
|
||||||
(void) r0;
|
(void) r0;
|
||||||
|
@ -669,14 +734,16 @@ _approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0)
|
||||||
int c;
|
int c;
|
||||||
int distance_min = INT_MAX;
|
int distance_min = INT_MAX;
|
||||||
Evas_Object *textgrid;
|
Evas_Object *textgrid;
|
||||||
|
const uint32_t color_msb = (r0 << 24) | (g0 << 16) | (b0 << 8);
|
||||||
|
|
||||||
DBG("approximating r:%d g:%d b:%d", r0, g0, b0);
|
if (_tcc_find(color_msb, &chosen_color))
|
||||||
|
return chosen_color;
|
||||||
|
|
||||||
textgrid = termio_textgrid_get(ty->obj);
|
textgrid = termio_textgrid_get(ty->obj);
|
||||||
for (c = 0; c < 256; c++)
|
for (c = 0; c < 256; c++)
|
||||||
{
|
{
|
||||||
int r1 = 0, g1 = 0, b1 = 0, a1 = 0;
|
int r1 = 0, g1 = 0, b1 = 0, a1 = 0;
|
||||||
int delta_red_sq, delta_green_sq, delta_blue_sq, middle_red;
|
int delta_red_sq, delta_green_sq, delta_blue_sq, red_mean;
|
||||||
int distance;
|
int distance;
|
||||||
|
|
||||||
evas_object_textgrid_palette_get(textgrid,
|
evas_object_textgrid_palette_get(textgrid,
|
||||||
|
@ -684,23 +751,34 @@ _approximate_truecolor_rgb(Termpty *ty, int r0, int g0, int b0)
|
||||||
c, &r1, &g1, &b1, &a1);
|
c, &r1, &g1, &b1, &a1);
|
||||||
/* Compute the color distance
|
/* Compute the color distance
|
||||||
* XXX: this is inacurate but should give good enough results.
|
* XXX: this is inacurate but should give good enough results.
|
||||||
* See * https://en.wikipedia.org/wiki/Color_difference
|
* See https://en.wikipedia.org/wiki/Color_difference
|
||||||
*/
|
*/
|
||||||
middle_red = (r0 + r1) / 2;
|
red_mean = (r0 + r1) / 2;
|
||||||
delta_red_sq = (r0 - r1) * (r0 - r1);
|
delta_red_sq = (r0 - r1) * (r0 - r1);
|
||||||
delta_green_sq = (g0 - g1) * (g0 - g1);
|
delta_green_sq = (g0 - g1) * (g0 - g1);
|
||||||
delta_blue_sq = (b0 - b1) * (b0 - b1);
|
delta_blue_sq = (b0 - b1) * (b0 - b1);
|
||||||
|
|
||||||
|
#if 1
|
||||||
distance = 2 * delta_red_sq
|
distance = 2 * delta_red_sq
|
||||||
+ 4 * delta_green_sq
|
+ 4 * delta_green_sq
|
||||||
+ 3 * delta_blue_sq
|
+ 3 * delta_blue_sq
|
||||||
+ ((middle_red) * (delta_red_sq - delta_blue_sq) / 256);
|
+ ((red_mean) * (delta_red_sq - delta_blue_sq) / 256);
|
||||||
|
#else
|
||||||
|
/* from https://www.compuphase.com/cmetric.htm */
|
||||||
|
distance = (((512 + red_mean) * delta_red_sq) >> 8)
|
||||||
|
+ 4 * delta_green_sq
|
||||||
|
+ (((767 - red_mean) * delta_blue_sq) >> 8);
|
||||||
|
/* euclidian distance */
|
||||||
|
distance = delta_red_sq + delta_green_sq + delta_blue_sq;
|
||||||
|
(void)red_mean;
|
||||||
|
#endif
|
||||||
if (distance < distance_min)
|
if (distance < distance_min)
|
||||||
{
|
{
|
||||||
distance_min = distance;
|
distance_min = distance;
|
||||||
chosen_color = c;
|
chosen_color = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_tcc_insert(color_msb, chosen_color);
|
||||||
#endif
|
#endif
|
||||||
return chosen_color;
|
return chosen_color;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue