30天自制操作系统——第10天实验总结

实验日期实验项目
2020.12.3第10天 叠加处理

一、实验主要内容

1、 内容1 内存管理(续)

(1).内容概要

  • 实验内容:整理内存管理的代码;编写使用以4KB为基本单位进行内存分配和释放的函数。
  • 实验重点:向上舍入和向下舍入的理解以及代码实现。

在反复进行内存分配和内存释放之后,内存中就会出现很多不连续的小段未使用空间,这样会把man->frees消耗殆尽,这里编写以4KB为基本单元进行内存的分配和释放的函数,减少小块未使用内存浪费的情况。

向下舍入:把最后几位数字强制变为0,在16进制中可以将要舍入的数字和0相与就可以实现舍入。比如0x12345678要以0x1000向下舍入,就可以执行0x12345678 & 0xfffff000操作,将678舍去得到0x12345000。

向上舍入:首先判断最后几位,如果最后几位本来就是零则什么都不操作,如果不是零就先向下舍去,然后在加上舍入单位。比如0x12345678要以0x1000向上舍入,就可以先执行0x12345678 & 0xfffff000操作向下舍入得到0x12345000,接着再加上0x1000得到向上舍入的结果0x12346000。对于向上舍入还有一种技巧,以0x1000向上舍入为例,就是执行(i+0xfff)&0xfffff000,+0xfff就相当于进行一个进位的判断,如果加上这个值有进位,执行向下舍入就行,如果没有进位,可以直接向下舍入。

对其他进制数字的向下舍入操作:对于非二进制和非十六进制的数字,如果要向下舍入的话,无法使用与操作实现,但是可以采用除法实现,以10进制数为例,对i按照100进行向下舍入,i=(i/100)*100或者i=i-(i%100)。

(2).关键代码分析
在这里插入图片描述
这部分代码就是以4KB的大小为基本单位对实现内存分配和内存释放操作。实现思路很简单,在调用之前写好的内存分配和内存释放之前,以0x1000向上舍入,将size大小设置为为4KB的倍数。

2、 内容2 叠加处理

(1).内容概要

  • 实验内容:引入图层的概念,对第8天鼠标移动会擦除其他图像的问题进行了处理。
  • 实验重点:对图层相关功能函数实现的理解,如图层上下移动,左右移动和刷新图层信息等函数。

考虑到以后的设计中可能会有多窗口的处理,在处理鼠标问题时,采用了一种较为一般的方法,添加图层,每个图案在不同的图层上显示,所有图层叠加在一起一同构成最终看到的画面显示。最上面的小图层用来描述鼠标指针,它下面的几张图层是用来存放窗口,而最下面的一张存放桌面壁纸。同时,还要通过移动图层的方法实现鼠标指针的移动以及窗口的移动。

(2).关键代码分析

  • 图层结构部分

在这里插入图片描述
这部分代码是定义两个结构体,SHEET是图层结构体,SHTCTL是管理多重图层信息的结构体。两个结构体中各个变量的含义如左图所示,每个管理结构的大小如右图所示,约为9KB。
在这里插入图片描述在这里插入图片描述

  • 图层的相关功能函数

在这里插入图片描述
shtctl_init的功能是初始化图层管理的结构体,首先使用memman_alloc_4k函数为图层管理结构体分配内存空间,如果分配成功则继续初始化vram的地址和画面大小,并将图层的使用标志位全部置0,否则直接返回结束。

在这里插入图片描述
shtctl_alloc的功能是分配一个未使用的图层。在sheets0[]中寻找未使用的图层,如果找到了,就将其标记为”正在使用”,并将图层高度设置为-1,表示尚未显示。&ctl->sheets0[i]表示取ctl->sheets0[i]的地址。

在这里插入图片描述
shtctl_setbuf是设置缓冲区大小和透明色。

下面sheet_updown函数的代码比较长,下面分3个部分进行分析
在这里插入图片描述
这部分代码是对要设定图层高度的合法性进行判断,即不能超过当前最高图层高度+1,最低不能小于-1。如果不合法,需要将其修正后才能设定响应的高度。
在这里插入图片描述
这部分代码是对sheet排序的第1种情况,要设定的图层新高度比原图层低。实现思路:首先判断设定的高度,如果高度不小于0,则需要将中间的图层往上提,为要设定的高度腾出位置。

举个例子,如下图所示,current是当前图层高度,height是要设定的新高度,此时需要将高度为a,b,c的图层依次往上移,将高度为height的图层放在c后面。
在这里插入图片描述
如果高度为-1,则需要将old上面的图层降下来,top减少1。如下图所示,将高度为current的图层隐藏起来后,需要将current之前的图层依次往下降。
在这里插入图片描述
最后完成高度设定后使用sheet_reflesh函数重新刷新图层。

