分享
 
 
 

利用MMX优化64K色Alpha混合算法

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

开始使用MMX CPU后,一直在考虑如何用MMX技术加快Alpha混合的操作,尤其是针对目前常用的高彩模式。而早先在国外一个有关游戏编程的邮件列表讨论的结果是MMX不利于对16位色进行Alpha混合操作。让我们先来看看MMX技术相对于普通指令集的更新,来了解一下这个论点的立论。

MMX技术的优势在于,它的寄存器是64位的,而提供了分组模式,可以将寄存器内的数据按8个字节,或4个字,或2个双字同时进行同一操作,方便了大数据量的数据处理。可以成组数据同时作比较操作,这为透明色点的批量判断带来好处。MMX的CPU拥有8个MMX寄存器,在一定程度上缓解了80x86CPU寄存器数量不足的缺陷。

但是它也有诸多不足,比如算术指令不能对四字节字操作。指令结构都不影响标志位。不能对常数立即寻址。MMX系统指令集的指令相当贫乏(连NOT操作也不能直接实现)。当颜色深度是24/32位时,RGB都占8位,这样可以巧妙的利用MMX里的分组乘法指令达到做Alpha混合运算的效果(MMX的乘法相关指令只有对字操作的PMULHW/PMULLW两条,分别是成组数据的乘后取高位和取低位)本文旨在探讨16位色的快速Alpha混合运算,所以此处略去不提。而16位色,红绿蓝各占5或6位,难以被分组分开,所以不利于运用MMX的这些特性。当然另外的解决方法是采用aRGB 4444的结构,其中4位是Alpha通道,每个色素占半个字节,再采用类似的方法。

看过云风去年提出的《16位Alpha混合优化算法》的朋友,应该会联想到这个算法向MMX的引申,好了,也许你已经明白了大概,本文的理论基本点就在此,唯一的问题是,我们需要面对的是MMX指令集的种种缺陷,这些在实际的程序设计中会逐步的体现出来,下面,云风将在介绍算法的同时,附带的提出一些运用MMX的技巧。先来看看上次的算法有无可进一步优化的可能:

16位下Alpha混合的关键在于如何将RGB分离,让随后的乘法结果不至于相互干扰。我提出的是将16位的“rrrrrggggggbbbbb”扩展到32位变形成“00000gggggg00000rrrrr000000bbbbb”,即将中间的绿色提到高16位,而使色素间隔都有5到6位,而对于5位的颜色,超过5位的Alpha级别是没有意义的,所以只要设定Alpha值在0~31间,同时算这3个色素的乘法是不会因为进位造成干扰的。而这里需要多操作一次移位扩展16位到32位,然后需要一次与操作, 将中间间隔位置0,而且结果需要同样复杂的逆操作从32位还原到16位。

改进的思路是直接将两个点交错分离,即“rrrrrggggggbbbbbRRRRRGGGGGGBBBBB”分离成“rrrrr000000bbbbb00000GGGGGG00000”及“00000gggggg00000RRRRR000000BBBBB”两部分,前一部分右移5位后变成“00000rrrrr000000bbbbb00000GGGGGG”,两个数字就都可以同时运算3个色素,其结果后一组右移5位后可以与前一组合并。这样就省去了好几次移位操作,并且数据可以4字节读入,和四字节写,粗看真的效率很高。但是在传统的80x86上却有两点制约了它的运用:

CPU 的寄存器不够用,这个方法光保存数据就需要4个32位的寄存器,虽然EAX、EBX、ECX、EDX刚够用,但是这就使得Alpha混合函数不能直接写在Blit操作里面。必须单写个子程序调用。(不过也值得写尝试一下,不是吗?如果有朋友写好了,希望能给我拜读一下,我在风魂游戏程序库里留了接口,并在注释里提到了函数的具体写法。)

2D游戏中,一般都是利用Alpha混合绘制精灵而不是规则的矩形位图,所以这里面还存在着透明色的判断,如果是双点处理,这一步不易实现。(不过也不是没有好的方法,就是代码的长度就长而复杂了)

而MMX却提供了8个寄存器,同时有分组比较的指令,正好弥补了这两点不足,而且利用寄存器有64位的优势可以同时运算4个点。所以我们暂且只用MMX来实现新的想法。(如果你对这个方法用在传统指令集上有兴趣,希望同时操作2个点进行Alpha混合,并写出实际的代码,请和我联系,我非常希望看到风魂的非MMX Alpha混合版本能够进一步优化)

用MMX来做这项工作,原理差不多(相当简单不是?),也是读入源点和目标点后分离成4个数据放在4个寄存器中。两对间进行Alpha混合,(这样6个色素)最后就两对数据混合的结果合并。不过从现在开始我们就要面对MMX 8个寄存器不够用的困境了。MMX指令不能和64位立即常数一起使用,所以在进行分裂操作的时候用到的掩码要常驻在寄存器内。

