From 3ef9938aa9e71b04505327b14d2f090615d17fca Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 15 Jan 2022 00:41:14 +1100 Subject: [PATCH] X11: Fix launcher appearing completely corrupted when visual depth is not 24/32 bit depth --- src/Window_X11.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-- src/_WindowBase.h | 14 +++++---- 2 files changed, 82 insertions(+), 9 deletions(-) diff --git a/src/Window_X11.c b/src/Window_X11.c index 234d2f848..c87632f4b 100644 --- a/src/Window_X11.c +++ b/src/Window_X11.c @@ -968,16 +968,86 @@ static void ShowDialogCore(const char* title, const char* msg) { static GC fb_gc; static XImage* fb_image; +static struct Bitmap fb_bmp; +static void* fb_data; +static int fb_fast; +static int fb_rShift, fb_gShift, fb_bShift; +static int fb_rOffset, fb_gOffset, fb_bOffset; + +static int CountSetBits(cc_uint32 i) { + i = i - ((i >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + i = (i + (i >> 4)) & 0x0F0F0F0F; + return (i * 0x01010101) >> 24; +} + +/* Calculates adjustments from 24 bit depth to depth of window visual */ +static void CalcRGBAdjustments(void) { + int rBits = CountSetBits(win_visual.red_mask); + int gBits = CountSetBits(win_visual.green_mask); + int bBits = CountSetBits(win_visual.blue_mask); + + /* e.g. for 8 bits to 6 bits, need to drop 2 lowest bits */ + fb_bShift = 8 - rBits; + fb_gShift = 8 - gBits; + fb_rShift = 8 - bBits; + + fb_bOffset = 0; + fb_gOffset = bBits; + fb_rOffset = bBits + gBits; +} + void Window_AllocFramebuffer(struct Bitmap* bmp) { if (!fb_gc) fb_gc = XCreateGC(win_display, win_handle, 0, NULL); - bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); - fb_image = XCreateImage(win_display, win_visual.visual, - win_visual.depth, ZPixmap, 0, (char*)bmp->scan0, + + /* X11 requires that the image to draw has same depth as window */ + /* Easy for 24/32 bit case, but much trickier with other depths */ + /* (have to do a manual and slow second blit for other depths) */ + fb_fast = win_visual.depth == 24 || win_visual.depth == 32; + fb_data = fb_fast ? bmp->scan0 : Mem_Alloc(bmp->width * bmp->height, 4, "window blit"); + CalcRGBAdjustments(); + + fb_bmp = *bmp; + fb_image = XCreateImage(win_display, win_visual.visual, + win_visual.depth, ZPixmap, 0, fb_data, bmp->width, bmp->height, 32, 0); } +static void BlitFramebuffer(int x1, int y1, int width, int height) { + unsigned long pixel; + BitmapCol src; + int x, y; + + for (y = y1; y < y1 + height; y++) { + BitmapCol* row = Bitmap_GetRow(&fb_bmp, y); + for (x = x1; x < x1 + width; x++) { + src = row[x]; + + /* e.g. for 24 to 16 bit depth (R5 G5 B5): */ + /* B is shifted right 3 bits, then shifted left 0 bits */ + /* G is shifted right 2 bits, then shifted left 5 bits */ + /* R is shifted right 3 bits, then shifted left 6+5 bits */ + /* Visually explained + /* rrrrrrrr:gggggggg:bbbbbbbb */ + /* ||||| |||||| :||||| + /* rrrrr gggggg :bbbbb */ + /* \\\\\ \\\\\\ ||||| + /* rrrrrggg:gggbbbbb*/ + pixel = + ((BitmapCol_R(src) >> fb_rShift) << fb_rOffset) | + ((BitmapCol_G(src) >> fb_gShift) << fb_gOffset) | + ((BitmapCol_B(src) >> fb_bShift) << fb_bOffset); + + XPutPixel(fb_image, x, y, pixel); + } + } +} + void Window_DrawFramebuffer(Rect2D r) { + /* Convert 32 bit depth to window depth when required */ + if (!fb_fast) BlitFramebuffer(r.X, r.Y, r.Width, r.Height); + XPutImage(win_display, win_handle, fb_gc, fb_image, r.X, r.Y, r.X, r.Y, r.Width, r.Height); } @@ -985,6 +1055,7 @@ void Window_DrawFramebuffer(Rect2D r) { void Window_FreeFramebuffer(struct Bitmap* bmp) { XFree(fb_image); Mem_Free(bmp->scan0); + if (bmp->scan0 != fb_data) Mem_Free(fb_data); } void Window_OpenKeyboard(const struct OpenKeyboardArgs* args) { } diff --git a/src/_WindowBase.h b/src/_WindowBase.h index 4acd278ec..d806bea24 100644 --- a/src/_WindowBase.h +++ b/src/_WindowBase.h @@ -79,17 +79,19 @@ static void InitGraphicsMode(struct GraphicsMode* m) { m->A = 0; switch (bpp) { case 32: - m->R = 8; m->G = 8; m->B = 8; m->A = 8; break; + m->R = 8; m->G = 8; m->B = 8; m->A = 8; break; + case 30: + m->R = 10; m->G = 10; m->B = 10; m->A = 2; break; case 24: - m->R = 8; m->G = 8; m->B = 8; break; + m->R = 8; m->G = 8; m->B = 8; break; case 16: - m->R = 5; m->G = 6; m->B = 5; break; + m->R = 5; m->G = 6; m->B = 5; break; case 15: - m->R = 5; m->G = 5; m->B = 5; break; + m->R = 5; m->G = 5; m->B = 5; break; case 8: - m->R = 3; m->G = 3; m->B = 2; break; + m->R = 3; m->G = 3; m->B = 2; break; case 4: - m->R = 2; m->G = 2; m->B = 1; break; + m->R = 2; m->G = 2; m->B = 1; break; default: /* mode->R = 0; mode->G = 0; mode->B = 0; */ Logger_Abort2(bpp, "Unsupported bits per pixel"); break;