top刷新间隔_计算机自制操作系统(二二):Windows窗口界面---解决刷新问题

22cb44cf7058a6f91e0982beec62c8a0.png

一、图层技术问题

虽然我们已经成功实现了Windows窗口的叠加显示,但是这个显示机制还会存在如下问题:

1.每次刷新屏幕都需要全部显示所有的图层的卡顿问题:因为目前我们的刷新原理是一旦窗口有消息触发(比如挪动鼠标或窗口),我们会遍历图层管理器的数组ctr->sheets[],保证height值是小到大的来显示所有图层,一直显示完top个图层。如果,我们的top值较大,有10个乃至100个窗口,这样一来计算机动不动就会刷新全部图层,由于这个数据量巨大,显然这个显示会出问题,表现出的现象是屏幕会自上到下的进行“刷新”或出现屏幕卡顿。

2.屏幕同一个像素点同时存在不同图层显示的闪烁问题:现在假设屏幕上有一个16*16的像素点矩阵已经被鼠标图形占据,而我们现在有另外一个窗口在高频显示动态的变化值(如计数器),而这个值的显示位置刚好和鼠标像素位置重合,这样的效果就会出问题:动态变化的时候,窗口和鼠标重叠的像素点会一直闪烁不停。这是因为,鼠标和窗口都在争夺该像素的显示权,所以会导致闪烁不停!

二、解决方法

作为视窗操作系统,以上两个问题是必须要解决的。解决方法是:

1.刷新部分图层。我们需要优化现有逻辑,将各种情况进行枚举,选择性的刷新部分图层:

1.1 窗口图层无变化:窗口仅内容有变化,而位置无变化。这种情况下,该窗口以下的图层就没有必要刷新了,只需要刷新该窗口本身以及它上面的图层(因为窗口刷新可能给会覆盖掉上层部分,包括最上层的鼠标)。具体在程序中为sheet_refresh函数。

1.2 窗口图层无变化:窗口位置有变化,也即比如移动(slide)。这种情况下,需要刷新它下面所有的图层,因为移动之后老位置会漏出所有的下层。另外,还需要刷新它到在位置的图层。具体在程序中为sheet_slide函数。

1.3 窗口图层有变化:up或down。同样的方法,也只需要刷新部分图层,不再累述。在程序中为sheet_updown函数。

可以看出,这种方法的最终目的是:尽最大限度的减少窗口刷新数据。

2.map图形技术。

第2个问题其实是窗口之间的重叠冲突问题,那么我们必须要用下面这种方法来避免:无论有多少个图层,我们只需规定屏幕上的某一个像素点只归属于1个图层,每层窗口的视频数据在显示的时候做一个判断:只有属于本层的数据才显示出了,不属于本层的数据不显示。

3c3a362a15577504711b597f72f6a4d8.png

具体实现过程:

1.专门分配一个和VRAM一样大小的map内存区,这个内存区的每个象素位置用来填写该象素点属于哪个图层(SID)。

2.在图层管理器数据结构中增加一个指针节点:*map,用来指向上面的map区。

struct SHTCTL {
	unsigned char *vram, *map;     
	int xsize, ysize, top;
	struct SHEET *sheets[MAX_SHEETS];
	struct SHEET sheets0[MAX_SHEETS];
};

3.将各图层sheet的图层编号值(height) ,写进map区。

void sheet_refreshmap(struct SHTCTL *ctl, int vx0, int vy0, int vx1, int vy1, int h0)
{
	int h, bx, by, vx, vy, bx0, by0, bx1, by1;
	unsigned char *buf, sid, *map = ctl->map;
	struct SHEET *sht;
	if (vx0 < 0) { vx0 = 0; }
	if (vy0 < 0) { vy0 = 0; }
	if (vx1 > ctl->xsize) { vx1 = ctl->xsize; }
	if (vy1 > ctl->ysize) { vy1 = ctl->ysize; }
	for (h = h0; h <= ctl->top; h++) {
		sht = ctl->sheets[h];
		sid = sht - ctl->sheets0;  
		buf = sht->buf;
		bx0 = vx0 - sht->vx0;
		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;
				if (buf[by * sht->bxsize + bx] != sht->col_inv) {
					map[vy * ctl->xsize + vx] = sid;
				}
			}
		}
	}
	return;
}

该程序遍历所有的图层sheet,把所有图层的每个视频象素点都用sid进行编号填写。关键语句:sid = sht - ctl->sheets0,含义:结构体名称 sht和数组名称ctl->sheets0代表的都是内存地址,sid 就是两个内存地址的差值,也即是这两个地址之间间隔多少个变量元素(sht是放在数组sheets0里面的,因此它们是同一种数据类型)。这里由于是从数组开始位置计算的,因此sid其实就是每个图层sheet的数组下标值,对于正在显示的图层窗口来说,这个差值其实就是height值。

cecf8986d69406c09915b8039be1b9f5.png
应该是B-A=2,图上写反了

这个过程有点麻烦,稍做解释就简单:刚开始是0号图层是桌面,那么它的窗口大小是xsize*ysize,那么执行以上函数之后,map区所有的数据都是一个sid=0。随后,我们增加了一个1号图层窗口WIN1,假设它的窗口大小是100*100,位置是(0,0),那么执行以上函数之后,map区的数据在map[0]---map[100*100]的SID就变成了1。同样,在增加2号窗口,那么map区相应位置的数据就会变成2......始终,底层的一些数据SID值其实会被上层窗口的SID值覆盖掉。这样,就能保证屏幕每个象素点的数据只能归属于某一个图层。不光新增窗口,我们在挪动窗口等操作时,任然需要实时更新map区的数据。

4.显示窗口的时候,关联map区数据来控制不重叠。它最终重要的功能就是显示每层窗口的时候,必须先判断象素点是不是属于当前图层,也即通过map区的SID值来判断,如果不是则不予显示,这样的话,所有的图层就永远不会有交叉争用的时候。函数是:sheet_refreshsub。map区数据控制显示技术,原理就是最终呈现出来的一整幅屏幕图像,实际是由属于不同图层的所有像素“东拼西揍”组合而成!。

4e5c59084754be48b3cf12fa58c03c10.png

所以,现在每个象素点便会有两个显示数据:视频数据和图层数据。这个机制反倒又有点像字符模式下的显示控制了。

三、显示效果

最后,我们通过制作一个高速更新的计数器窗口来验证,如果鼠标和窗口重叠在一起的地方,屏幕没有发生闪烁的情况,则说明是成功的。

466fee82aa26b90fddf7ac9838a2749c.png
消除图层竞争显示闪烁情况
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值