内容渲染速度是决定一个UI成败的关键。无论UI做得多华丽,没有速度都没有意义。

在MFC,WTL等开发框架下,每个控件都是一个窗口,窗口只需要画前景,背景。因为窗口之间的内容不需要做混合,一个子窗口的一次刷新只涉及该窗口本身,和其它窗口无关,因此这样效率很高。但是美中不足在于,窗口之间内容是孤立的,要想不同窗口之间的内容更协调,对美术有很高的要求,同时也基本只能适应个别窗口大小相对固定的场景。

要使UI更加漂亮,最简单有效的方法就是采用alpha混合的方式将各层的窗口相互混合,这样窗口之间没有了边界的感觉,从而使得UI更像一个整体,这也是现代UI的主要实现方式。

想像一下,如果一个最上层的子窗口内容发生了变化,UI系统如何把窗口内容绘制出来呢?

首先需要通知UI系统的渲染对象说我的窗口显示区域内容发生了变化,请求重绘。

UI系统拿到渲染对象后,对渲染范围设定剪裁区(clip),防止刷新那些不需要重绘的区域。

UI系统从最顶层的窗口开始依次绘制每一层的和剪裁区重叠的窗口的内容(不同窗口之间绘制内容的混合由绘制方法定义,例如图片可能是利用alpha通道)。

为了防止绘制过程中出现闪烁,一般上面绘制都是在一个内存绘图设备(如内存DC)上进行。在全部绘制完成后,将绘制内容再呈现到屏幕。

那么问题来了:一般子窗口会比父窗口小,子窗口请求重绘时,要执行父窗口的绘制函数,如果父窗口没有根据当前的剪裁范围来确定自己的绘制范围,那么尽管有剪裁区限制了不会绘制超出边界,在实际执行过程中,超出剪裁区的绘制行为也可能极大的影响UI的性能。

如何解决这个问题呢?

解决的方法可以有很多,比如在每个窗口的绘制方法都实现只绘制在剪裁区的那部分(实际上实现起来非常麻烦,附加的剪裁区计算也可能成为新的绘制瓶颈);又比如每个窗口都保留背景窗口的内容,当窗口需要刷新时,直接直接把背景内容拿过来在上面画。

第二种方法看起来效率是最高的,但是实际上可能并不高:虽然在绘制自己的内容时速度快了,问题是自己更新以后,还需要同时更新它的上层窗口的缓存,可能导致内存开销大,效率也不高。

在SOUI中,我们采用了第三种方法:给窗口加一个cache属性。

当cache=0时,窗口的绘制和前面提到的流程一样,只是如果窗口比较大,而需要一时半会的区域比较小时,速度慢一点。

如果cache=1,则窗口绘制的内容会被保存到一张缓存位图上,当其它窗口刷新并导致该窗口重绘时,直接从缓存中复制出来就可以了。

假定一个窗口使用一张小图片进行九宫格拉伸绘制出来,绘制整个窗口由于拉伸中的插值等一系列的计算,绘制可能需要消耗大量的CPU时间,而有了缓存以后,只在第一次绘制的时候使用图片绘制方法进行绘制,其它时间都是直接从缓存复制,效率能够极大的提高。

很显然,cache属性在提高渲染效率的同时,也需要开辟一块缓存来保存绘制内容,也就是常见的空间换时间的方法。因此如果绘制本身速度就足够快,那么完全可以不使用缓存(比如给一个窗口填充一个纯色的矩形)。

总结:

cache可以提高绘制速度,但是是以更高的内存占用为代价的,应该只在需要的地方使用(例如顶层背景窗口)。

