[PATCH v2 2/3] gdi32: Generate and use a lookup cache when looking up RGB values for a color table.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Fri Apr 2 07:54:01 CDT 2021
For now the generating algorithm is straightforward, but can be improved
in the future.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50898
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>
---
dlls/gdi32/dibdrv/primitives.c | 61 +++++++++++++++++++++++++---------
1 file changed, 45 insertions(+), 16 deletions(-)
diff --git a/dlls/gdi32/dibdrv/primitives.c b/dlls/gdi32/dibdrv/primitives.c
index 0a5f7e5..8947c60 100644
--- a/dlls/gdi32/dibdrv/primitives.c
+++ b/dlls/gdi32/dibdrv/primitives.c
@@ -3497,22 +3497,44 @@ static void convert_to_16(dib_info *dst, const dib_info *src, const RECT *src_re
}
}
-static inline BOOL color_tables_match(const dib_info *d1, const dib_info *d2)
+/*
+ * To lookup RGB values into nearest color in the color table, Windows uses 5-bits of the RGB
+ * at the "center" of the RGB cube, presumably to do a similar lookup cache. The lowest 3 bits
+ * of the color are thus set to halfway (0x04) and then it's used in the distance calculation
+ * to the exact color in the color table. We exploit this as well to create a lookup cache.
+*/
+struct rgb_lookup_colortable_ctx
+{
+ /* lookup table indexed by 5-bit-per-color RGB into a color table */
+ BYTE map[32 * 32 * 32];
+};
+
+static void rgb_lookup_colortable_init(const dib_info *dib, struct rgb_lookup_colortable_ctx *ctx)
{
- if (!d1->color_table || !d2->color_table) return (!d1->color_table && !d2->color_table);
- return !memcmp(d1->color_table, d2->color_table, (1 << d1->bit_count) * sizeof(d1->color_table[0]));
+ unsigned r, g, b;
+
+ for (b = 4; b < 256; b += 1 << 3)
+ for (g = 4; g < 256; g += 1 << 3)
+ for (r = 4; r < 256; r += 1 << 3)
+ ctx->map[r >> 3 | (g & ~7) << 2 | (b & ~7) << 7] = rgb_to_pixel_colortable(dib, r, g, b);
}
-static inline DWORD rgb_lookup_colortable(const dib_info *dst, BYTE r, BYTE g, BYTE b)
+static inline BYTE rgb_lookup_colortable(const struct rgb_lookup_colortable_ctx *ctx, BYTE r, BYTE g, BYTE b)
{
- /* Windows reduces precision to 5 bits, probably in order to build some sort of lookup cache */
- return rgb_to_pixel_colortable( dst, (r & ~7) + 4, (g & ~7) + 4, (b & ~7) + 4 );
+ return ctx->map[(r >> 3) | (g & ~7) << 2 | (b & ~7) << 7];
+}
+
+static inline BOOL color_tables_match(const dib_info *d1, const dib_info *d2)
+{
+ if (!d1->color_table || !d2->color_table) return (!d1->color_table && !d2->color_table);
+ return !memcmp(d1->color_table, d2->color_table, (1 << d1->bit_count) * sizeof(d1->color_table[0]));
}
static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rect, BOOL dither)
{
BYTE *dst_start = get_pixel_ptr_8(dst, 0, 0), *dst_pixel;
INT x, y, pad_size = ((dst->width + 3) & ~3) - (src_rect->right - src_rect->left);
+ struct rgb_lookup_colortable_ctx lookup_ctx;
DWORD src_val;
switch(src->bit_count)
@@ -3521,6 +3543,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
{
DWORD *src_start = get_pixel_ptr_32(src, src_rect->left, src_rect->top), *src_pixel;
+ rgb_lookup_colortable_init(dst, &lookup_ctx);
if(src->funcs == &funcs_8888)
{
for(y = src_rect->top; y < src_rect->bottom; y++)
@@ -3530,7 +3553,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst, src_val >> 16, src_val >> 8, src_val );
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx, src_val >> 16, src_val >> 8, src_val );
}
if(pad_size) memset(dst_pixel, 0, pad_size);
dst_start += dst->stride;
@@ -3546,7 +3569,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
src_val >> src->red_shift,
src_val >> src->green_shift,
src_val >> src->blue_shift );
@@ -3565,7 +3588,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
get_field(src_val, src->red_shift, src->red_len),
get_field(src_val, src->green_shift, src->green_len),
get_field(src_val, src->blue_shift, src->blue_len));
@@ -3582,13 +3605,14 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
{
BYTE *src_start = get_pixel_ptr_24(src, src_rect->left, src_rect->top), *src_pixel;
+ rgb_lookup_colortable_init(dst, &lookup_ctx);
for(y = src_rect->top; y < src_rect->bottom; y++)
{
dst_pixel = dst_start;
src_pixel = src_start;
for(x = src_rect->left; x < src_rect->right; x++, src_pixel += 3)
{
- *dst_pixel++ = rgb_lookup_colortable(dst, src_pixel[2], src_pixel[1], src_pixel[0] );
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx, src_pixel[2], src_pixel[1], src_pixel[0] );
}
if(pad_size) memset(dst_pixel, 0, pad_size);
dst_start += dst->stride;
@@ -3600,6 +3624,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
case 16:
{
WORD *src_start = get_pixel_ptr_16(src, src_rect->left, src_rect->top), *src_pixel;
+ rgb_lookup_colortable_init(dst, &lookup_ctx);
if(src->funcs == &funcs_555)
{
for(y = src_rect->top; y < src_rect->bottom; y++)
@@ -3609,7 +3634,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
((src_val >> 7) & 0xf8) | ((src_val >> 12) & 0x07),
((src_val >> 2) & 0xf8) | ((src_val >> 7) & 0x07),
((src_val << 3) & 0xf8) | ((src_val >> 2) & 0x07) );
@@ -3628,7 +3653,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
(((src_val >> src->red_shift) << 3) & 0xf8) |
(((src_val >> src->red_shift) >> 2) & 0x07),
(((src_val >> src->green_shift) << 3) & 0xf8) |
@@ -3650,7 +3675,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
(((src_val >> src->red_shift) << 3) & 0xf8) |
(((src_val >> src->red_shift) >> 2) & 0x07),
(((src_val >> src->green_shift) << 2) & 0xfc) |
@@ -3672,7 +3697,7 @@ static void convert_to_8(dib_info *dst, const dib_info *src, const RECT *src_rec
for(x = src_rect->left; x < src_rect->right; x++)
{
src_val = *src_pixel++;
- *dst_pixel++ = rgb_lookup_colortable(dst,
+ *dst_pixel++ = rgb_lookup_colortable(&lookup_ctx,
get_field(src_val, src->red_shift, src->red_len),
get_field(src_val, src->green_shift, src->green_len),
get_field(src_val, src->blue_shift, src->blue_len));
@@ -4807,8 +4832,10 @@ static void blend_rect_8(const dib_info *dst, const dib_info *src, const POINT *
const struct clipped_rects *clipped_rects, BLENDFUNCTION blend)
{
const RGBQUAD *color_table = get_dib_color_table( dst );
+ struct rgb_lookup_colortable_ctx lookup_ctx;
int i, x, y;
+ rgb_lookup_colortable_init( dst, &lookup_ctx );
for (i = 0; i < clipped_rects->count; i++)
{
const RECT *rc = &clipped_rects->rects[i];
@@ -4821,7 +4848,7 @@ static void blend_rect_8(const dib_info *dst, const dib_info *src, const POINT *
{
RGBQUAD rgb = color_table[dst_ptr[x]];
DWORD val = blend_rgb( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, src_ptr[x], blend );
- dst_ptr[x] = rgb_lookup_colortable( dst, val >> 16, val >> 8, val );
+ dst_ptr[x] = rgb_lookup_colortable( &lookup_ctx, val >> 16, val >> 8, val );
}
}
}
@@ -4831,8 +4858,10 @@ static void blend_rect_4(const dib_info *dst, const dib_info *src, const POINT *
const struct clipped_rects *clipped_rects, BLENDFUNCTION blend)
{
const RGBQUAD *color_table = get_dib_color_table( dst );
+ struct rgb_lookup_colortable_ctx lookup_ctx;
int i, j, x, y;
+ rgb_lookup_colortable_init( dst, &lookup_ctx );
for (i = 0; i < clipped_rects->count; i++)
{
const RECT *rc = &clipped_rects->rects[i];
@@ -4846,7 +4875,7 @@ static void blend_rect_4(const dib_info *dst, const dib_info *src, const POINT *
DWORD val = ((x & 1) ? dst_ptr[x / 2] : (dst_ptr[x / 2] >> 4)) & 0x0f;
RGBQUAD rgb = color_table[val];
val = blend_rgb( rgb.rgbRed, rgb.rgbGreen, rgb.rgbBlue, src_ptr[j], blend );
- val = rgb_lookup_colortable( dst, val >> 16, val >> 8, val );
+ val = rgb_lookup_colortable( &lookup_ctx, val >> 16, val >> 8, val );
if (x & 1)
dst_ptr[x / 2] = val | (dst_ptr[x / 2] & 0xf0);
else
--
2.30.0
More information about the wine-devel
mailing list