From cc1c4f34336e1b91507271a68f198dcf4794bc92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Thu, 20 May 2021 22:11:06 -0400 Subject: [PATCH] Optimizations: 1) Keep a rectangle updated per-screen rather than regenerate each time 2) Strip palette info when putting pixels into rectangles rather than during scaling 3) Tighten up the screen locks a bit 4) Don't require a full resend of both screens on an update request 5) Only force a redraw for cursor movement when the cursor is visible (And force it whenever the cursor changes) 6) Avoid doubles in interpolation 7) Heavily optimize interpolate_height() interpolate_width() likely doesn't need it because it's generally not used and also it reads from the next pixel in memory making the prefetchers job easier. 8) Fix some memory-leak-on-error issues 9) For ARGB8 XImages, manipulate the data directly rather than through XPutPixel() At this point, the scaling and X11 output time is heavily dominated by cache misses. The only really effective way to reduce this hit is to spread the work across all the L3 caches in the system or move it into the GPU. With the latest updates, at the SyncTERM menu, over 90% of the time is spent in the rendering pipeline, and over 90% of that time is spent thrashing the caches... the only real easy win left is vectorizing, but that's highly compiler specific. To that end, I've switched to -O3 for release builds. There was a comment that -finline-functions broke Baja "badly", but that's clearly false since -f-inline-functions has been part of -O2 for quite a while now, and Baja doesn't seem any more broken that it ever was. --- src/build/Common.gmake | 6 +- src/conio/bitmap_con.c | 143 +++++++++++++++++++++++++++-------------- src/conio/scale.c | 93 ++++++++++++++++++++------- src/conio/x_events.c | 78 ++++++++++++---------- 4 files changed, 209 insertions(+), 111 deletions(-) diff --git a/src/build/Common.gmake b/src/build/Common.gmake index 0ab0f6fa92..3647ce4263 100644 --- a/src/build/Common.gmake +++ b/src/build/Common.gmake @@ -437,9 +437,9 @@ ifdef DEBUG CFLAGS += -D_DEBUG CFLAGS += -Wall -Wno-char-subscripts else # RELEASE - # -finline functions breaks the baja build badly. - # This also means that -O3 won't work either. - CFLAGS := -O2 -fomit-frame-pointer -ffast-math -funroll-loops $(CFLAGS) + # -finline-functions (used to) break the baja build badly. + # This also meant that -O3 wouldn't work either. + CFLAGS := -O3 -fomit-frame-pointer -ffast-math -funroll-loops $(CFLAGS) endif -include targets.mk diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c index 3809287461..35b523ef23 100644 --- a/src/conio/bitmap_con.c +++ b/src/conio/bitmap_con.c @@ -69,6 +69,7 @@ struct bitmap_screen { int screenheight; pthread_mutex_t screenlock; int update_pixels; + struct rectlist *rect; }; struct bitmap_callbacks { @@ -114,10 +115,11 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos); static void cb_flush(void); static int check_redraw(void); static void blinker_thread(void *data); -static __inline struct bitmap_screen *current_screen(void); +static __inline void both_screens(struct bitmap_screen** current, struct bitmap_screen** noncurrent); static int update_from_vmem(int force); static int bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fill); static uint32_t color_value(uint32_t col); +void bitmap_drv_free_rect(struct rectlist *rect); /**************************************************************/ /* These functions get called from the driver and ciolib only */ @@ -286,7 +288,8 @@ static int bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vme return(1); } -static void set_vmem_cell(struct vstat_vmem *vmem_ptr, size_t pos, uint16_t cell, uint32_t fg, uint32_t bg) +static void +set_vmem_cell(struct vstat_vmem *vmem_ptr, size_t pos, uint16_t cell, uint32_t fg, uint32_t bg) { int altfont; int font; @@ -436,16 +439,15 @@ static struct rectlist *alloc_full_rect(struct bitmap_screen *screen) static uint32_t color_value(uint32_t col) { if (col & 0x80000000) - return col; + return col & 0xffffff; if ((col & 0xffffff) < sizeof(palette) / sizeof(palette[0])) - return (col & 0xff000000) | palette[col & 0xffffff]; + return palette[col & 0xffffff] & 0xffffff; fprintf(stderr, "Invalid colour value: %08x\n", col); - return 0xff000000; + return 0; } static struct rectlist *get_full_rectangle_locked(struct bitmap_screen *screen) { - size_t i; struct rectlist *rect; // TODO: Some sort of caching here would make things faster...? @@ -453,8 +455,7 @@ static struct rectlist *get_full_rectangle_locked(struct bitmap_screen *screen) rect = alloc_full_rect(screen); if (!rect) return rect; - for (i=0; i<screen->screenwidth*screen->screenheight; i++) - rect->data[i] = color_value(screen->screen[i]); + memcpy(rect->data, screen->rect->data, sizeof(*rect->data) * screen->screenwidth * screen->screenheight); return rect; } return NULL; @@ -486,6 +487,7 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) uint8_t fb = 0; int y; int fontoffset; + int pixeloffset; unsigned char *this_font; WORD sch; struct vstat_vmem *vmem_ptr; @@ -501,22 +503,6 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) return(-1); } - pthread_mutex_lock(&screena.screenlock); - pthread_mutex_lock(&screenb.screenlock); - - if ((xoffset + vstat.charwidth > screena.screenwidth) || (yoffset + vstat.charheight > screena.screenheight) || - (xoffset + vstat.charwidth > screenb.screenwidth) || (yoffset + vstat.charheight > screenb.screenheight)) { - pthread_mutex_unlock(&screenb.screenlock); - pthread_mutex_unlock(&screena.screenlock); - return(-1); - } - - if((!screena.screen) || (!screenb.screen)) { - pthread_mutex_unlock(&screenb.screenlock); - pthread_mutex_unlock(&screena.screenlock); - return(-1); - } - sch=vmem_ptr->vmem[(ypos-1)*cio_textinfo.screenwidth+(xpos-1)].legacy_attr << 8 | vmem_ptr->vmem[(ypos-1)*cio_textinfo.screenwidth+(xpos-1)].ch; fg = vmem_ptr->vmem[(ypos-1)*cio_textinfo.screenwidth+(xpos-1)].fg; bg = vmem_ptr->vmem[(ypos-1)*cio_textinfo.screenwidth+(xpos-1)].bg; @@ -539,8 +525,6 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) this_font = (unsigned char *)conio_fontdata[vmem_ptr->vmem[(ypos-1)*cio_textinfo.screenwidth+(xpos-1)].font].eight_by_sixteen; break; default: - pthread_mutex_unlock(&screenb.screenlock); - pthread_mutex_unlock(&screena.screenlock); return(-1); } } @@ -550,7 +534,24 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) fdw = vstat.charwidth - (vstat.flags & VIDMODES_FLAG_EXPAND) ? 1 : 0; fontoffset=(sch & 0xff) * (vstat.charheight * ((fdw + 7) / 8)); + pthread_mutex_lock(&screena.screenlock); + pthread_mutex_lock(&screenb.screenlock); + + if ((xoffset + vstat.charwidth > screena.screenwidth) || (yoffset + vstat.charheight > screena.screenheight) || + (xoffset + vstat.charwidth > screenb.screenwidth) || (yoffset + vstat.charheight > screenb.screenheight)) { + pthread_mutex_unlock(&screenb.screenlock); + pthread_mutex_unlock(&screena.screenlock); + return(-1); + } + + if((!screena.screen) || (!screenb.screen)) { + pthread_mutex_unlock(&screenb.screenlock); + pthread_mutex_unlock(&screena.screenlock); + return(-1); + } + draw_fg = ((!(sch & 0x8000)) || vstat.no_blink); + pixeloffset = PIXEL_OFFSET(screena, xoffset, yoffset); for(y=0; y<vstat.charheight; y++) { for(x=0; x<vstat.charwidth; x++) { fdx = x; @@ -574,34 +575,39 @@ static int bitmap_draw_one_char(unsigned int xpos, unsigned int ypos) } if(fb & (0x80 >> (fdx & 7)) && draw_fg) { - if (screena.screen[PIXEL_OFFSET(screena, xoffset + x, yoffset + y)] != fg) { + if (screena.screen[pixeloffset] != fg) { screena.update_pixels = 1; - screena.screen[PIXEL_OFFSET(screena, xoffset + x, yoffset + y)] = fg; + screena.screen[pixeloffset] = fg; + screena.rect->data[pixeloffset] = color_value(fg); } } else { - if (screena.screen[PIXEL_OFFSET(screena, xoffset + x, yoffset + y)] != bg) { + if (screena.screen[pixeloffset] != bg) { screena.update_pixels = 1; - screena.screen[PIXEL_OFFSET(screena, xoffset + x, yoffset + y)] = bg; + screena.screen[pixeloffset] = bg; + screena.rect->data[pixeloffset] = color_value(bg); } } if(fb & (0x80 >> (fdx & 7))) { - if (screenb.screen[PIXEL_OFFSET(screenb, xoffset + x, yoffset + y)]!=fg) { + if (screenb.screen[pixeloffset] != fg) { screenb.update_pixels = 1; - screenb.screen[PIXEL_OFFSET(screenb, xoffset + x, yoffset + y)]=fg; + screenb.screen[pixeloffset] = fg; + screenb.rect->data[pixeloffset] = color_value(fg); } } else { - if (screenb.screen[PIXEL_OFFSET(screenb, xoffset+x, yoffset+y)]!=bg) { + if (screenb.screen[pixeloffset] != bg) { screenb.update_pixels = 1; - screenb.screen[PIXEL_OFFSET(screenb, xoffset+x, yoffset+y)]=bg; + screenb.screen[pixeloffset]=bg; + screenb.rect->data[pixeloffset] = color_value(bg); } } - + pixeloffset++; } if (x & 0x07) fontoffset++; + pixeloffset += screena.screenwidth - vstat.charwidth; } pthread_mutex_unlock(&screenb.screenlock); pthread_mutex_unlock(&screena.screenlock); @@ -642,6 +648,7 @@ static void blinker_thread(void *data) int curs_changed; int blink_changed; struct bitmap_screen *screen; + struct bitmap_screen *ncscreen; SetThreadName("Blinker"); while(1) { @@ -649,7 +656,7 @@ static void blinker_thread(void *data) blink_changed = 0; do { SLEEP(10); - screen = current_screen(); + both_screens(&screen, &ncscreen); } while (screen->screen == NULL); count++; if (count==25) { @@ -690,7 +697,13 @@ static void blinker_thread(void *data) request_redraw(); } pthread_mutex_lock(&screen->screenlock); + // TODO: Maybe we can optimize the blink_changed forced update? if (screen->update_pixels || curs_changed || blink_changed) { + // If the other screen is update_pixels == 2, clear it. + pthread_mutex_lock(&ncscreen->screenlock); + if (ncscreen->update_pixels == 2) + ncscreen->update_pixels = 0; + pthread_mutex_unlock(&ncscreen->screenlock); rect = get_full_rectangle_locked(screen); screen->update_pixels = 0; pthread_mutex_unlock(&screen->screenlock); @@ -711,6 +724,13 @@ static void blinker_thread(void *data) } } +static __inline struct bitmap_screen *noncurrent_screen_locked(void) +{ + if (vstat.blink) + return &screenb; + return &screena; +} + static __inline struct bitmap_screen *current_screen_locked(void) { if (vstat.blink) @@ -718,14 +738,12 @@ static __inline struct bitmap_screen *current_screen_locked(void) return(&screenb); } -static __inline struct bitmap_screen *current_screen(void) +static __inline void both_screens(struct bitmap_screen** current, struct bitmap_screen** noncurrent) { - struct bitmap_screen *ret; - pthread_mutex_lock(&vstatlock); - ret = current_screen_locked(); + *current = current_screen_locked(); + *noncurrent = noncurrent_screen_locked(); pthread_mutex_unlock(&vstatlock); - return(ret); } /* @@ -901,7 +919,8 @@ void bitmap_gotoxy(int x, int y) cio_textinfo.cury=y; vstat.curs_col = x + cio_textinfo.winleft - 1; vstat.curs_row = y + cio_textinfo.wintop - 1; - force_cursor = 1; + if (cursor_visible_locked()) + force_cursor = 1; } pthread_mutex_unlock(&vstatlock); pthread_mutex_unlock(&blinker_lock); @@ -921,10 +940,12 @@ void bitmap_setcursortype(int type) case _SOLIDCURSOR: vstat.curs_start=0; vstat.curs_end=vstat.charheight-1; + force_cursor = 1; break; default: vstat.curs_start = vstat.default_curs_start; vstat.curs_end = vstat.default_curs_end; + force_cursor = 1; break; } pthread_mutex_unlock(&vstatlock); @@ -1159,6 +1180,7 @@ int bitmap_movetext(int x, int y, int ex, int ey, int tox, int toy) pthread_mutex_lock(&screena.screenlock); for(screeny=0; screeny < height*vstat.charheight; screeny++) { memmove(&(screena.screen[ssourcepos+sdestoffset]), &(screena.screen[ssourcepos]), sizeof(screena.screen[0])*width*vstat.charwidth); + memmove(&(screena.rect->data[ssourcepos+sdestoffset]), &(screena.rect->data[ssourcepos]), sizeof(screena.screen[0])*width*vstat.charwidth); ssourcepos += direction * vstat.scrnwidth; } screena.update_pixels = 1; @@ -1176,6 +1198,7 @@ int bitmap_movetext(int x, int y, int ex, int ey, int tox, int toy) pthread_mutex_lock(&screenb.screenlock); for(screeny=0; screeny < height*vstat.charheight; screeny++) { memmove(&(screenb.screen[ssourcepos+sdestoffset]), &(screenb.screen[ssourcepos]), sizeof(screenb.screen[0])*width*vstat.charwidth); + memmove(&(screenb.rect->data[ssourcepos+sdestoffset]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.screen[0])*width*vstat.charwidth); ssourcepos += direction * vstat.scrnwidth; } screenb.update_pixels = 1; @@ -1265,6 +1288,7 @@ void bitmap_setcustomcursor(int s, int e, int r, int b, int v) vstat.curs_blinks=b; if(v>=0) vstat.curs_visible=v; + force_cursor = 1; pthread_mutex_unlock(&vstatlock); pthread_mutex_unlock(&blinker_lock); } @@ -1344,6 +1368,7 @@ int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour) if (screena.screen[PIXEL_OFFSET(screena, x, y)] != colour) { screena.screen[PIXEL_OFFSET(screena, x, y)]=colour; screena.update_pixels = 1; + screena.rect->data[PIXEL_OFFSET(screena, x, y)]=color_value(colour); } } pthread_mutex_unlock(&screena.screenlock); @@ -1353,6 +1378,7 @@ int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour) if (screenb.screen[PIXEL_OFFSET(screenb, x, y)] != colour) { screenb.screen[PIXEL_OFFSET(screenb, x, y)]=colour; screenb.update_pixels = 1; + screenb.rect->data[PIXEL_OFFSET(screenb, x, y)]=color_value(colour); } } pthread_mutex_unlock(&screenb.screenlock); @@ -1401,10 +1427,14 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_ if (mask == NULL) { for (x = sx; x <= ex; x++) { screena.screen[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos]; - if (pixels->pixelsb) + if (pixels->pixelsb) { screenb.screen[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos]; - else + screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = color_value(pixels->pixelsb[pos]); + } + else { screenb.screen[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos]; + screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = color_value(pixels->pixels[pos]); + } pos++; } } @@ -1415,10 +1445,15 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_ mask_bit = 0x80 >> mask_bit; if (m[mask_byte] & mask_bit) { screena.screen[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos]; - if (pixels->pixelsb) + screena.rect->data[PIXEL_OFFSET(screena, x, y)] = color_value(pixels->pixels[pos]); + if (pixels->pixelsb) { screenb.screen[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos]; - else + screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = color_value(pixels->pixelsb[pos]); + } + else { screenb.screen[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos]; + screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = color_value(pixels->pixels[pos]); + } } pos++; } @@ -1597,6 +1632,13 @@ static int init_screen(struct bitmap_screen *screen, int *width, int *height) screen->screen = newscreen; memset_u32(screen->screen, vstat.palette[0], screen->screenwidth * screen->screenheight); screen->update_pixels = 1; + bitmap_drv_free_rect(screen->rect); + screen->rect = alloc_full_rect(screen); + if (screen->rect == NULL) { + pthread_mutex_unlock(&screen->screenlock); + return(-1); + } + memset_u32(screen->rect->data, color_value(vstat.palette[0]), screen->rect->rect.width * screen->rect->rect.height); pthread_mutex_unlock(&screen->screenlock); return(0); } @@ -1714,12 +1756,13 @@ int bitmap_drv_init(void (*drawrect_cb) (struct rectlist *data) void bitmap_drv_request_pixels(void) { - // TODO: We may need something extra now... this results in two updates. pthread_mutex_lock(&screena.screenlock); - screena.update_pixels = 1; + if (screena.update_pixels == 0) + screena.update_pixels = 2; pthread_mutex_unlock(&screena.screenlock); pthread_mutex_lock(&screenb.screenlock); - screenb.update_pixels = 1; + if (screenb.update_pixels == 0) + screenb.update_pixels = 2; pthread_mutex_unlock(&screenb.screenlock); } @@ -1731,6 +1774,8 @@ void bitmap_drv_request_some_pixels(int x, int y, int width, int height) void bitmap_drv_free_rect(struct rectlist *rect) { + if (rect == NULL) + return; pthread_mutex_lock(&free_rect_lock); rect->next = free_rects; free_rects = rect; diff --git a/src/conio/scale.c b/src/conio/scale.c index 6b5c0d8b97..a029b03929 100644 --- a/src/conio/scale.c +++ b/src/conio/scale.c @@ -185,6 +185,8 @@ get_buffer(void) void release_buffer(struct graphics_buffer *buf) { + if (buf == NULL) + return; buf->next = free_list; free_list = buf; } @@ -724,30 +726,29 @@ pointy_scale3(uint32_t* src, uint32_t* dest, int width, int height) } } -static -uint32_t blend(const uint32_t c1, const uint32_t c2, const double weight) +static uint32_t +blend(const uint32_t c1, const uint32_t c2, int weight) { uint8_t yuv1[4]; uint8_t yuv2[4]; - int y, u, v; - const double iw = 1.0 - weight; + uint8_t yuv3[4]; + const double iw = 256 - weight; *(uint32_t *)yuv1 = r2y[c1]; *(uint32_t *)yuv2 = r2y[c2]; #ifdef __BIG_ENDIAN__ - y = yuv1[1] * iw + yuv2[1] * weight; - u = yuv1[2] * iw + yuv2[2] * weight; - v = yuv1[3] * iw + yuv2[3] * weight; + yuv3[0] = 0; + yuv3[1] = (yuv1[1] * iw + yuv2[1] * weight) / 256; + yuv3[2] = (yuv1[2] * iw + yuv2[2] * weight) / 256; + yuv3[3] = (yuv1[3] * iw + yuv2[3] * weight) / 256; #else - y = yuv1[2] * iw + yuv2[2] * weight; - u = yuv1[1] * iw + yuv2[1] * weight; - v = yuv1[0] * iw + yuv2[0] * weight; + yuv3[3] = 0; + yuv3[2] = (yuv1[2] * iw + yuv2[2] * weight) / 256; + yuv3[1] = (yuv1[1] * iw + yuv2[1] * weight) / 256; + yuv3[0] = (yuv1[0] * iw + yuv2[0] * weight) / 256; #endif - CLAMP(y); - CLAMP(u); - CLAMP(v); - return y2r[(y<<16)|(u<<8)|v]; + return y2r[*(uint32_t*)yuv3]; } /* @@ -773,12 +774,12 @@ interpolate_width(uint32_t* src, uint32_t* dst, int width, int height, int newwi else { const double weight = xpos - xposi; // Now pick the two pixels - const uint32_t pix1 = src[y * width + xposi] & 0xffffff; + const uint32_t pix1 = src[y * width + xposi]; uint32_t pix2; if (xposi < width - 1) - pix2 = src[y * width + xposi + 1] & 0xffffff; + pix2 = src[y * width + xposi + 1]; else - pix2 = src[y * width + xposi] & 0xffffff; + pix2 = src[y * width + xposi]; if (pix1 == pix2) *dst = pix1; else { @@ -799,23 +800,53 @@ static void interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newheight) { int x, y; - bool em = false; const double mult = (double)height / newheight; + double ypos = 0; + int last_yposi = 0; + int ywn = width; + static uint32_t *nline = NULL; + static uint32_t *tline = NULL; + static size_t nsz = 0; + static size_t tsz = 0; + uint32_t *stmp; + + if (nsz < width * 4) { + stmp = realloc(nline, width * 4); + if (stmp == NULL) + goto fail; + nline = stmp; + nsz = width * 4; + } + if (tsz < width * 4) { + stmp = realloc(tline, width * 4); + if (stmp == NULL) + goto fail; + tline = stmp; + tsz = width * 4; + } + memcpy(tline, src, width * sizeof(*tline)); + memcpy(nline, src + width, width * sizeof(*tline)); for (y = 0; y < newheight; y++) { - const double ypos = mult * y; const int yposi = ypos; - em = (y == ypos || yposi >= height - 1); - if (em) { - memcpy(dst, &src[yposi * width], width * sizeof(dst[0])); + if (yposi != last_yposi) { + ywn += width; + last_yposi = yposi; + stmp = tline; + tline = nline; + nline = stmp; + memcpy(nline, &src[ywn], nsz); + } + if (y == ypos || yposi >= height - 1) { + memcpy(dst, tline, tsz); dst += width; } else { - const double weight = ypos - yposi; + const uint8_t weight = ypos * 256; for (x = 0; x < width; x++) { // Now pick the two pixels - const uint32_t pix1 = src[yposi * width + x] & 0xffffff; - const uint32_t pix2 = src[(yposi + 1) * width + x] & 0xffffff; + const uint32_t pix1 = tline[x]; + const uint32_t pix2 = nline[x]; if (pix1 == pix2) *dst = pix1; else @@ -823,7 +854,19 @@ interpolate_height(uint32_t* src, uint32_t* dst, int width, int height, int newh dst++; } } + ypos += mult; } + + return; +fail: + free(nline); + free(tline); + nline = NULL; + tline = NULL; + nsz = 0; + tsz = 0; + memcpy(src, dst, width * height * sizeof(*src)); + fprintf(stderr, "Allocation failure in interpolate_height()!"); } static void diff --git a/src/conio/x_events.c b/src/conio/x_events.c index 8266622e61..086ca7d38d 100644 --- a/src/conio/x_events.c +++ b/src/conio/x_events.c @@ -464,7 +464,8 @@ static int video_init() return(0); } -static void local_draw_rect(struct rectlist *rect) +static void +local_draw_rect(struct rectlist *rect) { int x, y, xoff = 0, yoff = 0; unsigned int r, g, b; @@ -476,10 +477,12 @@ static void local_draw_rect(struct rectlist *rect) int idx; uint32_t last_pixel = 0x55555555; struct graphics_buffer *source; - int lines; + bool isRGB8 = false; - if (bitmap_width != rect->rect.width || bitmap_height != rect->rect.height) + if (bitmap_width != rect->rect.width || bitmap_height != rect->rect.height) { + bitmap_drv_free_rect(rect); return; + } xoff = (x11_window_width - xim->width) / 2; if (xoff < 0) @@ -490,12 +493,12 @@ static void local_draw_rect(struct rectlist *rect) // Scale... source = do_scale(rect, x_cvstat.scaling, x_cvstat.scaling, x_cvstat.aspect_width, x_cvstat.aspect_height); - bitmap_drv_free_rect(rect); - if (source == NULL) + if (source == NULL) { + bitmap_drv_free_rect(rect); return; + } cleft = source->w; ctop = source->h; - lines = 0; xoff = (x11_window_width - source->w) / 2; if (xoff < 0) @@ -511,6 +514,9 @@ static void local_draw_rect(struct rectlist *rect) /* TODO: Translate into local colour depth */ idx = 0; + if (visual.red_mask == 0xff0000 && visual.green_mask == 0x00ff00 && visual.blue_mask == 0x0000ff) + isRGB8 = true; + for (y = 0; y < source->h; y++) { for (x = 0; x < source->w; x++) { if (last) { @@ -529,40 +535,44 @@ static void local_draw_rect(struct rectlist *rect) continue; } } - if (last_pixel != source->data[idx]) { - last_pixel = source->data[idx]; - r = source->data[idx] >> 16 & 0xff; - g = source->data[idx] >> 8 & 0xff; - b = source->data[idx] & 0xff; - r = (r<<8)|r; - g = (g<<8)|g; - b = (b<<8)|b; - pixel = base_pixel; - if (r_shift >= 0) - pixel |= (r << r_shift) & visual.red_mask; - else - pixel |= (r >> (0-r_shift)) & visual.red_mask; - if (g_shift >= 0) - pixel |= (g << g_shift) & visual.green_mask; - else - pixel |= (g >> (0-g_shift)) & visual.green_mask; - if (b_shift >= 0) - pixel |= (b << b_shift) & visual.blue_mask; - else - pixel |= (b >> (0-b_shift)) & visual.blue_mask; + if (isRGB8) { + pixel = source->data[idx]; + ((uint32_t*)xim->data)[idx] = pixel; } + else { + if (last_pixel != source->data[idx]) { + last_pixel = source->data[idx]; + r = source->data[idx] >> 16 & 0xff; + g = source->data[idx] >> 8 & 0xff; + b = source->data[idx] & 0xff; + r = (r<<8)|r; + g = (g<<8)|g; + b = (b<<8)|b; + pixel = base_pixel; + if (r_shift >= 0) + pixel |= (r << r_shift) & visual.red_mask; + else + pixel |= (r >> (0-r_shift)) & visual.red_mask; + if (g_shift >= 0) + pixel |= (g << g_shift) & visual.green_mask; + else + pixel |= (g >> (0-g_shift)) & visual.green_mask; + if (b_shift >= 0) + pixel |= (b << b_shift) & visual.blue_mask; + else + pixel |= (b >> (0-b_shift)) & visual.blue_mask; + } #ifdef XPutPixel - XPutPixel(xim, (x + rect->rect.x), (y + rect->rect.y), pixel); + XPutPixel(xim, x, y, pixel); #else - x11.XPutPixel(xim, (x + rect->rect.x), (y + rect->rect.y), pixel); + x11.XPutPixel(xim, x, y, pixel); #endif + } idx++; } - lines++; /* This line was changed */ // TODO: Previously this did one update per display line... - if (last && (cbottom != y || y == source->h - 1) && cright >= 0) { - lines = 0; + if (last && cright >= 0 && (cbottom != y || y == source->h - 1)) { x11.XPutImage(dpy, win, gc, xim, cleft, ctop , cleft + xoff, ctop + yoff , (cright - cleft + 1), (cbottom - ctop + 1)); @@ -573,7 +583,7 @@ static void local_draw_rect(struct rectlist *rect) } if (last == NULL) - x11.XPutImage(dpy, win, gc, xim, rect->rect.x, rect->rect.y, rect->rect.x + xoff, rect->rect.y + yoff, source->w, source->h); + x11.XPutImage(dpy, win, gc, xim, 0, 0, xoff, yoff, source->w, source->h); else release_buffer(last); last = source; @@ -1231,7 +1241,7 @@ void x11_event_thread(void *args) case -1: /* * Errno might be wrong, so we just select again. - * This could cause a problem is something really + * This could cause a problem if something really * was wrong with select.... */ -- GitLab