Bootstrap

64K色模式下的快速Alpha混合算法(转)

64K色模式下的快速Alpha混合算法(转)[@more@]

  在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 ([email protected]

  ;       (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函数。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/8225414/viewspace-952246/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/8225414/viewspace-952246/

;