在32/64K色模式下,由于每个点的RGB值是放在一个字里,以16位色为例,一般是按RGB或BGR 565存放。传统的软件Alpha混合算法是先将RGB分离出来,分开运算,然后再合成。这造成了16位模式下的alpha混合比24位模式下慢 的现象,但使用16位色真的那么慢吗?我认为如果不使用MMX指令,15/16的比24位的快。因为我们可以使用一个小的技巧来同时计算RGB。而24位颜色,除非使用MMX指令,否则必须分开计算R、G、B。 先设颜色(color)是RGB 565的,那么按二进制看,这个颜色字是这样分布的: RRRRR GGGGGG BBBBB 5位 6位 5位 RGB成分 而386以上CPU都有32位的寄存器,我们只需要将16位RGB变形为: 00000 GGGGGG 00000 RRRRR 000000 BBBBB 5位 6位 5位 5位 6位 5位 变形后的RGB成分 储存在32位寄存器中,(就是把绿色提到前16位里)由于64K色下颜色深度是32级的,所以alpha也只用分32级就能满足需要。那么对上面变形过的双字处理,可以同时算RGB了。(Color1*Alpha+Color2*(32-Alpha))/32能不能简化为(Color1-Color2)*Alpha/32+Color2?我思考过这个问题,以为减法将产生负数,这样再算乘法时有可能出问题,但是经过测试,这样简化似乎又没有问题。毕竟极小的误差是可以忽略的。 最近温习了一下汇编,今天用NASM写了个C可调用的Alpha混合函数(32位模式,我针对DJGPP写的)并进行了Pentium优化(针对双流水线,有错请指出)。大家看看,有BUG,还能优化或有更快的方法也请一定告诉我。顺便提一下,上面提到的化简没有体现到下面的程序中,而且,使用乘法本身是个错误。只是看看吧,如果你想实际运用,请参考Allegro程序库的做法。 ; 对16位的color1与color2进行Alpha混合 ; R=(r1*alpha+r2*(32-alpha))/32 ; G=(g1*alpha+g2*(32-alpha))/32 ; B=(b1*alpha+b2*(32-alpha))/32 ; C 语言调用函数(32 位保护模式)Pentium双流水线优化 ; By Cloud Wu (cloudwu@263.net) ; (http://member.netease.com/~cloudwu) ; ------------------------------------------------------------------------- ; unsigned long alpha (unsigned long c1,unsigned long c2,unsigned long alpha); ; ------------------------------------------------------------------------- ; c1: 颜色1的RGB(565),c2: 颜色2的RGB(565),alpha: Alpha值(0~31) ; NASM 编译通过 [BITS 32] [GLOBAL _alpha] [SECTION .text] _alpha: ; 初始化代码 push ebp ; ebp 压栈 mov ebp,esp ; 保存 esp 到 ebp mov edi,0x7e0f81f ; dx=00000111111000001111100000011111 add esp,8 ; esp 指向参数 c1 pop eax ; 弹出 c1 到 ax pop ebx ; 弹出 c2 到 bx ; 处理颜色 mov cx,ax ; cx=r1..b1 mov dx,bx ; dx=r2..b2 sal eax,16 ; eax=r1g1b1...... sal ebx,16 ; ebx=r2g2b2...... mov ax,cx ; eax=r1g1b1r1g1b1 mov bx,dx ; ebx=r2g2b2r2g2b2 and eax,edi ; eax=..g1..r1..b1 pop esi ; 弹出 alpha mul esi ; eax*=alpha neg esi ; -alpha and ebx,edi ; ebx=..g2..r2..b2 add esi,0x20 ; 32-alpha xchg eax,ebx ; 交换 eax,ebx mul esi ; c2*=(32-alpha) add eax,ebx ; c1*alpha+c2*(32-alpha) mov esp,ebp sar eax,5 ; color=(c1*alpha+c2*(32-alpha))/32 ;还原成 RGB 形式 pop ebp and eax,edi ; color=..g..r..b mov cx,ax ; sar eax,16 ; or ax,cx ; color=rgb (eax) ret 如果建一张256K的表来查表预处理RGB怎样?经过尝试,发现速度不仅没有提高,反而降低了。分析的结论是,256K的表太大了,以至于不能放到缓存(Cache)里,反而没有计算的方法快,毕竟计算的话,每行的代码都很快,而不必和内存打交道。真正加速的方法是什么?借鉴Allegro程序库里的方法,建立32个函数分别计算每个alpha值的情况。这样,alpha值变成固定的,从而可以使用LEA、ADD、SUB、SAL、SAR来替代缓慢的MUL。经过实践,我重写了Allegro程序库里的cblend15.c及cblend16.c,(使用程序库自己的Test.exe,机器配置为Cyrix Gx/120 S3/375 4M)测试数据如下: 原有的混合函数 使用新算法的混合函数 将Blender函数置为空 1402 per sec 1779 per sec 2002 per sec 呵呵,速度提高了一倍不是吗?Allegro库目前的版本已经使用了我写的blender函数。
 【责编:admin】
|