天天看點

提高窗體圖層疊加處理速度

代碼的深入講解和調試請參看視訊:

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目的就是僅僅更新文字所占據的區域。

有了上面的改進後,雖然我們的系統在外在表現上,沒有明顯的變化,但實際上,性能已經有了上千倍的提升。

提高窗體圖層疊加處理速度

繼續閱讀