在这里插入图片描述
这部分代码是对sheet排序的第2种情况,要设定的图层新高度比原图层高。实现思路:首先判断原图层的高度,如果高度不小于0,则需要将从old以上的图层依次往下降,为要设定的高度腾出位置。

举个例子,如下图所示,current是当前图层高度,height是要设定的新高度,此时需要将高度为a,b,c的图层依次往下移,将高度为height的图层放在a前面。
在这里插入图片描述
如果原图层的高度为-1,则需要将height上面的图层依次往上移,top增加1。如下图所示,将高度为-1的图层从隐藏变为显示后,需要将待放入位置上面高度为b,a,top的图层依次往上移。
在这里插入图片描述
最后完成高度设定后使用sheet_reflesh函数重新绘制刷新图层。

在这里插入图片描述
sheet_reflesh的功能是实现图层刷新,即从下往上,将透明以外的所有像素复制到VRAM中。实现思路:使用一个三重for循环嵌套结构,最外层循环遍历按照高度遍历每个图层,内部的两重循环遍历该图层中每一个像素,并计算得到该像素在图形画面的坐标(vx,vy),将其复制到vram中。

在这里插入图片描述
这部分代码是两个函数,其中sheet_slide函数是设置图层的位置,需要注意的是,如果是对正在显示的图层进行设置,需要重新刷新该图层。sheet_free函数是释放某一图层,将其设置为隐藏状态。

  • 主函数部分

主函数部分就是调用上述是实现的功能函数,使用图层解决鼠标移动会擦除画面的问题。下面根据主函数中的内容对使用一个图层的主要过程进行总结。以背景图层的使用为例,其他图层的使用方法类似。
在这里插入图片描述

3、 内容3 提高叠加的处理速度(1)

(1).内容概要

  • 实验内容: 从图形刷新角度,对叠加处理的程序进行优化处理,提高速度。

修改1:在harib07b中的程序中,鼠标指针只有16×16=256个像素,根据其原理,只要它稍微移动一下,程序就会对整个画面进行刷新,也就是重新描绘320×200=64000个像素。而实际上,只重新描绘移动相关的部分,也就是移动前后的部分就可以了,即256×2=512个像素。这只是64 000像素的0.8%而已,根据这个思路,可以编写一个函数sheet_refreshsub函数只刷新部分图层,这样就可以提速很多。

修改2:在图层上显示文字,每次都需要调用sheet_refresh函数刷新图层。事实上,每次显示文字后,只有修改了文字所占区域的图层信息,并不需要重新全部刷新。根据这个思路,在sheet_refresh函数中调用sheet_refreshsub函数指定范围刷新。

(2).关键代码分析
在这里插入图片描述
在harib07b程序的基础上,增加了函数sheet_refreshsub,这个函数可以制定刷新的范围,将刷新的范围限定在vx0~vy1之间。需要注意的是sheet_refreshsub函数中传递的刷新范围的参数是整个画面中的坐标,而sheet_refresh函数中传递的刷新范围的参数是相对于缓冲区的坐标。

4、 内容4 提高叠加的处理速度(2)

(1).内容概要

  • 实验内容:从代码层面,对叠加处理的程序进行优化处理,提高速度。

在harib07c代码中sheet_refreshsub函数即使只刷新图层的一部分,但也要对所有图层的全部像素执行if语句,判断“是写入呢,还是不写呢”。而对于刷新范围以外的部分,就算执行if判断语句,最后也不会进行刷新,所以这纯粹就是一种浪费。从代码角度考虑,应该把for语句的范围限定在刷新范围之内。

(2).关键代码分析
在这里插入图片描述
这部分代码是在原来sheet_refreshsub函数的基础上进行修改的,限定刷新范围,这样就可以减少了繁杂的判断。代码实现思路如下图所示,假设刷新范围是左上矩形,现在开始对第i层图层刷新,从左图中可以看到图层i对刷新范围造成影响的只有黄色区域,故只需要对黄色区域进行刷新(两者的相交区域)即可。当刷新区域包含整个图层时,如右图所示,bx0和by0计算得到的值小于0,bx1和by1计算得到的值会大于图层的bxsize和bysize,此时需要重新确定范围,对应上图中代码对情况1和2的处理(bx0,by0,bx1,by1是相对于图层上的坐标)。右图只是情况1和2的其中一种例子,但总体上情况1和2的处理就是使得bx0,by0,bx1,by1所表示范围在图层上。
在这里插入图片描述在这里插入图片描述

二、遇到的问题及解决方法

1、 描述问题1

  • 问题描述

图层解决鼠标擦除背景颜色的方案是如何实现的,具体的原理是什么?

  • 解决方法

从之前的实验中可以知道,图像显示的区域只有一块,而在本次实验中引入了图层的概念,将需要显示的每个画面使用图层保存起来(每个像素点保存在数组中),当需要显示该图层的时候,就将该图层信息显示出来,即通过不断地刷新分时显示。