如果寄存器足够多的话,可以连掩码的反值也放一个,可惜现在不能这么浪费。处理透明色问题方面,可以先将点和透明色比较得到一个掩码,我们再将混合后的点,及原来的目标图上的点(这个点应当保留一个备份,哎,又去了一个寄存器)分别与掩码逻辑运算合并得到最终的数据写入目标图。这里,需要大量运用的NOT操作,Intel竟然没有在MMX指令集中提供。我们只好用PANDN(取反再与操作)间接完成。(例:可以先用PCMPEQW mm0,mm0(自己和自己比较当然全相等了)生成常数FFFFFFFFFFFFFFFF,用PANDN mm1,mm0就可以将mm1取反。)这里,不再可以利用MMX的分组乘法,(MMX不能对32位数进行乘法操作)所以我们应该用移位和加减法来实现。这样,如果有几级Alpha值,就应该写几个混合函数。最后建立一个函数指针数组,将每级Alpha混合函数依次放入数组。我们在调用时就可以根据需要的Alpha值来调用相应的函数了。

在风魂0.07里,Alpha混合又一次修改了算法,(0.06使用的上述算法,0.07 则没有)这里要感谢网友T&P的新思路。针对分级数比较少的Alpha混合,比如8级,可以用更简单的方法。大家可以注意到,50%的 Alpha时,R=(r1+r2)/2,也可以近似的等于r1/2+r2/2。那么RGB可以方便的同时运算。只需要在移位后做一次简单的与操作即可(0RRRRRGGGGGGBBBB & 011110111101111 = 0RRRR0GGGGG0BBBB)然后,将两个移位后的数据相加就完成了Alpha=50%的混合。这个方法避免了切分和还原数据,所以速度更快。风魂的早期版本,对50%的Alpha度就做了此种特殊处理。但是,它是有误差的,误差在于移位造成的每色素上1/32或1/64的偏差。

下一步我们可以将50%的Alpha值推广到25%、12.5%甚至更小。现在来看一下完成R1*25%+R2*75%,它等于R2+R1*25%-R2*25% = R2+R1/4+R2/4。这里除4的操作和除2原理是一样的即:(RRRRRGGGGGGBBBBB2)&0011100111100111。依次类推,X*37.5%+Y*62.5% = (X+Y)/2+Y/8-X/8等等。我们就只需要利用移位和加减法就可以同时完成N个色素的混合了。

再来看看这个方法的缺陷。首先是误差问题,每一组移位取与都会造成最大为1/32的误差,而多次运算有可能使误差累计,所以alpha级别不能分的太多。而且alpha级别分的太细后,使得运算步骤变的很多,不切分直接运算的优势有可能损失掉。而且更致命的一点是,如果想用MMX加速,那么通常AND运算用的掩码应该放在寄存器中(如果放在内存,而MMX不能立即寻址,间接寻址取内存可能不能命中CACHE速度变慢,大规模的混合运算速度损失太多),MMX的寄存器却只有8个。那么多个掩码会使明显的感觉寄存器不够用,但这不失为一种好的方法。风魂库0.07中新的alpha精灵,这一步的算法更改带来了10%左右的速度提升,而画质的损失却几乎没有体现。

最后对关于带Alpha通道的位图的做一点探讨,这里每一个点将带有不同的Alpha值,我们应该合理的协调位图的结构。将Alpha值和颜色信息放在一起是不合算的。这样不利于高速处理。我们可以将所有点的Alpha值提出来放在一起,对于16位的颜色,合理的Alpha级别应该在16级以下。这样可以每一个字节存放两个Alpha值。用一个寄存器作为指向Alpha值区域的指针,读入对应点的Alpha值,调用相应的混合函数运算。但是,这种位图每个点都有可能是不同的alpha值,如此就不能多点同时运算,云风找到了另外的加速方法,要知详情,且看下文分解。

后记

本文提出的方法,都被云风实践证明可行,请参阅风魂游戏程序库的源代码。你会发现速度相当的快。测试表明,MMX下带Alpha混合的位图操作,仅仅比普通的检查透明色的位图操作慢20%。比不用MMX逐点做Alpha混合快2.7倍。如果采用RLE压缩掉透明色点,去掉对透明色的特殊处理,速度还会有很大的提高。(达到DirectDraw里内存表面(Surface)间关键色检查的位块传送(blit)操作的速度)这个算法的意义在于,16位色下,软件Alpha混合的速度已经足够快,这使游戏中大量运用光影效果不再有速度上的顾虑。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有