Skip to content
Snippets Groups Projects
Commit 9c871efc authored by Deucе's avatar Deucе :ok_hand_tone4:
Browse files

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.
parent 935afe75
Branches
Tags
No related merge requests found
Pipeline #7706 failed
/* $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;
uint32_t fontoffset;
int8_t extra_rows;
bool double_height;
bool gexpand;
};
struct blockstate {
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;
int maxpix;
int font_data_width;
uint32_t cheat_colour;
bool expand;
};
if(!bitmap_initialized) {
return(-1);
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);
}
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;
// 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,28 +628,26 @@ 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) {
......@@ -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;
cs->afc = draw_fg ? fg : cs->bg;
cs->bfc = not_hidden ? fg : cs->bg;
}
else if ((sch) >= 0xC0 && (sch) <= 0xDF) {
fb = this_font[fontoffset];
static void
draw_char_row(struct blockstate *bs, struct charstate *cs, uint32_t y)
{
bool fbb;
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
fb = 0;
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;
}
fbb = fb & (0x80 >> (fdx & 7));
if(fbb && draw_fg) {
if (screena.rect->data[pixeloffset] != fg) {
if (screena.rect->data[bs->pixeloffset] != ac) {
screena.rect->data[bs->pixeloffset] = ac;
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;
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 {
if (screena.rect->data[pixeloffset] != bg) {
ac = cs->bg;
bc = cs->bg;
}
if (screena.rect->data[pixeloffset] != ac) {
screena.rect->data[pixeloffset] = ac;
screena.update_pixels = 1;
screena.rect->data[pixeloffset] = bg;
}
if (double_height) {
if (screena.rect->data[pixeloffset+screena.screenwidth] != bg) {
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;
screena.rect->data[pixeloffset+screena.screenwidth] = bg;
}
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);
}
if(fbb && not_hidden) {
if (screenb.rect->data[pixeloffset] != fg) {
screenb.update_pixels = 1;
screenb.rect->data[pixeloffset] = fg;
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;
}
if (double_height) {
if (screenb.rect->data[pixeloffset+screena.screenwidth] != fg) {
screenb.update_pixels = 1;
screenb.rect->data[pixeloffset+screena.screenwidth] = fg;
}
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));
}
else {
if (screenb.rect->data[pixeloffset] != bg) {
screenb.update_pixels = 1;
screenb.rect->data[pixeloffset] = bg;
bs.pixeloffset += rsz;
if (bs.pixeloffset >= bs.maxpix)
bs.pixeloffset -= bs.maxpix;
}
if (double_height) {
if (screenb.rect->data[pixeloffset+screena.screenwidth] != bg) {
screenb.update_pixels = 1;
screenb.rect->data[pixeloffset+screena.screenwidth] = bg;
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));
}
bs.pixeloffset += rsz;
if (bs.pixeloffset >= bs.maxpix)
bs.pixeloffset -= bs.maxpix;
}
screenb.update_pixels = 1;
}
pixeloffset++;
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;
}
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,33 +1372,58 @@ 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);
}
else {
int maxpos = screena.screenwidth * screena.screenheight;
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);
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 {
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++) {
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);
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;
pthread_mutex_unlock(&screenlock);
......@@ -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);
......
......@@ -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
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment