zoukankan      html  css  js  c++  java
  • 《30天自制操作系统》10_day_学习笔记

    harib07a:
      整理内存管理函数:memman_alloc和memman_free能够以最小1字节进行内存管理,但时间久了后,容易产生外部碎片;为此,笔者编写了一些以0x1000字节为单位进行内存分配和释放的函数,它们会把指定的内存大小按照0x1000字节为单位向上舍入(roundup),0x1000大小正好是4KB.
      1、向下舍入:以0x1000为单位向下舍入
        0x1234_5678 & 0xffff_f000 = 0x1234_5000;
        i = i & 0xffff_f000 ;
      2、向上舍入:以0x1000为单位向上舍入
        i = (i + 0xfff) & 0xffff_f000

    unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size) {
        unsigned int a;
        //以0x1000为单位向上舍入的方式进行内存分配
        size = (size + 0xfff) & 0xfffff000;
        a = memman_alloc(man, size);
        return a;
    }
    int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size) {
        int i;
        //以0x1000为单位向上舍入的方式进行内存释放
        size = (size + 0xfff) & 0xfffff000;
        i = memman_free(man, addr, size);
        return i;
    }

    harib07b:
      图层的定义:下面我们来解决图层叠加的问题,编写一段程序,既适用于于鼠标的叠加,也适应于窗口的叠加!

    #define MAX_SHEETS        256
    //图层的整体大小:bxsize*byseze
    //vx0和vy0表示图层在画面上坐标的位置
    //col_inv表示透明色色号
    //height :表示图层的高度
    //flags : 用于存放图层的各种设定信息
    struct SHEET {               //图层的结构体
        unsigned char *buf;         //记录图层上描绘内容的结构体
        int bxsize, bysize, vx0, vy0, col_inv, height, flags;
    };
    /* 图层管理的结构体;实现图层的叠加 */
    struct SHTCTL {
        unsigned char *vram;        //VRAM地址
        int xsize, ysize, top;       //VRAM画面的大小;top:最上面图层的高度
        struct SHEET *sheets[MAX_SHEETS];//sheets0[]啊没找高度排序后的图层地址
        struct SHEET sheets0[MAX_SHEETS];//用于存放256个图层的信息
    };

      图层的处理:界面图层处理的函数都被封装在sheet.c中,关于图层的具体实现方法和原理请对照图片和注释看

      (注释已经很详细了,应该能看懂!代码有点长,我们折起来吧!)

       

    //sheet.c
    #include "bootpack.h"
    
    #define SHEET_USE        1
    struct SHTCTL *shtctl_init(struct MEMMAN *memman, unsigned char *vram, int xsize, int ysize)
    {                                          //图层控制变量的初始化
        struct SHTCTL *ctl;
        int i;
                                               //分配图层管理空间
        ctl = (struct SHTCTL *) memman_alloc_4k(memman, sizeof (struct SHTCTL));
        if (ctl == 0) {                           //分配空间失败
            goto err;
        }
        ctl->vram = vram;                          //给控制变量赋值
        ctl->xsize = xsize;
        ctl->ysize = ysize;
        ctl->top = -1;                              /* 表示没有图层(0) */
        for (i = 0; i < MAX_SHEETS; i++) {
            ctl->sheets0[i].flags = 0;               /* 标记为未使用 */
        }
    err:
        return ctl;                                //初始化失败
    }
    
    struct SHEET *sheet_alloc(struct SHTCTL *ctl)
    {                                          //用于取得新生成的未使用的图层
        struct SHEET *sht;
        int i;
        for (i = 0; i < MAX_SHEETS; i++) {
            if (ctl->sheets0[i].flags == 0) {        //找到第一个未使用的图层
                sht = &ctl->sheets0[i];            //返回第一个未使用图层的地址
                sht->flags = SHEET_USE;            /* 要分配,标记为正在使用 */
                sht->height = -1;                 /* 隐藏,此时高度还没有设置 */
                return sht;                      //取得(分配)成功
            }
        }
        return 0;                        /* 没有空闲图层,分配失败 */
    }
    //设定图层缓冲区大小和透明色的函数
    void sheet_setbuf(struct SHEET *sht, unsigned char *buf, int xsize, int ysize, int col_inv)
    {
        sht->buf = buf;
        sht->bxsize = xsize;
        sht->bysize = ysize;
        sht->col_inv = col_inv;
        return;
    }
    //设定底板高度的函数:
    void sheet_updown(struct SHTCTL *ctl, struct SHEET *sht, int height)
    {
        int h, old = sht->height;                    /* 存储设置前的高度信息 */
    
                                                /* 如果指定的高度过高或过低,则进行修正 */
        if (height > ctl->top + 1) {                  //需要设定的高度与目前图层最高高度比较
            height = ctl->top + 1;
        }
        if (height < -1) {
            height = -1;
        }
        sht->height = height;                        /* 设定高度 */
    
                                               /* 有新的高度了,对sheets[]重新排序 */
        if (old > height) {                        /* 比以前低 */
            if (height >= 0) {
                                               /* 把中间的往上提 */
                for (h = old; h > height; h--) {     //这里不断把当前高度低的图层,不断的向上赋值
                    ctl->sheets[h] = ctl->sheets[h - 1];
                    ctl->sheets[h]->height = h;
                }
                ctl->sheets[height] = sht;
            } else {                            /* 高度小于0时,表示图层没有初始化,隐藏 */
                if (ctl->top > old) {
                                               /* 把上面的降下来 */
                    for (h = old; h < ctl->top; h++) {//这里不断把当前高度图层,不断地向下赋值
                        ctl->sheets[h] = ctl->sheets[h + 1];
                        ctl->sheets[h]->height = h;
                    }
                }
                ctl->top--;                       /* 现实中的图层少了一个,最上面的图层高度下降 */
            }
            sheet_refresh(ctl);                    /* 按照新图层的信息重新绘制画面 */
        } else if (old < height) {                  /* 图层更新后的高度比以前高 */
            if (old >= 0) {
                                        /* 把中间的拉下去 */
                for (h = old; h < height; h++) {     //不断的把图层往前移动
                    ctl->sheets[h] = ctl->sheets[h + 1];
                    ctl->sheets[h]->height = h;
                }
                ctl->sheets[height] = sht;
            } else {                            /* 由隐藏状态转为显示状态 */
                                              /* 将已经在上面的提上来 */
                for (h = ctl->top; h >= height; h--) { //不断地把图层往后移动
                    ctl->sheets[h + 1] = ctl->sheets[h];
                    ctl->sheets[h + 1]->height = h + 1;
                }
                ctl->sheets[height] = sht;
                ctl->top++;                      /* 由于已显示的图层增加了1个,所以最上面的图层高度增加 */
            }
            sheet_refresh(ctl);                   /* 按照新图层信息重新描绘画面 */
        }
        return;
    }
    //图层刷新函数。
    //刷新原理:对于已经设定的高度的所有图层,从下往上,将透明以外的所有像素都复制到VRAM中,由于是从下往上复制,所以最后最上面的内容就留在了画面上。
    void sheet_refresh(struct SHTCTL *ctl)
    {
        int h, bx, by, vx, vy;
        unsigned char *buf, c, *vram = ctl->vram;
        struct SHEET *sht;
        for (h = 0; h <= ctl->top; h++) {           //从图层0 开始,向高图层一个一个走
            sht = ctl->sheets[h];                  //获得每一层的地址
            buf = sht->buf;                     //将该地址的内容放到VRAM缓冲区
            for (by = 0; by < sht->bysize; by++) {    //VRAM按照从左到右,从上到下的顺序,不断的更新VRAM缓存
                vy = sht->vy0 + by;
                for (bx = 0; bx < sht->bxsize; bx++) {
                    vx = sht->vx0 + bx;
                    c = buf[by * sht->bxsize + bx];
                    if (c != sht->col_inv) {
                        vram[vy * ctl->xsize + vx] = c;
                    }
                }
            }
        }
        return;
    }
    //功能:不改变图层的高度,只上下左右移动图层(滑动)
    void sheet_slide(struct SHTCTL *ctl, struct SHEET *sht, int vx0, int vy0)
    {
        sht->vx0 = vx0;
        sht->vy0 = vy0;
        if (sht->height >= 0) {               /* 正在显示 */
            sheet_refresh(ctl);               /* 按照新图层的信息刷新页面 */
        }
        return;
    }
    //释放已经使用图层的内存的函数
    void sheet_free(struct SHTCTL *ctl, struct SHEET *sht)
    {
        if (sht->height >= 0) {
            sheet_updown(ctl, sht, -1);        /* 如果该图层正在显示,设置height=-1;隐藏 */
        }
        sht->flags = 0;                     /* FLAG=0表示该图层未使用 */
        return;
    }
    View Code

    harib07c:
      上一步我们实现了界面图层显示的叠加,但当我们MAKE RUN 发现实在是太慢了!接下来我们来提高图层叠加处理的速度!
      1、提高刷新的速度
      从void sheet_refresh(struct SHTCTL *ctl)中我们可以看到,只要鼠标动了,就会对整个界面进行刷新!然而我们只需让它刷新相关的部分。我们在函数sheet_refresh()添加一个条件函数IF,只刷新鼠标经过的部分。

    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;
    }

      2、使用fefreshsub提高sheet_slide的速度

      //首先记住移动前的位置,在设定新的位置,最后只要重新描绘移动前和移动后的地方。
      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);

      3、图层内文字显示问题
      当我们在图层上显示或者改写文字时,并不是改写图层的全部内容;但是我们却要每次重写64000个像素的内容,怎么办?我们重新来编写sheet_refresh()函数吧!把文字显示单独处理。
      注  意:指定的范围不是直接指定画面内的左边,而是以缓冲区的坐标来表示的。

    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;
    }

      同时也要对sheet_updown进行修改,当然改动的只有sheet_refresh(ctl):
      sheet_refreshsub(ctl, sht->vx0, sht->vy0, sht->vx0 + sht->bxsize, sht->vy0 + sht->bysize);

    harib07c:
      make run一下,还是感觉有些别扭;我们看看还有那些可以改进的地方。我们看看上面的refreshsub()发现即使不写入像素,任然要对每一层的每一个像素进行判断。但是对于需要刷新以外的部分,这就做了很多无用功。因此我们做了一下改良(如下图)

       

    void sheet_refreshsub(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1){
        int h, bx, by, vx, vy, bx0, by0, bx1, by1;
        unsigned char *buf, c, *vram = ctl->vram;
        struct SHEET *sht;
        for (h = 0; h <= ctl->top; h++) {
            sht = ctl->sheets[h];
            buf = sht->buf;
            /* 使用vx0--vy1,对bx0--by1进行倒推得到图层中需要刷新的范围
                vx = sht->vx0 ; --> bx = vx - sht->vx0;  */
            bx0 = vx0 - sht->vx0;               //倒推得到需要刷新的范围(bx0,by0)(bx1,by1)
            by0 = vy0 - sht->vy0;
            bx1 = vx1 - sht->vx0;
            by1 = vy1 - sht->vy0;
            if (bx0 < 0) { bx0 = 0; }            //第一种情况:刷新范围的一部分被其他图层遮盖;用于处理刷新范围在图层外侧的情况
            if (by0 < 0) { by0 = 0; }
            if (bx1 > sht->bxsize) { bx1 = sht->bxsize; }//第二种情况:需要刷新的坐标超出了图层的范围
            if (by1 > sht->bysize) { by1 = sht->bysize; }
                                       //改良后,这段循环不再对整个图层进行刷新,只刷新需要的部分
            for (by = by0; by < by1; by++) {
                vy = sht->vy0 + by;
                for (bx = bx0; bx < bx1; bx++) {
                    vx = sht->vx0 + bx;
                    c = buf[by * sht->bxsize + bx];    //获得该像素出缓冲区的内容
                    if (c != sht->col_inv) {
                        vram[vy * ctl->xsize + vx] = c; //将该像素出缓冲区的内容给VRAM
                    }
                }
            }
        }
        return;
    }
  • 相关阅读:
    Lucene in action 笔记 case study
    关于Restful Web Service的一些理解
    Lucene in action 笔记 analysis篇
    Lucene in action 笔记 index篇
    Lucene in action 笔记 term vector
    Lucene in action 笔记 search篇
    博客园开博记录
    数论(算法概述)
    DIV, IFRAME, Select, Span标签入门
    记一个较困难的SharePoint性能问题的分析和解决
  • 原文地址:https://www.cnblogs.com/pengfeiz/p/5798664.html
Copyright © 2011-2022 走看看