第十七篇:使用窗口的cache属性加速SOUI的渲染的更多相关文章

  1. 第六十七篇:Vue的计算属性

    好家伙, 1.什么是计算属性? 首先它是一种属性,其次他有计算这个特殊的性质, 它是一个依赖于其他属性的属性,当依赖的属性发生变化的时候就会触发我们计算属性的逻辑 它会对这个属性进行计算, 所以说它是 ...

  2. Python之路【第十七篇】:Django之【进阶篇】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  3. Python之路【第十七篇】:Django【进阶篇】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  4. Python之路【第十七篇】:Django【进阶篇 】

    Python之路[第十七篇]:Django[进阶篇 ]   Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接 ...

  5. 第十六篇:SWindow的布局属性pos2type及offset

    当窗口大小需要根据内容来确定时,使用XML布局可能需要做一些特殊的处理. 例如:不管窗口多大,我需要将该窗口相对于父窗口居中在XML中应该怎么处理? 如果窗口大小是固定的(如, 100 *100),这 ...

  6. 解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译)

    解剖SQLSERVER 第十七篇 使用 OrcaMDF Corruptor 故意损坏数据库(译) http://improve.dk/corrupting-databases-purpose-usin ...

  7. Document对象关于窗口的一些属性

    在网上搜罗的,只为自己查用方便,不做他用 window.screen.availWidth 返回当前屏幕宽度(空白空间) window.screen.availHeight 返回当前屏幕高度(空白空间 ...

  8. 第六篇 ANDROID窗口系统机制之显示机制

    第六篇 ANDROID窗口系统机制之显示机制 ANDROID的显示系统是整个框架中最复杂的系统之一,涉及包括窗口管理服务.VIEW视图系统.SurfaceFlinger本地服务.硬件加速等.窗口管理服 ...

  9. 跟我学SpringCloud | 第十七篇:服务网关Zuul基于Apollo动态路由

    目录 SpringCloud系列教程 | 第十七篇:服务网关Zuul基于Apollo动态路由 Apollo概述 Apollo相比于Spring Cloud Config优势 工程实战 示例代码 Spr ...

随机推荐

  1. 【云计算】Cloudify-基于TOSCA规范的开源云应用编排系统

      .cloudify-manager-blueprints:https://github.com/cloudify-cosmo/cloudify-manager-blueprints/tree/3. ...

  2. ACM/ICPC 之 Prim范例(ZOJ1586-POJ1789(ZOJ2158))

    两道Prim解法范例题型,简单的裸Prim,且两题相较以边为重心的Kruskal解法而言更适合以点为重心扩展的Prim解法. ZOJ1586-QS Network 题意:见Code 题解:直接的MST ...

  3. java入门第一季2

    1. 变量:在java中,我们通过三个元素描述变量:变量类型,变量名以及变量值 注意:java中的标点符号都是英文的 2. 变量名= 首字母+其余部分 字母,+  字母 下划线,  数字 $      ...

  4. Divide and conquer:Subset(POJ 3977)

    子序列 题目大意:给定一串数字序列,要你从中挑一定个数的数字使这些数字和绝对值最小,求出最小组合数 题目的数字最多35个,一看就是要数字枚举了,但是如果直接枚举,复杂度就是O(2^35)了,显然行不通 ...

  5. 【leetcode】Reverse Linked List(easy)

    Reverse a singly linked list. 思路:没啥好说的.秒... ListNode* reverseList(ListNode* head) { ListNode * rList ...

  6. 【leetcode】Substring with Concatenation of All Words (hard) ★

    You are given a string, S, and a list of words, L, that are all of the same length. Find all startin ...

  7. 【mongo】drop不释放磁盘空间

    用drop删除mongo的collection后,其size归零,但是storage仍然是原大小,磁盘空间没有被释放. 要用下面命令释放无用的磁盘空间 mongod -repair

  8. 如何让数据库在每天的某一个时刻自动执行某一个存储过程或者某一个sql语句

    这就要涉及到代理的知识了哦,首先我们要启动代理服务.

  9. 如何给DropDownList在后台代码中添加一个空的选项

    代码如何: ddl_dept.Items.Insert(, new ListItem("---请选择---","")); new ListItem的第一个参数表 ...

  10. 分页Bean终极封装

    package org.guangsoft.vo; import java.util.List; public class Page { private Integer pageNum; privat ...