From 9c871efc203959ef38f4e3be65ff470d4871a285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Thu, 9 Jan 2025 20:34:00 -0500 Subject: [PATCH] Massive SyncTERM performance overhaul. This makes the performance about seven times better. Previously, outputting the entire works of Shakespeare took about two minutes, nineteen seconds on my system. With this change, it takes about 19 seconds. This is still far behind non-BBS terminals like XTerm and Alacritty which tend to do that job in under one second. The main improvements: - For the bitmaps in memory, make them a ring buffer, and for full-width scrolling of more than half the screen, just move the top instead of a memmove() - Eliminate unnecessary comparisons and calculations in the glyph rendering loop - Combine drawing glyphs beside each other for better cache usage This still needs some cleanup, and much testing. --- src/conio/bitmap_con.c | 561 ++++++++++++++++++++++++++--------------- src/conio/cterm.c | 4 + 2 files changed, 361 insertions(+), 204 deletions(-) diff --git a/src/conio/bitmap_con.c b/src/conio/bitmap_con.c index 7e6589fca4..f3a3263ed3 100644 --- a/src/conio/bitmap_con.c +++ b/src/conio/bitmap_con.c @@ -1,5 +1,6 @@ /* $Id: bitmap_con.c,v 1.148 2020/06/27 00:04:44 deuce Exp $ */ +#include <assert.h> #include <math.h> #include <stdarg.h> #include <stdbool.h> @@ -74,6 +75,7 @@ struct bitmap_screen { //uint32_t *screen; int screenwidth; int screenheight; + int toprow; int update_pixels; struct rectlist *rect; }; @@ -104,9 +106,6 @@ static int outstanding_rects; // win32gdi requires two rects... #define MAX_OUTSTANDING 2 -/* The read lock must be held here. */ -#define PIXEL_OFFSET(screen, x, y) ( (y)*(screen).screenwidth+(x) ) - /* Exported globals */ pthread_mutex_t vstatlock; @@ -120,7 +119,6 @@ static void cb_drawrect(struct rectlist *data); static void request_redraw_locked(void); static void request_redraw(void); static void memset_u32(void *buf, uint32_t u, size_t len); -static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigned int ypos); static void cb_flush(void); static int check_redraw(void); static void blinker_thread(void *data); @@ -128,6 +126,7 @@ static __inline void both_screens(int blink, struct bitmap_screen** current, str static int update_from_vmem(int force); static uint32_t color_value(uint32_t col); void bitmap_drv_free_rect(struct rectlist *rect); +static void bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill); /**************************************************************/ /* These functions get called from the driver and ciolib only */ @@ -269,6 +268,7 @@ bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fil int x,y; struct vstat_vmem *vmem_ptr; struct vmem_cell *vc; + struct vmem_cell *fi = fill; if(!bitmap_initialized) return(0); @@ -288,10 +288,10 @@ bitmap_vmem_puttext_locked(int sx, int sy, int ex, int ey, struct vmem_cell *fil for(y=sy-1;y<ey;y++) { for(x=sx-1;x<ex;x++) { vc = &vmem_ptr->vmem[y*cio_textinfo.screenwidth+x]; - memcpy(vc, fill++, sizeof(*fill)); - bitmap_draw_one_char(vc, x+1, y+1); + memcpy(vc, fi++, sizeof(*fi)); } } + bitmap_draw_vmem(sx, sy, ex, ey, fill); release_vmem(vmem_ptr); return(1); } @@ -497,15 +497,18 @@ static struct rectlist *get_full_rectangle_locked(struct bitmap_screen *screen) { struct rectlist *rect; size_t sz = screen->screenwidth * screen->screenheight; - size_t pos; + size_t pos, spos; // TODO: Some sort of caching here would make things faster...? if(callbacks.drawrect) { rect = alloc_full_rect(screen, true); if (!rect) return rect; - for (pos = 0; pos < sz; pos++) - rect->data[pos] = color_value(screen->rect->data[pos]); + for (pos = 0, spos = screen->screenwidth * screen->toprow; pos < sz; pos++, spos++) { + if (spos >= sz) + spos -= sz; + rect->data[pos] = color_value(screen->rect->data[spos]); + } return rect; } return NULL; @@ -522,90 +525,90 @@ static void memset_u32(void *buf, uint32_t u, size_t len) } } -// vstatlock must be held -static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigned int ypos) +/* The read lock must be held here. */ +static int +pixel_offset(struct bitmap_screen *screen, int x, int y) { - uint32_t fg; + y += screen->toprow; + if (y >= screen->screenheight) + y -= screen->screenheight; + return y * screen->screenwidth + x; +} + +struct charstate { + unsigned char *font; + uint32_t afc; + uint32_t bfc; uint32_t bg; - int fdw; - int xoffset; - int yoffset; - int x; - int fdx; - uint8_t fb = 0; - uint8_t fbb = 0; - int y; - int fontoffset; - int pixeloffset; - unsigned char *this_font; - WORD sch; - BOOL draw_fg = TRUE; - size_t rsz; - bool double_height = false; - bool bottom = false; - bool top = false; - bool not_hidden = true; + uint32_t fontoffset; + int8_t extra_rows; + bool double_height; + bool gexpand; +}; - if(!bitmap_initialized) { - return(-1); - } +struct blockstate { + int pixeloffset; + int maxpix; + int font_data_width; + uint32_t cheat_colour; + bool expand; +}; - xoffset=(xpos-1)*vstat.charwidth; - yoffset=(ypos-1)*vstat.charheight; - draw_fg = ((!(vc->legacy_attr & 0x80)) || vstat.no_blink); - sch = vc->ch; - fg = vc->fg; - bg = vc->bg; +static bool +can_cheat(struct blockstate *bs, struct vmem_cell *vc) +{ + return vc->bg == bs->cheat_colour && (vc->ch == ' ') && (vc->font < CONIO_FIRST_FREE_FONT) && !(vc->bg & 0x02000000); +} + +// Returns false if we can't chate, true otherwise +static void +calc_charstate(struct blockstate *bs, struct vmem_cell *vc, struct charstate *cs, int xpos, int ypos) +{ + bool not_hidden = true; if (vstat.forced_font) { - this_font = vstat.forced_font; + cs->font = vstat.forced_font; } else { if (current_font[0] == -1) - this_font = font[0]; + cs->font = font[0]; else { switch (vstat.charheight) { case 8: - this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_eight; + cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_eight; break; case 14: - this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_fourteen; + cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_fourteen; break; case 16: - this_font = (unsigned char *)conio_fontdata[vc->font].eight_by_sixteen; + cs->font = (unsigned char *)conio_fontdata[vc->font].eight_by_sixteen; break; default: - return(-1); + assert(0); } } } - if (this_font == NULL) { - this_font = font[0]; - } - if (this_font == NULL) - return(-1); - fdw = vstat.charwidth - (vstat.flags & VIDMODES_FLAG_EXPAND) ? 1 : 0; - fontoffset=(sch) * (vstat.charheight * ((fdw + 7) / 8)); - - pthread_mutex_lock(&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(&screenlock); - return(-1); - } - - if((!screena.rect) || (!screenb.rect)) { - pthread_mutex_unlock(&screenlock); - return(-1); + if (cs->font == NULL) { + cs->font = font[0]; } + assert(cs->font); + bool draw_fg = ((!(vc->legacy_attr & 0x80)) || vstat.no_blink); + cs->fontoffset = (vc->ch) * (vstat.charheight * ((bs->font_data_width + 7) / 8)); + cs->double_height = false; + if ((vstat.flags & VIDMODES_FLAG_LINE_GRAPHICS_EXPAND) && (vc->ch) >= 0xC0 && (vc->ch) <= 0xDF) + cs->gexpand = true; + else + cs->gexpand = false; + uint32_t fg = vc->fg; + cs->bg = vc->bg; + cs->extra_rows = 0; - pixeloffset = PIXEL_OFFSET(screena, xoffset, yoffset); - rsz = screena.screenwidth - vstat.charwidth; - // PRESTEL! - if (vstat.mode == PRESTEL_40X24) { + if (vstat.mode == PRESTEL_40X24 && (vc->bg & 0x02000000)) { struct vstat_vmem *vmem_ptr = get_vmem(&vstat); unsigned char lattr = vc->legacy_attr; + int x, y; + bool top = false; + bool bottom = false; for (y = 0; y < ypos; y++) { if (top) { @@ -625,29 +628,27 @@ static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigne } if (bottom) { if (vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg & 0x01000000) { - double_height = true; + cs->double_height = true; + cs->extra_rows = -(vstat.charheight); + cs->fontoffset = (vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].ch) * (vstat.charheight * ((bs->font_data_width + 7) / 8)); + // TODO: Update FS etc. + } + else { + // Draw as space if not double-bottom + cs->fontoffset=(32) * (vstat.charheight * ((bs->font_data_width + 7) / 8)); } fg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].fg; - bg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg; + cs->bg = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].bg; lattr = vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].legacy_attr; } else { if (ypos != vstat.rows) { if (vmem_ptr->vmem[(ypos - 1) * vstat.cols + (xpos - 1)].bg & 0x01000000) { top = true; - double_height = true; + cs->double_height = true; } } } - // Draw as space if not double-bottom - if (bottom) { - if (double_height) { - pixeloffset -= vstat.charheight * vstat.scrnwidth; - fontoffset=(vmem_ptr->vmem[(ypos - 2) * vstat.cols + (xpos - 1)].ch) * (vstat.charheight * ((fdw + 7) / 8)); - } - else - fontoffset=(32) * (vstat.charheight * ((fdw + 7) / 8)); - } release_vmem(vmem_ptr); if (lattr & 0x08) { if (!(cio_api.options & CONIO_OPT_PRESTEL_REVEAL)) { @@ -656,92 +657,207 @@ static int bitmap_draw_one_char(struct vmem_cell *vc, unsigned int xpos, unsigne } } } - for (y = 0; y < vstat.charheight; y++) { - for(x = 0; x < vstat.charwidth; x++) { - fdx = x; - fb = this_font[fontoffset]; - if ((x & 0x07) == 7) - fontoffset++; - if (vstat.flags & VIDMODES_FLAG_EXPAND) { - if (x == vstat.charwidth - 1) { - fontoffset--; - fdx--; - if (!(vstat.flags & VIDMODES_FLAG_LINE_GRAPHICS_EXPAND)) { - fb = 0; - } - else if ((sch) >= 0xC0 && (sch) <= 0xDF) { - fb = this_font[fontoffset]; - } - else - fb = 0; + cs->afc = draw_fg ? fg : cs->bg; + cs->bfc = not_hidden ? fg : cs->bg; +} - } - } - fbb = fb & (0x80 >> (fdx & 7)); +static void +draw_char_row(struct blockstate *bs, struct charstate *cs, uint32_t y) +{ + bool fbb; - if(fbb && draw_fg) { - if (screena.rect->data[pixeloffset] != fg) { - screena.update_pixels = 1; - screena.rect->data[pixeloffset] = fg; - } - if (double_height) { - if (screena.rect->data[pixeloffset+screena.screenwidth] != fg) { - screena.update_pixels = 1; - screena.rect->data[pixeloffset+screena.screenwidth] = fg; - } - } + uint8_t fb = cs->font[cs->fontoffset]; + for(unsigned x = 0; x < vstat.charwidth; x++) { + if (bs->expand && x == bs->font_data_width) { + if (cs->gexpand) + fbb = cs->font[cs->fontoffset - 1] & (0x80 >> ((x - 1) & 7)); + else + fbb = 0; + } + else + fbb = fb & (0x80 >> (x & 7)); + + if ((x & 0x07) == 7) { + cs->fontoffset++; + fb = cs->font[cs->fontoffset]; + } + + uint32_t ac, bc; + + if (fbb) { + ac = cs->afc; + bc = cs->bfc; + } + else { + ac = cs->bg; + bc = cs->bg; + } + + if (screena.rect->data[bs->pixeloffset] != ac) { + screena.rect->data[bs->pixeloffset] = ac; + screena.update_pixels = 1; + } + if (screenb.rect->data[bs->pixeloffset] != bc) { + screenb.rect->data[bs->pixeloffset] = bc; + screenb.update_pixels = 1; + } + + bs->pixeloffset++; + assert(bs->pixeloffset < bs->maxpix || x == (vstat.charwidth - 1)); + } +} + +static void +draw_char_row_double(struct blockstate *bs, struct charstate *cs, uint32_t y) +{ + bool fbb; + + ssize_t pixeloffset = bs->pixeloffset + (cs->extra_rows * screena.screenwidth); + if (pixeloffset >= bs->maxpix) + pixeloffset -= bs->maxpix; + if (pixeloffset < 0) + pixeloffset += bs->maxpix; + ssize_t pixeloffset2 = bs->pixeloffset + (cs->extra_rows + 1) * screena.screenwidth; + if (pixeloffset2 < 0) + pixeloffset2 += bs->maxpix; + if (pixeloffset2 >= bs->maxpix) + pixeloffset2 -= bs->maxpix; + + uint8_t fb = cs->font[cs->fontoffset]; + for(unsigned x = 0; x < vstat.charwidth; x++) { + if (bs->expand && x == bs->font_data_width) { + if (cs->gexpand) + fbb = cs->font[cs->fontoffset - 1] & (0x80 >> ((x - 1) & 7)); + else + fbb = 0; + } + else + fbb = fb & (0x80 >> (x & 7)); + + if ((x & 0x07) == 7) { + cs->fontoffset++; + fb = cs->font[cs->fontoffset]; + } + + uint32_t ac, bc; + + if (fbb) { + ac = cs->afc; + bc = cs->bfc; + } + else { + ac = cs->bg; + bc = cs->bg; + } + + if (screena.rect->data[pixeloffset] != ac) { + screena.rect->data[pixeloffset] = ac; + screena.update_pixels = 1; + } + if (screenb.rect->data[pixeloffset] != bc) { + screenb.rect->data[pixeloffset] = bc; + screenb.update_pixels = 1; + } + pixeloffset++; + assert(pixeloffset < bs->maxpix || x == (vstat.charwidth - 1)); + if (screena.rect->data[pixeloffset2] != ac) { + screena.rect->data[pixeloffset2] = ac; + screena.update_pixels = 1; + } + if (screenb.rect->data[pixeloffset2] != bc) { + screenb.rect->data[pixeloffset2] = bc; + screenb.update_pixels = 1; + } + pixeloffset2++; + assert(pixeloffset2 < bs->maxpix || x == (vstat.charwidth - 1)); + } + cs->extra_rows++; + bs->pixeloffset += vstat.charwidth; + assert(bs->pixeloffset <= bs->maxpix); +} + +static void +bitmap_draw_vmem(int sx, int sy, int ex, int ey, struct vmem_cell *fill) +{ + struct charstate charstate[255]; // ciolib only supports 255 columns + struct blockstate bs; + size_t vwidth = ex - sx + 1; + size_t vheight = ey - sy + 1; + + size_t xoffset = (sx-1) * vstat.charwidth; + size_t yoffset = (sy-1) * vstat.charheight; + assert(xoffset + vstat.charwidth <= screena.screenwidth); + assert(xoffset + vstat.charwidth <= screenb.screenwidth); + assert(yoffset + vstat.charheight <= screena.screenheight); + assert(yoffset + vstat.charheight <= screenb.screenheight); + bs.maxpix = screena.screenwidth * screena.screenheight; + bs.expand = vstat.flags & VIDMODES_FLAG_EXPAND; + bs.font_data_width = vstat.charwidth - (bs.expand ? 1 : 0); + + pthread_mutex_lock(&screenlock); + bs.pixeloffset = pixel_offset(&screena, xoffset, yoffset); + bs.cheat_colour = fill[0].bg; + size_t rsz = screena.screenwidth - vstat.charwidth * vwidth; + + // Fill in charstate for this pass + bool cheat = true; // If the whole thing is spaces in compiled in fonts, we can just fill. + for (size_t vy = 0; vy < vheight; vy++) { + for (size_t vx = 0; vx < vwidth; vx++) { + if (!can_cheat(&bs, &fill[vy * vwidth + vx])) { + cheat = false; + break; } - else { - if (screena.rect->data[pixeloffset] != bg) { - screena.update_pixels = 1; - screena.rect->data[pixeloffset] = bg; - } - if (double_height) { - if (screena.rect->data[pixeloffset+screena.screenwidth] != bg) { - screena.update_pixels = 1; - screena.rect->data[pixeloffset+screena.screenwidth] = bg; - } - } + } + if (!cheat) + break; + } + if (cheat) { + size_t ylim = vheight * vstat.charheight; + size_t xlim = vwidth * vstat.charwidth; + for (uint32_t y = 0; y < ylim; y++) { + for (size_t vx = 0; vx < xlim; vx++) { + screena.rect->data[bs.pixeloffset] = bs.cheat_colour; + bs.pixeloffset++; + assert(bs.pixeloffset < bs.maxpix || vx == (xlim - 1)); } - - if(fbb && not_hidden) { - if (screenb.rect->data[pixeloffset] != fg) { - screenb.update_pixels = 1; - screenb.rect->data[pixeloffset] = fg; - } - if (double_height) { - if (screenb.rect->data[pixeloffset+screena.screenwidth] != fg) { - screenb.update_pixels = 1; - screenb.rect->data[pixeloffset+screena.screenwidth] = fg; - } - } + bs.pixeloffset += rsz; + if (bs.pixeloffset >= bs.maxpix) + bs.pixeloffset -= bs.maxpix; + } + screena.update_pixels = 1; + bs.pixeloffset = pixel_offset(&screena, xoffset, yoffset); + for (uint32_t y = 0; y < ylim; y++) { + for (size_t vx = 0; vx < xlim; vx++) { + screenb.rect->data[bs.pixeloffset] = bs.cheat_colour; + bs.pixeloffset++; + assert(bs.pixeloffset < bs.maxpix || vx == (xlim - 1)); } - else { - if (screenb.rect->data[pixeloffset] != bg) { - screenb.update_pixels = 1; - screenb.rect->data[pixeloffset] = bg; - } - if (double_height) { - if (screenb.rect->data[pixeloffset+screena.screenwidth] != bg) { - screenb.update_pixels = 1; - screenb.rect->data[pixeloffset+screena.screenwidth] = bg; - } + bs.pixeloffset += rsz; + if (bs.pixeloffset >= bs.maxpix) + bs.pixeloffset -= bs.maxpix; + } + screenb.update_pixels = 1; + } + else { + for (size_t vy = 0; vy < vheight; vy++) { + // Fill in charstate for this pass + for (size_t vx = 0; vx < vwidth; vx++) + calc_charstate(&bs, &fill[vy * vwidth + vx], &charstate[vx], sx + vx, sy + vy); + // Draw the characters... + for (uint32_t y = 0; y < vstat.charheight; y++) { + for (size_t vx = 0; vx < vwidth; vx++) { + if (charstate[vx].double_height) + draw_char_row_double(&bs, &charstate[vx], y); + else + draw_char_row(&bs, &charstate[vx], y); } + bs.pixeloffset += rsz; + if (bs.pixeloffset >= bs.maxpix) + bs.pixeloffset -= bs.maxpix; } - pixeloffset++; } - if (x & 0x07) { - fontoffset++; - if (double_height && ((y & 1) == 0)) - fontoffset--; - } - pixeloffset += rsz; - if (double_height) - pixeloffset += screena.screenwidth; } pthread_mutex_unlock(&screenlock); - - return(0); } /***********************************************************/ @@ -954,7 +1070,7 @@ static int update_from_vmem(int force) || ((vmem_ptr->vmem[pos].legacy_attr & 0x80) && blink_attr_changed) || ((vmem_ptr->vmem[pos].legacy_attr & 0x08) && bright_attr_changed)) /* Bright char */ { - bitmap_draw_one_char(&vmem_ptr->vmem[pos], x+1,y+1); + bitmap_draw_vmem(x + 1, y + 1, x + 1, y + 1, &vmem_ptr->vmem[pos]); } pos++; } @@ -977,7 +1093,9 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill) int ret = 1; uint16_t *buf = fill; struct vstat_vmem *vmem_ptr; - struct vmem_cell *vc; + + if(!bitmap_initialized) + return(0); if (sx < 1 || sy < 1 @@ -993,12 +1111,14 @@ int bitmap_puttext(int sx, int sy, int ex, int ey, void *fill) pthread_mutex_lock(&vstatlock); vmem_ptr = get_vmem(&vstat); + struct vmem_cell va[(ex - sx + 1) * (ey - sy + 1)]; + size_t c = 0; for (y = sy - 1; y < ey; y++) { for (x = sx - 1; x < ex; x++) { - vc = set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, *(buf++), 0x00ffffff, 0x00ffffff); - bitmap_draw_one_char(vc, x+1, y+1); + va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, *(buf++), 0x00ffffff, 0x00ffffff); } } + bitmap_draw_vmem(sx, sy, ex, ey, va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); return ret; @@ -1252,32 +1372,57 @@ static void bitmap_movetext_screen(int x, int y, int tox, int toy, int direction, int height, int width) { int32_t sdestoffset; - size_t ssourcepos; + ssize_t ssourcepos; int step; int32_t screeny; pthread_mutex_lock(&screenlock); - if (width == cio_textinfo.screenwidth) { - ssourcepos = (( y - 1) * vstat.scrnwidth * vstat.charheight + ( x - 1) * vstat.charwidth); - sdestoffset = ((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos; - memmove(&(screena.rect->data[ssourcepos+sdestoffset]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth*height*vstat.charheight); - memmove(&(screenb.rect->data[ssourcepos+sdestoffset]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth*height*vstat.charheight); + if (width == cio_textinfo.screenwidth && (height > vstat.rows / 2) && toy == 1) { + screena.toprow += (y - toy) * vstat.charheight; + if (screena.toprow >= screena.screenheight) + screena.toprow -= screena.screenheight; + if (screena.toprow < 0) + screena.toprow += screena.screenheight; + screenb.toprow += (y - toy) * vstat.charheight; + if (screenb.toprow >= screenb.screenheight) + screenb.toprow -= screenb.screenheight; + if (screena.toprow < 0) + screena.toprow += screena.screenheight; + + if (direction == -1) + direction = 1; + else + direction = -1; + height = vstat.rows - height; + int otoy = toy; + toy = vstat.rows - (y - toy); + y = toy - (y - otoy); + } + + int maxpos = screena.screenwidth * screena.screenheight; + if (direction == -1) { + ssourcepos = ((y + height - 1) * vstat.charheight - 1) * vstat.scrnwidth + (x - 1) * vstat.charwidth; + sdestoffset = ((((toy + height - 1) * vstat.charheight - 1) * vstat.scrnwidth + (tox - 1) * vstat.charwidth) - ssourcepos); } else { - if (direction == -1) { - ssourcepos=((y + height - 2) * vstat.charheight - 1) * vstat.scrnwidth + (x - 1) * vstat.charwidth; - sdestoffset=((((toy + height - 2) * vstat.charheight - 1) * vstat.scrnwidth + (tox - 1) * vstat.charwidth) - ssourcepos); - } - else { - ssourcepos=(y - 1) * vstat.scrnwidth * vstat.charheight + (x - 1) * vstat.charwidth; - sdestoffset=(((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos); - } - step = direction * vstat.scrnwidth; - for(screeny=0; screeny < height*vstat.charheight; screeny++) { - memmove(&(screena.rect->data[ssourcepos+sdestoffset]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth); - memmove(&(screenb.rect->data[ssourcepos+sdestoffset]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth); - ssourcepos += step; - } + ssourcepos=(y - 1) * vstat.scrnwidth * vstat.charheight + (x - 1) * vstat.charwidth; + sdestoffset=(((toy - 1) * vstat.scrnwidth * vstat.charheight + (tox - 1) * vstat.charwidth) - ssourcepos); + } + ssourcepos += screena.toprow * screena.screenwidth; + step = direction * vstat.scrnwidth; + for(screeny=0; screeny < height*vstat.charheight; screeny++) { + if (ssourcepos >= maxpos) + ssourcepos -= maxpos; + if (ssourcepos < 0) + ssourcepos += maxpos; + int dest = ssourcepos + sdestoffset; + if (dest >= maxpos) + dest -= maxpos; + if (dest < 0) + dest += maxpos; + memmove(&(screena.rect->data[dest]), &(screena.rect->data[ssourcepos]), sizeof(screena.rect->data[0])*width*vstat.charwidth); + memmove(&(screenb.rect->data[dest]), &(screenb.rect->data[ssourcepos]), sizeof(screenb.rect->data[0])*width*vstat.charwidth); + ssourcepos += step; } screena.update_pixels = 1; screenb.update_pixels = 1; @@ -1353,17 +1498,21 @@ void bitmap_clreol(void) int pos,x; WORD fill=(cio_textinfo.attribute<<8)|' '; struct vstat_vmem *vmem_ptr; - struct vmem_cell *vc; int row; + if(!bitmap_initialized) + return; + row = cio_textinfo.cury + cio_textinfo.wintop - 1; pos=(row - 1)*cio_textinfo.screenwidth; pthread_mutex_lock(&vstatlock); vmem_ptr = get_vmem(&vstat); + struct vmem_cell va[cio_textinfo.winright - (cio_textinfo.curx + cio_textinfo.winleft - 1) + 1]; + int c = 0; for(x=cio_textinfo.curx+cio_textinfo.winleft-2; x<cio_textinfo.winright; x++) { - vc = set_vmem_cell(vmem_ptr, pos+x, fill, ciolib_fg, ciolib_bg); - bitmap_draw_one_char(vc, x+1, row); + va[c++] = *set_vmem_cell(vmem_ptr, pos+x, fill, ciolib_fg, ciolib_bg); } + bitmap_draw_vmem(cio_textinfo.curx + cio_textinfo.winleft - 1, row, cio_textinfo.winright, row, va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); } @@ -1373,19 +1522,23 @@ void bitmap_clrscr(void) size_t x, y; WORD fill = (cio_textinfo.attribute << 8) | ' '; struct vstat_vmem *vmem_ptr; - struct vmem_cell *vc; + struct vmem_cell va[(cio_textinfo.winright - cio_textinfo.winleft + 1) * (cio_textinfo.winbottom - cio_textinfo.wintop + 1)]; + size_t c = 0; int rows, cols; + if(!bitmap_initialized) + return; + pthread_mutex_lock(&vstatlock); vmem_ptr = get_vmem(&vstat); rows = vstat.rows; cols = vstat.cols; for (y = cio_textinfo.wintop - 1; y < cio_textinfo.winbottom && y < rows; y++) { for (x = cio_textinfo.winleft - 1; x < cio_textinfo.winright && x < cols; x++) { - vc = set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, fill, ciolib_fg, ciolib_bg); - bitmap_draw_one_char(vc, x+1, y+1); + va[c++] = *set_vmem_cell(vmem_ptr, y * cio_textinfo.screenwidth + x, fill, ciolib_fg, ciolib_bg); } } + bitmap_draw_vmem(cio_textinfo.winleft, cio_textinfo.wintop, cio_textinfo.winright, cio_textinfo.winbottom, va); release_vmem(vmem_ptr); pthread_mutex_unlock(&vstatlock); } @@ -1491,16 +1644,16 @@ int bitmap_setpixel(uint32_t x, uint32_t y, uint32_t colour) { pthread_mutex_lock(&screenlock); if (x < screena.screenwidth && y < screena.screenheight) { - if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != colour) { + if (screena.rect->data[pixel_offset(&screena, x, y)] != colour) { screena.update_pixels = 1; - screena.rect->data[PIXEL_OFFSET(screena, x, y)] = colour; + screena.rect->data[pixel_offset(&screena, x, y)] = colour; } } if (x < screenb.screenwidth && y < screenb.screenheight) { - if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != colour) { + if (screenb.rect->data[pixel_offset(&screenb, x, y)] != colour) { screenb.update_pixels = 1; - screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = colour; + screenb.rect->data[pixel_offset(&screenb, x, y)] = colour; } } pthread_mutex_unlock(&screenlock); @@ -1549,19 +1702,19 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_ pos = pixels->width*(y-sy+y_off)+x_off; if (mask == NULL) { for (x = sx; x <= ex; x++) { - if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != pixels->pixels[pos]) { - screena.rect->data[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos]; + if (screena.rect->data[pixel_offset(&screena, x, y)] != pixels->pixels[pos]) { + screena.rect->data[pixel_offset(&screena, x, y)] = pixels->pixels[pos]; screena.update_pixels = 1; } if (pixels->pixelsb) { - if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixelsb[pos]) { - screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos]; + if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixelsb[pos]) { + screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixelsb[pos]; screenb.update_pixels = 1; } } else { - if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixels[pos]) { - screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos]; + if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixels[pos]) { + screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixels[pos]; screenb.update_pixels = 1; } } @@ -1575,19 +1728,19 @@ int bitmap_setpixels(uint32_t sx, uint32_t sy, uint32_t ex, uint32_t ey, uint32_ mask_bit = mpos % 8; mask_bit = 0x80 >> mask_bit; if (mask->bits[mask_byte] & mask_bit) { - if (screena.rect->data[PIXEL_OFFSET(screena, x, y)] != pixels->pixels[pos]) { - screena.rect->data[PIXEL_OFFSET(screena, x, y)] = pixels->pixels[pos]; + if (screena.rect->data[pixel_offset(&screena, x, y)] != pixels->pixels[pos]) { + screena.rect->data[pixel_offset(&screena, x, y)] = pixels->pixels[pos]; screena.update_pixels = 1; } if (pixels->pixelsb) { - if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixelsb[pos]) { - screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixelsb[pos]; + if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixelsb[pos]) { + screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixelsb[pos]; screenb.update_pixels = 1; } } else { - if (screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] != pixels->pixels[pos]) { - screenb.rect->data[PIXEL_OFFSET(screenb, x, y)] = pixels->pixels[pos]; + if (screenb.rect->data[pixel_offset(&screenb, x, y)] != pixels->pixels[pos]) { + screenb.rect->data[pixel_offset(&screenb, x, y)] = pixels->pixels[pos]; screenb.update_pixels = 1; } } @@ -1648,8 +1801,8 @@ struct ciolib_pixels *bitmap_getpixels(uint32_t sx, uint32_t sy, uint32_t ex, ui for (y = sy; y <= ey; y++) { // TODO: This is the place where screen vs. buffer matters. :( - memcpy(&pixels->pixels[width*(y-sy)], &screena.rect->data[PIXEL_OFFSET(screena, sx, y)], width * sizeof(pixels->pixels[0])); - memcpy(&pixels->pixelsb[width*(y-sy)], &screenb.rect->data[PIXEL_OFFSET(screenb, sx, y)], width * sizeof(pixels->pixelsb[0])); + memcpy(&pixels->pixels[width*(y-sy)], &screena.rect->data[pixel_offset(&screena, sx, y)], width * sizeof(pixels->pixels[0])); + memcpy(&pixels->pixelsb[width*(y-sy)], &screenb.rect->data[pixel_offset(&screenb, sx, y)], width * sizeof(pixels->pixelsb[0])); } pthread_mutex_unlock(&screenlock); diff --git a/src/conio/cterm.c b/src/conio/cterm.c index 590b3f03b2..54142b92ab 100644 --- a/src/conio/cterm.c +++ b/src/conio/cterm.c @@ -799,6 +799,7 @@ set_attr(struct cterminal *cterm, unsigned char colour, bool bg) if (cterm->emulation == CTERM_EMULATION_PRESTEL) { if (cterm->extattr & CTERM_EXTATTR_PRESTEL_DOUBLE_HEIGHT) cterm->bg_color |= 0x01000000; + cterm->bg_color |= 0x02000000; } if (bg) FREE_AND_NULL(cterm->bg_tc_str); @@ -824,6 +825,7 @@ prestel_new_line(struct cterminal *cterm) cterm->extattr &= ~(CTERM_EXTATTR_PRESTEL_CONCEAL | CTERM_EXTATTR_PRESTEL_DOUBLE_HEIGHT | CTERM_EXTATTR_PRESTEL_HOLD | CTERM_EXTATTR_PRESTEL_MOSAIC | CTERM_EXTATTR_PRESTEL_SEPARATED); cterm->attr = 7; attr2palette(cterm->attr, &cterm->fg_color, &cterm->bg_color); + cterm->bg_color |= 0x02000000; cterm->prestel_last_mosaic = 0; TEXTATTR(cterm->attr); setcolour(cterm->fg_color, cterm->bg_color); @@ -869,6 +871,7 @@ prestel_apply_ctrl_before(struct cterminal *cterm, uint8_t ch) cterm->extattr |= CTERM_EXTATTR_PRESTEL_HOLD; break; } + cterm->bg_color |= 0x02000000; } static void @@ -950,6 +953,7 @@ prestel_apply_ctrl_after(struct cterminal *cterm, uint8_t ch) cterm->extattr &= ~(CTERM_EXTATTR_PRESTEL_HOLD); break; } + cterm->bg_color |= 0x02000000; } static void -- GitLab