From 25d7456145c54b34f5285fe74b9f4d6ce21cee7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Deuc=D0=B5?= <shurd@sasktel.net> Date: Wed, 8 Jan 2025 13:58:05 -0500 Subject: [PATCH] Make the scrollback a ring buffer instead of a linear one. This was one of the two major perforance issues with previous versions of SyncTERM. Using a larger scrollback will not longer slow down SyncTERM. The other major issue is updating the pixel data for every change, but we can't fix that as long as graphics and text are drawn on the same plane. --- src/conio/cterm.c | 66 +++++++++++++++++++++-------------------- src/conio/cterm.h | 4 ++- src/syncterm/bbslist.c | 12 ++++---- src/syncterm/menu.c | 24 +++++++++------ src/syncterm/syncterm.c | 1 - src/syncterm/syncterm.h | 3 -- src/syncterm/term.c | 60 ++++++++++++++++++++++++++----------- 7 files changed, 101 insertions(+), 69 deletions(-) diff --git a/src/conio/cterm.c b/src/conio/cterm.c index a9f93934b0..590b3f03b2 100644 --- a/src/conio/cterm.c +++ b/src/conio/cterm.c @@ -1391,6 +1391,33 @@ scrolldown(struct cterminal *cterm) GOTOXY(x, y); } +static void +cterm_line_to_scrollback(struct cterminal *cterm, int row) +{ + if(cterm->scrollback!=NULL) { + int getw; + + cterm->backfilled++; + if (cterm->backfilled > cterm->backlines) { + cterm->backfilled--; + cterm->backstart++; + if (cterm->backstart == cterm->backlines) + cterm->backstart = 0; + } + getw = cterm->backwidth; + if (getw > cterm->width) + getw = cterm->width; + if (getw < cterm->backwidth) { + memset(cterm->scrollback + cterm->backpos * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth); + } + vmem_gettext(cterm->x, row, cterm->x + getw - 1, row, cterm->scrollback + cterm->backpos * cterm->backwidth); + + cterm->backpos++; + if (cterm->backpos == cterm->backlines) + cterm->backpos = 0; + } +} + void cterm_scrollup(struct cterminal *cterm) { @@ -1399,24 +1426,10 @@ cterm_scrollup(struct cterminal *cterm) int maxx = TERM_MAXX; int maxy = TERM_MAXY; int x,y; - int getw; - cterm->backpos++; coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &minx, &miny); coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &maxx, &maxy); - if(cterm->scrollback!=NULL) { - if(cterm->backpos>cterm->backlines) { - memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth, cterm->backwidth * sizeof(*cterm->scrollback) * (cterm->backlines - 1)); - cterm->backpos--; - } - getw = cterm->backwidth; - if (getw > cterm->width) - getw = cterm->width; - if (getw < cterm->backwidth) { - memset(cterm->scrollback + (cterm->backpos - 1) * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth); - } - vmem_gettext(cterm->x, miny, cterm->x + getw - 1, miny, cterm->scrollback + (cterm->backpos - 1) * cterm->backwidth); - } + cterm_line_to_scrollback(cterm, miny); MOVETEXT(minx, miny + 1, maxx, maxy, minx, miny); CURR_XY(&x, &y); cterm_clrblk(cterm, minx, maxy, minx + TERM_MAXX - 1, maxy); @@ -1500,26 +1513,15 @@ clear2bol(struct cterminal * cterm) void cterm_clearscreen(struct cterminal *cterm, char attr) { - int getw; - if(!cterm->started) cterm_start(cterm); - if(cterm->scrollback!=NULL) { - cterm->backpos+=cterm->height; - if(cterm->backpos>cterm->backlines) { - memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * (cterm->backpos - cterm->backlines), cterm->backwidth * sizeof(*cterm->scrollback) * (cterm->backlines - (cterm->backpos - cterm->backlines))); - cterm->backpos=cterm->backlines; - } - getw = cterm->backwidth; - if (getw > cterm->width) - getw = cterm->width; - if (getw < cterm->backwidth) { - memset(cterm->scrollback + (cterm->backpos - cterm->height) * cterm->backwidth, 0, sizeof(*cterm->scrollback) * cterm->backwidth * cterm->height); - } - vmem_gettext(cterm->x, cterm->y, cterm->x + getw - 1, cterm->y + cterm->height - 1, - cterm->scrollback + (cterm->backpos - cterm->height) * cterm->backwidth); - } + int minx = TERM_MINX; + int miny = TERM_MINY; + coord_conv_xy(cterm, CTERM_COORD_TERM, CTERM_COORD_SCREEN, &minx, &miny); + + for (int i = 0; i < cterm->height; i++) + cterm_line_to_scrollback(cterm, miny + i); CLRSCR(); GOTOXY(CURR_MINX, CURR_MINY); } diff --git a/src/conio/cterm.h b/src/conio/cterm.h index fc808d51cb..de8bedcbdb 100644 --- a/src/conio/cterm.h +++ b/src/conio/cterm.h @@ -99,6 +99,7 @@ struct cterminal { int right_margin; int quiet; // No sounds are made struct vmem_cell *scrollback; + int backfilled; // Number of lines copied into scrollback int backlines; // Number of lines in scrollback int backwidth; // Number of columns in scrollback char DA[1024]; // Device Attributes @@ -170,7 +171,8 @@ struct cterminal { link_list_t notes; sem_t playnote_thread_terminated; sem_t note_completed_sem; - int backpos; + int backpos; // Position where new lines will be added + int backstart; // First line of scrollback int xpos; int ypos; cterm_log_t log; diff --git a/src/syncterm/bbslist.c b/src/syncterm/bbslist.c index d36c0d98e9..a5ed0a160f 100644 --- a/src/syncterm/bbslist.c +++ b/src/syncterm/bbslist.c @@ -368,6 +368,7 @@ viewofflinescroll(void) struct text_info txtinfo; struct text_info sbtxtinfo; struct mouse_event mevent; + int scrollback_pos; if (scrollback_buf == NULL) return; @@ -403,10 +404,11 @@ viewofflinescroll(void) setfont(0, false, 4); drawwin(); set_modepalette(palettes[COLOUR_PALETTE]); - top = scrollback_pos; gotoxy(1, 1); textattr(uifc.hclr | (uifc.bclr << 4) | BLINK); gettextinfo(&sbtxtinfo); + scrollback_pos = scrollback_lines - sbtxtinfo.screenheight; + top = scrollback_pos; ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_START); ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_MOVE); ciomouse_addevent(CIOLIB_BUTTON_1_DRAG_END); @@ -415,10 +417,10 @@ viewofflinescroll(void) showmouse(); for (i = 0; !i && !quitting;) { - if (top < 1) - top = 1; - if (top > (int)scrollback_lines) - top = scrollback_lines; + if (top < 0) + top = 0; + if (top > scrollback_pos) + top = scrollback_pos; vmem_puttext(((sbtxtinfo.screenwidth - scrollback_cols) / 2) + 1, 1, (sbtxtinfo.screenwidth - scrollback_cols) / 2 + scrollback_cols, sbtxtinfo.screenheight, diff --git a/src/syncterm/menu.c b/src/syncterm/menu.c index 7a0af78b61..e17c5d2f4c 100644 --- a/src/syncterm/menu.c +++ b/src/syncterm/menu.c @@ -35,19 +35,25 @@ viewscroll(void) /* too large for alloca() */ scrollback = malloc((scrollback_buf - == NULL ? 0 : (term.width * sizeof(*scrollback) * settings.backlines)) + == NULL ? 0 : (term.width * sizeof(*scrollback) * cterm->backlines)) + (txtinfo.screenheight * txtinfo.screenwidth * sizeof(*scrollback))); if (scrollback == NULL) return; - memcpy(scrollback, cterm->scrollback, term.width * sizeof(*scrollback) * settings.backlines); - vmem_gettext(1, 1, txtinfo.screenwidth, txtinfo.screenheight, scrollback + (cterm->backpos) * cterm->width); + int lines = 0; + if (cterm->backstart > 0) { + lines = cterm->backlines - cterm->backstart; + memcpy(scrollback, cterm->scrollback + term.width * cterm->backstart, term.width * lines * sizeof(*scrollback)); + } + memcpy(scrollback + term.width * lines, cterm->scrollback, term.width * sizeof(*scrollback) * cterm->backpos); + int sblines = cterm->backpos + lines; + vmem_gettext(1, 1, txtinfo.screenwidth, txtinfo.screenheight, scrollback + sblines * cterm->width); savscrn = savescreen(); setfont(0, false, 1); setfont(0, false, 2); setfont(0, false, 3); setfont(0, false, 4); drawwin(); - top = cterm->backpos; + top = sblines; set_modepalette(palettes[COLOUR_PALETTE]); gotoxy(1, 1); textattr(uifc.hclr | (uifc.bclr << 4) | BLINK); @@ -57,10 +63,10 @@ viewscroll(void) ciomouse_addevent(CIOLIB_BUTTON_4_PRESS); ciomouse_addevent(CIOLIB_BUTTON_5_PRESS); for (i = 0; (!i) && (!quitting);) { - if (top < 1) - top = 1; - if (top > cterm->backpos) - top = cterm->backpos; + if (top < 0) + top = 0; + if (top > sblines) + top = sblines; vmem_puttext(term.x - 1, term.y - 1, term.x + term.width - 2, term.y + term.height - 2, scrollback + (term.width * top)); cputs("Scrollback"); @@ -86,7 +92,7 @@ viewscroll(void) break; case CIOLIB_BUTTON_5_PRESS: top++; - if (top > cterm->backpos) + if (top > sblines) i = 1; break; } diff --git a/src/syncterm/syncterm.c b/src/syncterm/syncterm.c index 3c7142bf2c..0e4e519021 100644 --- a/src/syncterm/syncterm.c +++ b/src/syncterm/syncterm.c @@ -143,7 +143,6 @@ struct syncterm_settings settings; char *font_names[sizeof(conio_fontdata) / sizeof(struct conio_font_data_struct)]; struct vmem_cell *scrollback_buf = NULL; unsigned int scrollback_lines = 0; -unsigned int scrollback_pos = 0; unsigned int scrollback_mode = C80; unsigned int scrollback_cols = 80; int safe_mode = 0; diff --git a/src/syncterm/syncterm.h b/src/syncterm/syncterm.h index 5ca4a75652..afb3e27117 100644 --- a/src/syncterm/syncterm.h +++ b/src/syncterm/syncterm.h @@ -86,10 +86,7 @@ extern char *inpath; extern char *list_override; extern const char *syncterm_version; extern struct vmem_cell *scrollback_buf; -extern uint32_t *scrollback_fbuf; -extern uint32_t *scrollback_bbuf; extern unsigned int scrollback_lines; -extern unsigned int scrollback_pos; extern unsigned int scrollback_mode; extern unsigned int scrollback_cols; extern struct syncterm_settings settings; diff --git a/src/syncterm/term.c b/src/syncterm/term.c index 0264b3b4b6..fb49a6c3cb 100644 --- a/src/syncterm/term.c +++ b/src/syncterm/term.c @@ -4080,6 +4080,43 @@ normalize_entry(struct bbslist *bbs) } } +static void +finish_scrollback(void) +{ + scrollback_buf = cterm->scrollback; + scrollback_cols = cterm->backwidth; + // TODO: Set scrollback_mode here? + if (cterm->scrollback != NULL) { + cterm_clearscreen(cterm, cterm->attr); /* Clear screen into + * scrollback */ + + // Now make the scrollback a linear buffer instead of a ring buffer + if (cterm->backstart) { + struct vmem_cell *bottom; + int topsz = cterm->backlines - cterm->backstart; + + bottom = malloc(cterm->backwidth * cterm->backstart * sizeof(*bottom)); + if (bottom) { + memcpy(bottom, cterm->scrollback, cterm->backwidth * cterm->backstart * sizeof(*bottom)); + memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * cterm->backstart, cterm->backwidth * topsz * sizeof(*cterm->scrollback)); + memcpy(cterm->scrollback + cterm->backwidth * topsz, bottom, cterm->backwidth * cterm->backstart * sizeof(*bottom)); + free(bottom); + scrollback_lines = cterm->backlines; + } + else { + memmove(cterm->scrollback, cterm->scrollback + cterm->backwidth * cterm->backstart, cterm->backwidth * topsz * sizeof(*cterm->scrollback)); + scrollback_lines = topsz; + } + } + else { + scrollback_lines = cterm->backpos; + } + } + else { + scrollback_lines = 0; + } +} + bool doterm(struct bbslist *bbs) { @@ -4153,7 +4190,6 @@ doterm(struct bbslist *bbs) else { FREE_AND_NULL(scrollback_buf); } - scrollback_lines = 0; scrollback_mode = txtinfo.currmode; cterm = cterm_init(term.height, term.width, @@ -4173,7 +4209,6 @@ doterm(struct bbslist *bbs) cterm->mouse_state_change_cbdata = &ms; cterm->mouse_state_query = mouse_state_query; cterm->mouse_state_query_cbdata = &ms; - scrollback_cols = term.width; cterm->music_enable = bbs->music; ch[1] = 0; zrqbuf[0] = 0; @@ -4218,10 +4253,7 @@ doterm(struct bbslist *bbs) uifcmsg("Disconnected", "`Disconnected`\n\nRemote host dropped connection"); check_exit(false); - scrollback_pos = cterm->backpos; - cterm_clearscreen(cterm, cterm->attr); /* Clear screen into - * scrollback */ - scrollback_lines = cterm->backpos; + finish_scrollback(); cterm_end(cterm, 0); cterm = NULL; // TODO: Do this before the popup to avoid being rude... @@ -4559,10 +4591,7 @@ doterm(struct bbslist *bbs) "Selecting Yes closes the connection\n")) { freescreen(savscrn); setup_mouse_events(&ms); - scrollback_pos = cterm->backpos; - cterm_clearscreen(cterm, cterm->attr); /* Clear screen into - * scrollback */ - scrollback_lines = cterm->backpos; + finish_scrollback(); cterm_end(cterm, 0); cterm = NULL; conn_close(); @@ -4591,10 +4620,7 @@ doterm(struct bbslist *bbs) j = wherey(); switch (syncmenu(bbs, &speed)) { case -1: - scrollback_pos = cterm->backpos; - cterm_clearscreen(cterm, cterm->attr); /* Clear screen into - * scrollback */ - scrollback_lines = cterm->backpos; + finish_scrollback(); cterm_end(cterm, 0); cterm = NULL; conn_close(); @@ -4640,10 +4666,7 @@ doterm(struct bbslist *bbs) break; case 13: #endif - scrollback_pos = cterm->backpos; - cterm_clearscreen(cterm, cterm->attr); /* Clear screen into - * scrollback */ - scrollback_lines = cterm->backpos; + finish_scrollback(); cterm_end(cterm, 0); cterm = NULL; conn_close(); @@ -5089,5 +5112,6 @@ doterm(struct bbslist *bbs) * hidemouse(); * hold_update=oldmc; */ + finish_scrollback(); return false; } -- GitLab