[轉]真彩色转成高彩色的快速算法


这里我不谈减低色彩深度时,   采用抖动减少误差的方法.   因为本文将着力于找到尽可能快的算法   (虽然最快的方法一定存在,   但我们只能去接近它,   而无法达到,   因为优化是无至尽的,   而且随着   CPU   而变化)实时转化   24bit   (或32bit)   的真彩色位图到16bit(15bit)的高彩色.   

为什么要实时转换颜色深度?   

通常,   2D   游戏中的位图,   无论在外存中按什么颜色深度存放,   加栽后都被转换成了需要的颜色深度.   我们不太注意颜色深度转换说需要的时间.   

但是,   现在不同了.   云风未来的计划中,   最重要的一项是制作一个超级   2D   引擎.   将支持   Voxel   物体和实时光线处理这样的特性,   而且在光线处理中,   32   级的光线亮度级别也远远不够,   所以,   未来的   2D   游戏的发展趋势应该是采用真彩色,   至少是在内部运算时使用.   在某些场合下,   我们可能需要做   15/16bit   高彩色的输出,   所以有必要找到更快的方法实时处理.   

下面,   我们对此做一些探讨,   虽然显卡可以支持   15   或   16   bit   色中的一种,   但这里全部用   16bit   色举例:   

先来看看   C   版本:   

red=(truecolor> > 8)&0xf800; 
green=(truecolor> > 5)&0x7e0; 
blue=(truecolor> > 3)&0x1f; 
hicolor=red|green|blue; 

这样当然是相当慢的,   所以我们还是要借助汇编.   而汇编能极大的优化它:   
lodsd ;RRRRRRRR   GGGGGGGG   BBBBBBBB 
shr   eax,3 ;000RRRRR   RRRGGGGG   GGGBBBBB 
shl   al,2 ;000RRRRR   RRRGGGGG   GBBBBBxx 
shl   ax,3 ;000RRRRR   GGGGGGBBB   BBxxxxx 
dec   esi 
shr   eax,5 ;00000000   RRRRRGGG   GGGBBBBB 
stosw 

是不是精简了很多?   但不幸的是,   虽然看起来很简洁,   但由于大量使用部分寄存器,   对流水线的冲击很大.   代码几乎把流水线的效率减到了最低.   优化方案很多,   我们可以在一次循环里处理两个点,   分别使用   eax   和   ebx,   然后交错那些代码;   又或者将上面代码的后半部分改为查表,   相信都能提高速度.   但是下面我还想提出另一种方案,   采用   MMX   指令级:   
mm7=F800F800F800F800 
mm6=FC00FC00FC00FC00 
------------------------------ 
punpcklbw   mm0,[red+edx]
;mm0=RRRRRRRR   00000000   RRRRRRRR   00000000   RRRRRRRR   00000000   RRRRRRRR   00000000   
punpcklbw   mm1,[green+edx] 
;mm1=GGGGGGGG   00000000   GGGGGGGG   00000000   GGGGGGGG   00000000   GGGGGGGG   00000000   
punpcklbw   mm2,[blue+edx] 
;mm2=BBBBBBBB   00000000   BBBBBBBB   00000000   BBBBBBBB   00000000   BBBBBBBB   00000000   
pand   mm0,mm7 
;mm0=RRRRR000   00000000   RRRRR000   00000000   RRRRR000   00000000   RRRRR000   00000000   
pand   mm1,mm6 
;mm1=GGGGGG00   00000000   GGGGGG00   00000000   GGGGGG00   00000000   GGGGGG00   00000000   
psrlw   mm2,11 
;mm2=00000000   000BBBBB   00000000   000BBBBB   00000000   000BBBBB   00000000   000BBBBB   
psrlw   mm1,5 
;mm1=00000GGG   GGG00000   00000GGG   GGG00000   00000GGG   GGG00000   00000GGG   GGG00000   
por   mm0,mm2 
por   mm0,mm1 
;mm0=RRRRRGGG   GGGBBBBB   RRRRRGGG   GGGBBBBB   RRRRRGGG   GGGBBBBB   RRRRRGGG   GGGBBBBB 
movq   [dis+edx*2],mm0 
add   edx,4 

我们对   MMX   的运用是针对它的并行运算,   直接从   RGB888   格式利用并行处理变成   RGB565   似乎不可能,   但是,   如果我们将   RGB   三个色素分开存放,   就将其变为了可能.   可以同时读入   4   个色素,   并行处理,   然后合并,   这样便在一个循环内处理了   4   个点.   考虑到   CACHE   的效率,   最好不要将   RGB   三块内存分的太开.   我的建议是,   位图的每一行分成三个部分,   即为   Red   段,   Green   段   和   Blue   段.   
上面的方法都是可以继续优化的,   本文旨在启发朋友们的灵感,   找出更好的方法.

你可能感兴趣的:(算法)