《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天自制操作系统》笔记(08)——叠加窗口刷新,布布扣,bubuko.com

时间: 06-05

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

30天自制操作系统笔记(第四天)

这一节讲的最出彩的地方是c语言的地址. 而要理清c语言地址,又必须追根溯源,看看汇编里内存地址的使用. MOV AL,0X15 MOV [1024],AL MOV BYTE[1024],0X15 这两种指令效果相同,都是在这个内存地址里存入一个数据,而学过汇编的我们知道,直接往内存某地址存入数据时,要说明填入的数据大小,或者说数据类型,不然机器不知道怎么填入该数据,到底是按照8位填入,还是十六位填入.因此,这个byte必不可少,而前面的指令,由于AL已经明确了是八位,因此不用说明. 好了,接下来

《30天自制操作系统》笔记(09)——绘制窗口

<30天自制操作系统>笔记(09)--绘制窗口 进度回顾 上一篇中介绍了图层式窗口管理的思路和算法.在此基础上,本篇就解决绘制窗口及其简单的优化问题. 这里稍微吐槽一下<30天自制操作系统>原作者.全书我刚刚看了三分之一,写得确实不错,但是我能感受到原作者是习惯用汇编语言和汇编思维来写程序的.虽然书里尽量使用了C语言,但给我一种用C写汇编的感觉.也可能是原作者故意简化了OS开发过程,方便初学者理解吧.幸好这在我预料之中,一开始我就打算先看完这本书然后自己再从零设计OS的. 看似立体

《30天自制操作系统》笔记(01)——hello bitzhuwei’s OS!

<30天自制操作系统>笔记(01)--hello bitzhuwei's OS! 最初的OS代码 1 ; hello-os 2 ; TAB=4 3 4 ORG 0x7c00 ; 指明程序的装载地址 5 6 ; 以下这段是标准FAT32格式软盘专用的代码 7 8 JMP entry 9 DB 0x90 10 DB "HELLOIPL" ; freeparam 启动区的名称可以是任意的字符串(8字节) 11 DW 512 ; 每个扇区(sector)的大小(必须为512字节)

《30天自制操作系统》笔记(04)——显示器256色

<30天自制操作系统>笔记(04)--显示器256色 进度回顾 从最开始的(01)篇到上一篇为止,已经解决了开发环境问题和OS项目的顶层设计问题. 本篇做一个小练习:设置显卡显示256色. 原理 设置显卡模式 调用BIOS中断命令INT 0x10,设置显卡模式为VGA图形模式,320*200*8位彩色模式,调色板模式.代码如下. 1 MOV AL,0x13 ; VGA图形模式,320*200*8位彩色模式 2 MOV AH,0x00 3 INT 0x10 设置调色板 256色的调色板是这样一个

《30天自制操作系统》读书笔记(2)hello, world

让系统跑起来 要写一个操作系统,我们首先要有一个储存系统的介质,原版书似乎是06年出版的,可惜那时候没有电脑,没想到作者用的还是软盘,现在的电脑谁有软驱?不得已我使用一张128M的SD卡来代替,而事实上你用的是U盘还是软盘对我们的操作系统没有影响,缺点是你的U盘刷入系统后容量只能是1440 MB,即当年流行的3.5英寸软盘的大小,当然不用担心,再格式化一次(用DiskGeniu),就可以恢复. 我做事情的话,总是怕自己的努力的结果白费了,害怕辛辛苦苦看完这本书但是发现做出来的东西现在根本没法用,

多定时器处理1(30天自制操作系统--读书笔记)

自认为写过很多MCU程序,但总是回头想想,我所了解的MCU编程思想大体有两种,其中具体的想法我得再找时间写下来. 总想总结出一个可扩展的,易移植的写法,但能力还没到这个层次.但<30天自制操作系统>这本书确实给我了一个思路,就像我已经写过的两篇读书笔记. 将两个独立的内容--FIFO和内存动态管理做到高度模块化,尤其是其中数据结构模型的设计更是我学习的好例子. 今天要学习的设计内容是多定时器处理.原书对这部分的处理讲的很详细,由浅入深,看得我由衷佩服作者,也可能是因为我水平低,稍稍看出点门道来

内存管理(30天自制操作系统--读书笔记)

今天继续读书笔记,“挑战内存管理”(30天自制操作系统). 为什么对这块内容敢兴趣呢,因为曾经遇到这么一个问题.在STM32程序中想使用队列,可不是上篇讲的FIFO,而是使用了较大的内存空间,又想做队列的顺序存取管理. 在这个队列里用到了malloc,动态申请内存,一开始是直接申请不到内存,后来在启动脚本里更改了设置堆的地址值,可以申请成功,但发现申请几次后,也申请不到内存. 果然MCU级别的程序,内存这块处理起来就没有windows程序那么随心所欲了.讲了这么多,开始正题吧. 1.相关数据结构

单字节的FIFO缓存(30天自制操作系统--读书笔记)

从今天起,写一些读书笔记.最近几个月都在看<30天自制操作系统这本书>,书虽说看的是电子书,但可以花钱买的正版书,既然花费了金钱,就总得有些收获. 任何人都不能总是固步自封,想要进步就得学习别人的知识,对于程序员而言,最简单的方法即是学习别人的代码. 今天的标题是“单字节的FIFO缓存”,其实就是做一个FIFO,看名字就知道了.也就4个函数和1个相关结构体,这样的小代码在嵌入式系统中很常用,也会很好用. 1.相关数据结构体 struct FIFO8 { unsigned char *buf;

《30天自制操作系统》读书笔记(4) 绘图

暑假果然是滋生懒散的温床. (╯‵□′)╯︵┻━┻ 好久不动都忘记之前做到哪里了, 上次好像做到了C语言的引入, 这一节所做的东西都相当轻松, 将会绘制出操作系统的基本界面. 绘图的原理 按照书中所说, 将值写入到显存中就能在屏幕上显示相应的像素, 在asmhead.nas 中有这一段: 1 CYLS EQU 0x0ff0 ; 设定启动区 2 LEDS EQU 0x0ff1 3 VMODE EQU 0x0ff2 ; 关于颜色数目的信息,颜色的位数 4 SCRNX EQU 0x0ff4 ; 分辨率