最近许多人写了关于图形缩放的文章,哈哈Windows下到是好完全可以依靠Blt。但是我发现可以写出一个与Blt差不多的缩放程序,甚至快于Blt所以也来凑个热闹。图形缩放就是在原来的图形中均匀地插入或者删除列或者行构成目标图形。我们的目的就是通过列举常用的缩放方法然后进行优化最终写出与Blt旗鼓相当的缩放程序。 插值法都是以整数模拟小数的,比如从长度是N1放大到长度是N2可以用下面两个循环完成:(注:本文是提供初学者的入门文章,不当之处还请指点出) for (int p1=0,p2=0,count=0;p2<N2;p2++) for (dest_pixel[p2]=src_pixel[p1], count=count+N1;count>=N2;p1++) count-=N2; 算法的关键之处就在于用count来判断插值情况,下面是一段完整的缩放图形程序,算法和上面的相同:
在我写程序的机器上面(P-450, Nvida TNT2 8MB显卡)在640x480x16bit模式中做一次内存到现存的全屏缩放需要时间是0.034423秒,一秒中是29.050279fps。而此时用Blt缩放是0.005179秒193.081426fps!差距实在太大了,好了开始提速了: 首先观察程序中每写一行就要进行一次缩放计算,那么图块有多高就要进行多少次重复性工作,这正是这种算法致命的弱点,优化的关键是把缩放部分独立出来,一次性生成两个查找表tablex[],tabley[]然后每次用查表替代计算,目标图形中的第n行象素对应源图形中的地tabley[n]行,列也是按照同样的方法计算的,这样一来速度瞬间提到了150fps(Blt是193fps)!我们可以用上面的算法来生成这两lookup table,但是下面我提供了Bresenham插值算法,比上面的要快点:
那么一开始的缩放程序就可以写成: zoom(0,0,N1,N2,tablex); for (i=0;i<N2;i++) dest_pixel[i]=src_pixel[tablex[i]]; 是不是很简单,令人激动。现在已经达到了150fps了,那么最后的工作应该交给汇编来完成了。下面是我的缩放程序,汇编部分经过奔腾优化,不过技术有限,不当处还请高手门一定指出:
程序运行的结果可以下载我写的DEMO看看,运行的结果会自动保存在logfile.txt之中,下面的表格是几种缩放方法的时间对比,有时因为图片大小不一样,缩放大小不一样,会造成Blt快于上面的算法,或者上面的算法快于Blt,所以可以认为近似相等吧。其实大多数情况是上面的算法快于Blt的,由于我的显卡支持硬件的缩放,所以内存到现存的操作都会比内存到内存的要快,而且Blt会自动识别硬件支持,在我的TNT2上面硬件还自动做了二次线性插值,使得效果非常的好,消除了放大是的马赛克和缩小产生的闪烁现象,速度虽然略低但效果是最重要的,因此建议在内存到显存或显存到显存时的缩放用Blt而内存到内存的缩放用此算法。对于经常需要缩放的图形可以提前计算出几种常用尺寸的查找表增快速度,也可以提前计算出表面中每行开始象素的地址来代替乘法,也有人提醒用定点数来代替差表,那样可以用一条加法指令还有位移指令代替一次内存I/O也是可行的,总之熟练运用定点数,查找表于汇编是编写图形程序必备的手段。我也只是还在学习,所以有错误或者优化的地方还请各位高手不惜赐教一二:skywindt@yeah.net
内存到显存 |
DDSURFACE的BLT |
193.081426fps |
0.005179s |
原始算法 |
29.050279fps |
0.034423s |
建立缩放表和行查找表 |
150fps左右 |
- |
作后的汇编优化 |
221.108884fps |
0.004523s | |
内存到内存 |
DDSURFACE的BLT |
159.891599fps |
0.006254s |
原始算法 |
- |
- |
建立缩放表和行查找表 |
- |
- |
作后的汇编优化 |
172.958133fps |
0.005782s | |
你对本文有何看法?
|