三、程序设计创新点

增加一个窗口图层,要求窗口必须自己动手绘制,不能直接用后一天的现成窗口,至少实现点击窗口右上角的关闭按钮(一个×)能关闭窗口

基本功能实现
init_windows函数(初始化窗口缓冲区)
下面的代码比较长,分为3个部分进行分析
在这里插入图片描述
这部分代码是关闭按钮的存储十足,使用和O摆出X的形状,不同的区域上不同的颜色,实现绘制一个关闭按钮的功能。
在这里插入图片描述
这部分代码是绘制一个大小为150
80的窗口,窗口仿照之前的背景的实现,右下侧增加灰色和黑色线条,左上方增加灰色和白色线条,来增加窗口的立体感。

在这里插入图片描述
这部分代码是将图层按钮像素存放入一个缓冲区数组中。第1句是将字符”hmr”放到20,4的位置处,作为图层窗口的标识。接下来使用二重for循环将按钮从(3,x-19)的位置(这个位置是相对于图层的坐标)开始将按钮的信息存放缓冲区中。

关闭功能
在这里插入图片描述
这部分代码的功能是使用鼠标左键单击关闭按钮能够实现关闭。 (mx,my)是鼠标相对于画面所在位置,关闭按钮在相对于窗口上从(length-19,3)开始的一个17*17的矩形框中,length是窗口图层的长度,在判断位置的时候需要将关闭按钮的坐标转化为相对于画面的坐标,即加上窗口左上角在画面位置的坐标(sht_min->vx0,sht_min->vy0),判断鼠标是否在这个范围内。如果在说明点了关闭按钮,将窗口设置为隐藏,重新刷新图层。

1、 描述创新点,关键代码及结果截图

  • 创新点1

在基础功能实现的基础上,增加了窗口移动的功能。

  • 关键代码

在这里插入图片描述
这部分代码就是移动功能的实现。在按动鼠标左键之后,判断(mx,my)是否在窗口区域内。如果在除了关闭按钮的窗口区域内时,需要改变窗口位置。当一直按住鼠标左键时,窗口就会随着鼠标移动,坐标的移动和鼠标保持一致,故只需要将窗口左上角的初始坐标加上鼠标坐标的变化量(mdec.x,mdec.y)即可,得到新的坐标(a,b)就是移动后窗口的位置。对a,b的合法性进行检测后,使用sheet_slide函数将窗口移动到(a,b)这个位置。

2、 描述创新点,关键代码及结果截图

  • 创新点2

在基础功能实现的基础上,增加桌面图标功能,即关闭窗口后,可以通过这个图标再次打开窗口。

  • 关键代码

桌面图标的图层实现和窗口图层的实现基本一致,这里不做说明。
在这里插入图片描述
这部分代码的功能是使用鼠标左键单击图标后打开窗口。首先判断(mx,my)是否在图标所在位置,由于图标在桌面上是固定的,这里直接使用相对于画面的坐标。如果鼠标在图标所在位置,首先使用sheet_slide函数将小窗口移动到(100,55)的位置,接着将窗口高度设置为1,改为显示。这里仿照windows系统,打开窗口后,图标的背景颜色会改变。调用init_tubiao初始化图标图层,参数1表示深色(参数0表示白色)。最后刷新图标区域。

主函数代码实现
在这里插入图片描述
这是对相关变量的定义

在这里插入图片描述
这是对图层的属性设置

在这里插入图片描述
这是按下鼠标左键的处理。

效果展示
在这里插入图片描述在这里插入图片描述
左图是运行程序后的初始显示画面,当使用鼠标左键单击图标后,结果如右图所示,窗口显示出来,图标变灰,表示正在打开窗口。

在这里插入图片描述在这里插入图片描述
左图是关闭窗口后的画面,右图是打开窗口,将窗口进行移动。

四、实验心得体会

本次实验是自制操作系统的第10天,本次实验主要分为两个部分,第一部分是对内存管理进行一些后续的处理,整理源代码,实现以4KB为基本内存单元对内存进行分配和释放;第二部分引入图层的概念,对之前遗留下来的鼠标问题进行了优化,并对程序做了优化处理。内容不多,但是值得去深究,在这次实验的创新点中,利用图层的结构,我实现了一个简单的窗口,可以使用X关闭窗口,使用桌面图标打开窗口,以及移动窗口。除了这些,相信图层这部分的内容可以做的东西还很多,比如窗口最大化,最小化,仿照windows系统的一些功能,我们可以迁移更多的内容到我们自己的操作系统中。

在这次实验过程中,也体会到一点。做开发设计不是一开始就写成最终版本的,最终版本是通过不断地调试,优化得到的,例如本次实验中一开始编写了sheet_refresh函数,但是由于性能不好,进行了优化编写sheet_refreshsub函数,在后续使用过程中在sheet_refresh中又调用sheet_refreshsub函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值