3 提高叠加处理速度(1)(harib07c)
那么怎样才能提高速度呢?既然其他操作系统都能处理得那么快,就肯定有好的方法。首先,我们从鼠标指针的移动,也就是图层的移动来思考一下。
鼠标指针虽然最多只有16×16=256个像素,可根据harib07b的原理,只要它稍一移动,程序就会对整个画面进行刷新,也就是重新描绘320×200=64 000个像素。而实际上,只重新描绘移动相关的部分,也就是移动前后的部分就可以了,即256×2=512个像素。这只是64 000像素的0.8%而已,所以有望提速很多。现在我们根据这个思路写一下程序。
■■■■■
本次的*sheet.c节选
void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
{
int h, bx, by, vx, vy;
unsigned char *buf, c, *vram = ctl->vram;
struct SHEET *sht;
for (h = 0; h <= ctl->top; h++) {
sht = ctl->sheets[h];
buf = sht->buf;
for (by = 0; by < sht->bysize; by++) {
vy = sht->vy0 + by;
for (bx = 0; bx < sht->bxsize; bx++) {
vx = sht->vx0 + bx;
if (vx0 <= vx && vx < vx1 && vy0 <= vy && vy < vy1) {
c = buf[by * sht->bxsize + bx];
if (c != sht->col_inv) {
vram[vy * ctl->xsize + vx] = c;
}
}
}
}
}
return;
}
这个函数几乎和sheet_refresh一样,唯一的不同点在于它能使用vx0~ vy1指定刷新的范围,而我们只追加了一个if语句就实现了这个新功能。另外,程序中的&&运算符是我们之前没有见过的,所以在这里详细解释一下。
&&运算符是把多个条件关系式连接起来的运算符。当用它连接的所有条件都满足时,就执行{ }中的程序;只要有一个条件不满足,就不执行(如果有else,就执行else后的语句)。另外,还有一个跟它很像的运算符“||”。“ ||”也是把多个条件关系式连接起来的运算符,不过由它连接的各个条件,只要其中一个满足了,就执行{ }中的程序。简而言之,&&就是“而且”,而 || 是“或者”。
条件“vx大于等于vx0且小于vx1”可以用数学式vx0 <= vx < vx1来表达,但在C语言中不能这样写,我们只能写成 vx0 <= vx && vx < vx1。
■■■■■
现在我们使用这个refreshsub函数来提高sheet_slide的运行速度。
本次的*sheet.c节选
void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0)
{
int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
sht->vx0 = vx0;
sht->vy0 = vy0;
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */
sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);
sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);
}
return;
}
这段程序所做的是:首先记住移动前的显示位置,再设定新的显示位置,最后只要重新描绘移动前和移动后的地方就可以了。
■■■■■
估计大家会认为“这次鼠标的移动就快了吧”,但移动鼠标时,由于要在画面上显示坐标等信息,结果又执行了sheet_refresh程序,所以还是很慢。为了不浪费我们付出的各种努力,下面我们就来解决一下图层内文字显示的问题。
我们所说的在图层上显示文字,实际上并不是改写图层的全部内容。假设我们已经写了20个字,那么8×16×20=2560,也就是仅仅重写2560个像素的内容就应该足够了。但现在每次却要重写64 000个像素的内容,所以速度才那么慢。
这么说来,这里好像也可以使用refreshsub,那么我们就来重新编写函数sheet_refresh吧。
本次的*sheet.c节选
void sheet_refresh(struct SHTCTL *ctl, struct SHEET *sht, int bx0, int by0, int bx1, int by1)
{
if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/
sheet_refreshsub(ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1);
}
return;
}
所谓指定范围,并不是直接指定画面内的坐标,而是以缓冲区内的坐标来表示。这样一来,HariMain就可以不考虑图层在画面中的位置了。
■■■■■
我们改动了refresh,所以也要相应改造updown。做了改动的只有sheet_refresh(ctl)这部分(有两处),修改后的程序如下:
sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize);
最后还要改写HariMain。
本次的*bootpack.c节选
void HariMain(void)
{
(中略)
sprintf(s, "(%3d, %3d)", mx, my);
putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
sprintf(s, "memory %dMB free : %dKB",
memtotal / (1024 * 1024), memman_total(memman) / 1024);
putfonts8_asc(buf_back, binfo->scrnx, 0, 32, COL8_FFFFFF, s);
sheet_refresh(shtctl, sht_back, 0, 0, binfo->scrnx, 48); /* 这里! */
for (;;) {
io_cli();
if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
io_stihlt();
} else {
if (fifo8_status(&keyfifo) != 0) {
(中略)
sheet_refresh(shtctl, sht_back, 0, 16, 16, 32); /* 这里! */
} else if (fifo8_status(&mousefifo) != 0) {
i = fifo8_get(&mousefifo);
io_sti();
if (mouse_decode(&mdec, i) != 0) {
(中略)
boxfill8(buf_back, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
putfonts8_asc(buf_back, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
sheet_refresh(shtctl, sht_back, 32, 16, 32 + 15 * 8, 32); /* 这里! */
(中略)
sprintf(s, "(%3d, %3d)", mx, my);
boxfill8(buf_back, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 消去坐标 */
putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 写出坐标 */
sheet_refresh(shtctl, sht_back, 0, 0, 80, 16); /* 这里! */
sheet_slide(shtctl, sht_mouse, mx, my);
}
}
}
}
}
这里我们仅仅改写了sheet_refresh,变更点共有4个。只有每次要往buf_back中写入信息时,才进行sheet_refresh。
这样应该可以顺利运行了。我们赶紧试一试。“make run”。哦,确实比以前快多了。太好了,撒花!不过还是欠缺一些东西……