代碼的深入講解和調試請參看視訊:
Linux kernel Hacker, 從零建構自己的核心
在前幾節,我們使用窗體圖層疊加技術,解決了窗體,例如滑鼠移動時,破壞其他窗體界面的問題,但以此同時,也引入了新的問題。當滑鼠移動時,核心會将所有視窗重新繪制,如果目前系統打開的視窗很多,假設有幾十上百個,那麼滑鼠動一下,就重新繪制上百個視窗,這對cpu資源的消耗就會非常大,整個系統的性能就會被拖垮,由此,我們需要優化核心對視窗更新重繪的設計,降低不必要的損耗。
我們現在的滑鼠,占據的視窗大小是16*16, 也就是256個像素,按照現在核心的重繪機制,隻要滑鼠稍微移動一下,就需要對整個畫面進行重新整理,也就是重新繪制320*200 = 64000 個像素點,其實隻要重新繪制滑鼠移動的相關區域就可以了,例如,滑鼠從原來坐标點(0,0),移動到坐标點(1,1), 那麼核心隻要重繪區域[(0,0), (16,16)] 和【(1,1), (17,17)] 即可。也就是隻需要繪制的像素是256*2=512,這隻要64 000 個像素的百分之0.8, 也就是說,隻要我們稍微更改一下繪制機制,整個系統的性能能實作上千倍的提升!
由此,我們添加一個新的繪制函數:
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 = ; h <= ctl->top; h++) {
sht = ctl->sheets[h];
buf = sht->buf;
for (by = ; by < sht->bysize; by++) {
vy = sht->vy0 + by;
for (bx = ; 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;
}
}
}
}
}
}
這個函數功能就隻對每個窗體繪制局部區域,該區域的左上角是(vx0,vy0),右下角是(vx1, vy1).
接着我們改進一下原來的sheet_silde函數,這個函數意義在于視窗移動後重新繪制,現在我們把它改成重新整理視窗移動前後所占據的兩個區域既可:
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 >= ) {
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);
}
}
第一次調用sheet_refreshsub,為的是重新整理窗體移動前的區域,第二次調用sheet_refreshsub,是根據窗體移動後的坐标,重新繪制窗體。
原來的sheet_refresh函數也可以根據局部重新整理的原理重新實作以下:
int sheet_refresh(struct SHTCTL *ctl, struct SHEET *sht, int bx0, int by0, int bx1, int by1) {
if (sht->height >= ) {
sheet_refreshsub(ctl, sht->vx0 + bx0, sht->vy0 + by0, sht->vx0 + bx1,
sht->vy0 + by1);
}
return ;
}
還有一處需要改進的是文字的顯示,原理我們顯示文字時,同樣是需要把所有視窗重新繪制一次,二是我們的文章隻能繪制在桌面背景上。現在我們有了圖層的概念,是以我們可以把文字顯示機制改進一下,改進一是隻對文章所占據的區域進行重新整理,二是文字可以繪制到給定的圖層上,這樣文章就可以繪制到指定的窗體,而不再隻限制于桌面,代碼如下:
void showString(struct SHTCTL *shtctl ,struct SHEET *sht, int x, int y, char color, unsigned char *s ) {
int begin = x;
for (; *s != ; s++) {
showFont8(sht->buf, sht->bxsize, x, y,color, systemFont+ *s * );
x += ;
}
sheet_refresh(shtctl, sht, begin, y, x , y + );
}
輸入參數中的sht對應要繪制字元串的視窗圖層,調用的sheet_refresh目的就是僅僅更新文字所占據的區域。
有了上面的改進後,雖然我們的系統在外在表現上,沒有明顯的變化,但實際上,性能已經有了上千倍的提升。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISNykzM0gzMxEDOxETM2EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)