《30天自制操作系统》笔记(08)——叠加窗口刷新

《30天自制操作系统》笔记(08)——叠加窗口刷新

进度回顾

上一篇中介绍了内存管理的思路和算法,我们已经可以动态申请和释放内存了。这不就是(Heap)么。在此基础上,本篇要做一段程序,一并解决窗口和鼠标的叠加处理问题。

问题

在之前的《《30天自制操作系统》笔记(05)——启用鼠标键盘》篇,已经能够移动鼠标了。但是遗留了如下图所示的一个小问题。

我们希望的情形是这样的:

实际上,当前版本的OS还没有窗口图层的东西。本篇要做一段程序,一并解决窗口和鼠标的叠加处理问题。

在屏幕上显示多个窗口,类似于photoshop中显示多个图层。从桌面壁纸到每个窗口(层)到最上层的鼠标(鼠标也视为一个小窗口),将绘制了图案的透明图层叠加起来。

最初版解决方案

首先定义图层的数据结构。

 1 #define MAX_SHEETS        256
 2 struct SHEET {
 3     unsigned char *buf;
 4     int bxsize, bysize, vx0, vy0, col_inv, height, flags;
 5 };
 6 struct SHTCTL {
 7     unsigned char *vram;
 8     int xsize, ysize, top;
 9     struct SHEET *sheets[MAX_SHEETS];
10     struct SHEET sheets0[MAX_SHEETS];
11 };

原作者用sheet表示图层,看来英文很一般,用 layer似乎更恰当。

图层层次变更(当前窗口变更)、图层位置移动(窗口位置移动)这些代码实在没什么可说。刷新函数也很简单,就是从下(桌面壁纸)往上(鼠标),将透明以外的所有像素复制到VRAM中。代码如下。

 1 void sheet_refresh(struct SHTCTL *ctl)
 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                 c = buf[by * sht->bxsize + bx];
14                 if (c != sht->col_inv) {
15                     vram[vy * ctl->xsize + vx] = c;
16                 }
17             }
18         }
19     }
20     return;
21 }

很明显这样太没效率了。下面就对刷新功能进行优化。

优化1-移动优化

鼠标层只有16*16=256个像素。但是根据上文的代码,只要鼠标稍微动一下,OS就要重绘320*200=64000个像素。这是不必要的。只需重绘移动前后的部分即256*2=512个像素就可了。512只是64000的0.8%。以后启用高分辨率了,性能提升会更多。

 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 }

窗口(鼠标)移动时,只需先调用此函数重绘移动前的部分,再调用此函数重绘移动后的部分就行了。

优化2-文字优化

移动鼠标时,由于要在桌面上显示坐标等信息,又被迫重绘了整个桌面,所以还是很慢。下面来优化这个瓶颈。

原理和优化1是一样的。只重绘文字所在的部分就行了。不再赘述。

优化3-减少判定

在上文的"sheet_refreshsub"函数中,使用了长长的"if (vx0 <= vx && vx < vx1 && vy0 <= vy && vy < vy1)"判定。但对于窗口外(即透明色)的位置,根本不用重绘,所以这个判定也就不需要了。我们就把这一点优化一下,只更新窗口所在的矩形范围内的地方。

 1 void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1)
 2 {
 3     int h, bx, by, vx, vy, bx0, by0, bx1, by1;
 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         /* 使用vx0~vy1,对bx0~by1进行倒推*/
10         bx0 = vx0 - sht->vx0;
11         by0 = vy0 - sht->vy0;
12         bx1 = vx1 - sht->vx0;
13         by1 = vy1 - sht->vy0;
14         if (bx0 < 0) { bx0 = 0; }
15         if (by0 < 0) { by0 = 0; }
16         if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }
17         if (by1 > sht->bysize) { by1 = sht->bysize; }
18         for (by = by0; by < by1; by++) {
19             vy = sht->vy0 + by;
20             for (bx = bx0; bx < bx1; bx++) {
21                 vx = sht->vx0 + bx;
22                 c = buf[by * sht->bxsize + bx];
23                 if (c != sht->col_inv) {
24                     vram[vy * ctl->xsize + vx] = c;
25                 }
26             }
27         }
28     }
29     return;
30 }

说实话原作者的变量命名还是有点晦涩。理解原理就可以了,代码不需费劲看,因为真的很简单。

总结

本篇虽然没有在桌面上画出类似windows应用程序窗口那样的窗口,但是已经为其准备好了重绘的数据结构和算法。而且对算法进行优化,虽然优化原理及其简单(缩小不必要的重绘范围),但是效果很好。话是这么说,这个优化效果就没办法用图片展示了,自己在本地分别运行一下优化前后的版本吧还是。(建议用VMware,这个能看到很明显的差别,在QEMU下我测试的时候根本没有差别,未优化的版本也不卡)

有了本篇的准备,下一步就可以制作和显示窗口了。

请查看下一篇《《30天自制操作系统》笔记(09)——绘制窗口》

posted @ 2014-06-07 00:29  BIT祝威  阅读(4953)  评论(7编辑  收藏  举报
canvas start.

canvas end.