3 提高叠加处理速度(1)(harib07c)

那么怎样才能提高速度呢?既然其他操作系统都能处理得那么快,就肯定有好的方法。首先,我们从鼠标指针的移动,也就是图层的移动来思考一下。

鼠标指针虽然最多只有16×16=256个像素,可根据harib07b的原理,只要它稍一移动,程序就会对整个画面进行刷新,也就是重新描绘320×200=64 000个像素。而实际上,只重新描绘移动相关的部分,也就是移动前后的部分就可以了,即256×2=512个像素。这只是64 000像素的0.8%而已,所以有望提速很多。现在我们根据这个思路写一下程序。

■■■■■

本次的*sheet.c节选

  1. void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
  2. {
  3. int h, bx, by, vx, vy;
  4. unsigned char *buf, c, *vram = ctl->vram;
  5. struct SHEET *sht;
  6. for (h = 0; h <= ctl->top; h++) {
  7. sht = ctl->sheets[h];
  8. buf = sht->buf;
  9. for (by = 0; by < sht->bysize; by++) {
  10. vy = sht->vy0 + by;
  11. for (bx = 0; bx < sht->bxsize; bx++) {
  12. vx = sht->vx0 + bx;
  13. if (vx0 <= vx && vx < vx1 && vy0 <= vy && vy < vy1) {
  14. c = buf[by * sht->bxsize + bx];
  15. if (c != sht->col_inv) {
  16. vram[vy * ctl->xsize + vx] = c;
  17. }
  18. }
  19. }
  20. }
  21. }
  22. return;
  23. }

这个函数几乎和sheet_refresh一样,唯一的不同点在于它能使用vx0~ vy1指定刷新的范围,而我们只追加了一个if语句就实现了这个新功能。另外,程序中的&&运算符是我们之前没有见过的,所以在这里详细解释一下。

&&运算符是把多个条件关系式连接起来的运算符。当用它连接的所有条件都满足时,就执行{ }中的程序;只要有一个条件不满足,就不执行(如果有else,就执行else后的语句)。另外,还有一个跟它很像的运算符“||”。“ ||”也是把多个条件关系式连接起来的运算符,不过由它连接的各个条件,只要其中一个满足了,就执行{ }中的程序。简而言之,&&就是“而且”,而 || 是“或者”。

条件“vx大于等于vx0且小于vx1”可以用数学式vx0 <= vx < vx1来表达,但在C语言中不能这样写,我们只能写成 vx0 <= vx && vx < vx1。

■■■■■

现在我们使用这个refreshsub函数来提高sheet_slide的运行速度。

本次的*sheet.c节选

  1. void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0)
  2. {
  3. int old_vx0 = sht->vx0, old_vy0 = sht->vy0;
  4. sht->vx0 = vx0;
  5. sht->vy0 = vy0;
  6. if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面 */
  7. sheet_refreshsub(ctl, old_vx0, old_vy0, old_vx0 + sht->bxsize, old_vy0 + sht->bysize);
  8. sheet_refreshsub(ctl, vx0, vy0, vx0 + sht->bxsize, vy0 + sht->bysize);
  9. }
  10. return;
  11. }

这段程序所做的是:首先记住移动前的显示位置,再设定新的显示位置,最后只要重新描绘移动前和移动后的地方就可以了。

■■■■■

估计大家会认为“这次鼠标的移动就快了吧”,但移动鼠标时,由于要在画面上显示坐标等信息,结果又执行了sheet_refresh程序,所以还是很慢。为了不浪费我们付出的各种努力,下面我们就来解决一下图层内文字显示的问题。

我们所说的在图层上显示文字,实际上并不是改写图层的全部内容。假设我们已经写了20个字,那么8×16×20=2560,也就是仅仅重写2560个像素的内容就应该足够了。但现在每次却要重写64 000个像素的内容,所以速度才那么慢。

这么说来,这里好像也可以使用refreshsub,那么我们就来重新编写函数sheet_refresh吧。

本次的*sheet.c节选

  1. void sheet_refresh(struct SHTCTL *ctl, struct SHEET *sht, int bx0, int by0, int bx1, int by1)
  2. {
  3. if (sht->height >= 0) { /* 如果正在显示,则按新图层的信息刷新画面*/
  4. sheet_refreshsub(ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1, sht->vy0 + by1);
  5. }
  6. return;
  7. }

所谓指定范围,并不是直接指定画面内的坐标,而是以缓冲区内的坐标来表示。这样一来,HariMain就可以不考虑图层在画面中的位置了。

■■■■■

我们改动了refresh,所以也要相应改造updown。做了改动的只有sheet_refresh(ctl)这部分(有两处),修改后的程序如下:

  1. sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize);

最后还要改写HariMain。

本次的*bootpack.c节选

  1. void HariMain(void)
  2. {
  3. (中略)
  4. sprintf(s, "(%3d, %3d)", mx, my);
  5. putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s);
  6. sprintf(s, "memory %dMB free : %dKB",
  7. memtotal / (1024 * 1024), memman_total(memman) / 1024);
  8. putfonts8_asc(buf_back, binfo->scrnx, 0, 32, COL8_FFFFFF, s);
  9. sheet_refresh(shtctl, sht_back, 0, 0, binfo->scrnx, 48); /* 这里! */
  10. for (;;) {
  11. io_cli();
  12. if (fifo8_status(&keyfifo) + fifo8_status(&mousefifo) == 0) {
  13. io_stihlt();
  14. } else {
  15. if (fifo8_status(&keyfifo) != 0) {
  16. (中略)
  17. sheet_refresh(shtctl, sht_back, 0, 16, 16, 32); /* 这里! */
  18. } else if (fifo8_status(&mousefifo) != 0) {
  19. i = fifo8_get(&mousefifo);
  20. io_sti();
  21. if (mouse_decode(&mdec, i) != 0) {
  22. (中略)
  23. boxfill8(buf_back, binfo->scrnx, COL8_008484, 32, 16, 32 + 15 * 8 - 1, 31);
  24. putfonts8_asc(buf_back, binfo->scrnx, 32, 16, COL8_FFFFFF, s);
  25. sheet_refresh(shtctl, sht_back, 32, 16, 32 + 15 * 8, 32); /* 这里! */
  26. (中略)
  27. sprintf(s, "(%3d, %3d)", mx, my);
  28. boxfill8(buf_back, binfo->scrnx, COL8_008484, 0, 0, 79, 15); /* 消去坐标 */
  29. putfonts8_asc(buf_back, binfo->scrnx, 0, 0, COL8_FFFFFF, s); /* 写出坐标 */
  30. sheet_refresh(shtctl, sht_back, 0, 0, 80, 16); /* 这里! */
  31. sheet_slide(shtctl, sht_mouse, mx, my);
  32. }
  33. }
  34. }
  35. }
  36. }

这里我们仅仅改写了sheet_refresh,变更点共有4个。只有每次要往buf_back中写入信息时,才进行sheet_refresh。

这样应该可以顺利运行了。我们赶紧试一试。“make run”。哦,确实比以前快多了。太好了,撒花!不过还是欠缺一些东西……