图形图像处理-之-高质量的快速的图像缩放 补充 使用SSE2优化

转自 http://blog.csdn.net/housisong/article/details/6318890

 图形图像处理-之-高质量的快速的图像缩放 补充 使用SSE2优化
                           
[email protected]    2011.04.12

 

tag: 图像缩放,速度优化,线性插值,三次卷积插值,SSE2,scale,bilinear,bicubic,StretchBlt

 

摘要: 
  本文章对线性插值和三次卷积插值(bicubic)的实现做了一些新的优化尝试;
使用了SSE2的128bit寄存器及相关指令;并预先建立SSE2用到的缩放系数表; 
实现的结果在我的i7电脑上比以前的版本分别快出145%和75%!
线性插值的速度是StretchBlt的13倍!

 

正文: 
(请先看看我的blog里<高质量的快速的图像缩放>的前3篇文章!)
支持SSE2指令集的CPU越来越多,CPU的SSE2实现性能也好了很多(以前不比MMX好多少),
而且软件在64位模式的时候不再支持MMX,所以尝试了SSE2的缩放优化,效果不错!

 

速度测试说明: 
  只测试内存数据到内存数据的缩放
  测试图片都是800*600缩放到1024*768,单线程;fps表示每秒钟的帧数,值越大表示函数越快.

 

速度测试对比: (CPU:i7 920 内存:DDR3 1333 3通道)

 

(windows)
StretchBlt  近邻取样           869.09 fps
StretchBlt  线性插值            44.46 fps //SetStretchBltMode(dc,4);?

 

PicZoom0:                       95.69 fps
PicZoom1:                      158.35 fps
PicZoom2:                      332.78 fps
PicZoom3:                     1172.79 fps
PicZoom3_float:                874.13 fps
PicZoom3_Table:               1158.30 fps
PicZoom3_SSE:                 1908.40 fps
PicZoom_Bilinear0:              28.80 fps
PicZoom_Bilinear1:              56.09 fps
PicZoom_Bilinear2:              97.09 fps
PicZoom_Bilinear_Common:       119.83 fps
PicZoom_Bilinear_MMX:          180.12 fps
PicZoom_Bilinear_MMX_Ex:       237.34 fps
PicZoom_ftBilinear_Common:     118.67 fps
PicZoom_ftBilinear_MMX:        213.68 fps
PicZoom_ThreeOrder0:             6.11 fps
PicZoom_ThreeOrder_Common:      25.38 fps
PicZoom_ThreeOrder_MMX:         52.32 fps

 

(SSE2的实现)
PicZoom_ftBilinearTable_SSE2:  588.24 fps
PicZoom_ThreeOrderTable_SSE2:   93.24 fps


 

 

PicZoom_ftBilinearTable_SSE2实现代码如下:


  1.     typedef UInt64 TMMXData64;  
  2.     //ftBilinearTable_SSE2(out [edi+ebx*4]; xmm5=v,xmm6=vr,xmm7=0,[ebp]=(u,ur),[edx]=srx_x,esi=PSrcLineColor,ecx=PSrcLineColorNext)  
  3.     //void __declspec(naked) ftBilinearTable_SSE2(){  
  4.     #define  ftBilinearTable_SSE2()                     /  
  5.         asm mov         eax,[edx+ebx]                   /  
  6.         asm movq        xmm0,qword ptr[esi+eax*4]       /  
  7.         asm movq        xmm1,qword ptr[ecx+eax*4]       /  
  8.         asm punpcklbw   xmm0,xmm7                       /  
  9.         asm punpcklbw   xmm1,xmm7                       /  
  10.         asm pmullw      xmm0,mm5                        /  
  11.         asm pmullw      xmm1,mm6                        /  
  12.         asm paddw       xmm0,xmm1                       /  
  13.         asm pmulhw      xmm0,xmmword ptr [ebp+ebx*4] /  
  14.         asm movdqa      xmm1,xmm0                       /  
  15.         asm punpckhqdq  xmm0,xmm0                       /  
  16.         asm paddw       xmm0,xmm1                       /  
  17.         asm packuswb    xmm0,xmm7                       /  
  18.         asm movd  dword ptr  [edi+ebx],xmm0              
  19.         //ret //for  __declspec(naked)  
  20.         //}  
  21.     //}  
  22.     //void __declspec(naked) ftBilinearTable_SSE2_expand2(){  
  23.     #define  ftBilinearTable_SSE2_expand2()             /  
  24.         asm mov         eax,[edx+ebx]                   /  
  25.         asm movq        xmm0,qword ptr[esi+eax*4]       /  
  26.         asm movq        xmm1,qword ptr[ecx+eax*4]       /  
  27.         asm mov         eax,[edx+ebx+4]                 /  
  28.         asm movq        xmm2,qword ptr[esi+eax*4]       /  
  29.         asm movq        xmm3,qword ptr[ecx+eax*4]       /  
  30.         asm punpcklbw   xmm0,xmm7                       /  
  31.         asm punpcklbw   xmm1,xmm7                       /  
  32.         asm punpcklbw   xmm2,xmm7                       /  
  33.         asm punpcklbw   xmm3,xmm7                       /  
  34.         asm pmullw      xmm0,mm5                        /  
  35.         asm pmullw      xmm1,mm6                        /  
  36.         asm pmullw      xmm2,mm5                        /  
  37.         asm pmullw      xmm3,mm6                        /  
  38.         asm paddw       xmm0,xmm1                       /  
  39.         asm paddw       xmm2,xmm3                       /  
  40.         asm pmulhw      xmm0,xmmword ptr [ebp+ebx*4] /  
  41.         asm pmulhw      xmm2,xmmword ptr [ebp+ebx*4+16] /  
  42.         asm movdqa      xmm1,xmm0                       /  
  43.         asm punpcklqdq  xmm0,xmm2                       /  
  44.         asm punpckhqdq  xmm1,xmm2                       /  
  45.         asm paddw       xmm0,xmm1                       /  
  46.         asm packuswb    xmm0,xmm7                       /  
  47.         asm movq  qword ptr  [edi+ebx],xmm0             /  
  48.         //ret //for  __declspec(naked)  
  49.         //}  
  50.     //}  
  51.      
  52. void PicZoom_ftBilinearTable_SSE2(const TPixels32Ref& Dst,const TPixels32Ref& Src)  
  53. {  
  54.     if (  (0==Dst.width)||(0==Dst.height)  
  55.         ||(2>Src.width)||(2>Src.height)) return;  
  56.     long xrIntFloat_16=((Src.width-1)<<16)/Dst.width;  
  57.     long yrIntFloat_16=((Src.height-1)<<16)/Dst.height;  
  58.     long dst_width=Dst.width;  
  59.     UInt8* _bufMem=new UInt8[(dst_width*2*sizeof(TMMXData64)+15)+dst_width*sizeof(Int32)];  
  60.     TMMXData64* uList=(TMMXData64*)((((ptrdiff_t)_bufMem)+15)>>4<<4); //16byte对齐  
  61.     Int32* xList=(Int32*)(uList+dst_width*2);  
  62.     {//init u table  
  63.         long srcx_16=0;  
  64.         for (long x=0;x<dst_width*2;x+=2){  
  65.             xList[x>>1]=(srcx_16>>16);  
  66.             unsigned long u=(srcx_16>>8)&0xFF;  
  67.             unsigned long ur=(256-u)<<1;  
  68.             u=u<<1;  
  69.             uList[x+0]=(ur|(ur<<16));  
  70.             uList[x+0]|=uList[x+0]<<32;  
  71.             uList[x+1]=u|(u<<16);  
  72.             uList[x+1]|=uList[x+1]<<32;  
  73.             srcx_16+=xrIntFloat_16;  
  74.         }  
  75.     }  
  76.     Color32* pDstLine=Dst.pdata;  
  77.     long srcy_16=0;  
  78.     asm pxor  xmm7,xmm7 //xmm7=0  
  79.     for (long y=0;y<Dst.height;++y){  
  80.         unsigned long v=(srcy_16>>8) & 0xFF;  
  81.         unsigned long vr=(256-v)>>1;  
  82.         v>>=1;  
  83.         Color32* PSrcLineColor= (Color32*)((UInt8*)(Src.pdata)+Src.byte_width*(srcy_16>>16)) ;  
  84.         Color32* PSrcLineColorNext= (Color32*)((UInt8*)(PSrcLineColor)+Src.byte_width) ;  
  85.         asm{  
  86.               movd        xmm5,vr  
  87.               movd        xmm6,v  
  88.               punpcklwd   xmm5,xmm5  
  89.               punpcklwd   xmm6,xmm6  
  90.               punpckldq   xmm5,xmm5  
  91.               punpckldq   xmm6,xmm6  
  92.               punpcklqdq  xmm5,xmm5  
  93.               punpcklqdq  xmm6,xmm6  
  94.              
  95.               mov       esi,PSrcLineColor  
  96.               mov       ecx,PSrcLineColorNext  
  97.               mov       edx,xList //x  
  98.               mov       ebx,dst_width  
  99.               mov       edi,pDstLine  
  100.               push      ebp  
  101.               mov       ebp,uList  
  102.               push      ebx  
  103.                
  104.               and       ebx,(not 1)  
  105.               test      ebx,ebx  
  106.               jle     end_loop2  
  107.   
  108.               lea       ebx,[ebx*4]  
  109.               lea       edi,[edi+ebx]  
  110.               lea       edx,[edx+ebx]  
  111.               lea       ebp,[ebp+ebx*4]  
  112.               neg       ebx  
  113.         loop2_start:  
  114.               //call ftBilinearTable_SSE2_expand2  
  115.               ftBilinearTable_SSE2_expand2()  
  116.               add       ebx,8  
  117.               jnz       loop2_start  
  118.         end_loop2:  
  119.             pop    ebx  
  120.             and    ebx,1   
  121.             test   ebx,ebx  
  122.             jle    end_write  
  123.               lea       ebx,[ebx*4]  
  124.               lea       edi,[edi+ebx]  
  125.               lea       edx,[edx+ebx]  
  126.               lea       ebp,[ebp+ebx*4]  
  127.               neg       ebx  
  128.         loop1_start:  
  129.               //call ftBilinearTable_SSE2  
  130.               ftBilinearTable_SSE2()  
  131.               add       ebx,4  
  132.               jnz       loop1_start  
  133.         end_write:  
  134.               pop       ebp  
  135.         }  
  136.         srcy_16+=yrIntFloat_16;  
  137.         ((UInt8*&)pDstLine)+=Dst.byte_width;  
  138.     }  
  139.     delete []_bufMem;  
  140. }  
 


 

PicZoom_ThreeOrderTable_SSE2实现代码如下:

  1.     static TMMXData64 SinXDivX_Table64_MMX[(2<<8)+1];  
  2.     class _CAutoInti_SinXDivX_Table64_MMX {  
  3.     private:  
  4.         void _Inti_SinXDivX_Table64_MMX()  
  5.         {  
  6.             for (long i=0;i<=(2<<8);++i)  
  7.             {  
  8.                 unsigned short t=(unsigned short)(0.5+(1<<14)*SinXDivX(i*(1.0/(256))));  
  9.                 unsigned long tl=t|(((unsigned long)t)<<16);  
  10.                 TMMXData64 tll=tl|(((TMMXData64)tl)<<32);  
  11.                 SinXDivX_Table64_MMX[i]=tll;  
  12.             }  
  13.         };  
  14.     public:  
  15.         _CAutoInti_SinXDivX_Table64_MMX() { _Inti_SinXDivX_Table64_MMX(); }  
  16.     };  
  17.     static _CAutoInti_SinXDivX_Table64_MMX __tmp_CAutoInti_SinXDivX_Table64_MMX;  
  18.     //void __declspec(naked)  _private_ThreeOrderTable_Fast_SSE2_2(){  
  19.     #define  _private_ThreeOrderTable_Fast_SSE2_2() /  
  20.         asm movq        xmm0,qword ptr [eax]        /  
  21.         asm movq        xmm1,qword ptr [eax+8]      /  
  22.         asm movq        xmm2,qword ptr [eax+edx] /  
  23.         asm movq        xmm3,qword ptr [eax+edx+8] /  
  24.         asm punpcklbw   xmm0,xmm7     /  
  25.         asm punpcklbw   xmm1,xmm7     /  
  26.         asm punpcklbw   xmm2,xmm7     /  
  27.         asm punpcklbw   xmm3,xmm7     /  
  28.         asm psllw       xmm0,7      /  
  29.         asm psllw       xmm1,7      /  
  30.         asm psllw       xmm2,7      /  
  31.         asm psllw       xmm3,7      /  
  32.         asm pmulhw      xmm0,xmmword ptr [ecx]  /  
  33.         asm pmulhw      xmm1,xmmword ptr [ecx+16] /  
  34.         asm pmulhw      xmm2,xmmword ptr [ecx]  /  
  35.         asm pmulhw      xmm3,xmmword ptr [ecx+16] /  
  36.         asm paddsw      xmm0,xmm1     /  
  37.         asm paddsw      xmm2,xmm3     /  
  38.         asm pmulhw      xmm0,xmmword ptr [ebx]  /  
  39.         asm pmulhw      xmm2,xmmword ptr [ebx+16] /  
  40.         asm paddsw      xmm0,xmm2     /  
  41.         //asm ret //for __declspec(naked)  
  42.     //}  
  43.     must_inline UInt32 ThreeOrderTable_Fast_SSE2(const Color32* pixel,long byte_width,const TMMXData64* v4,const TMMXData64* u4){  
  44.         asm mov     eax,pixel  
  45.         asm mov     edx,byte_width  
  46.         asm mov     ebx,v4  
  47.         asm mov     ecx,u4  
  48.         //asm call _private_ThreeOrderTable_Fast_SSE2_2  
  49.         _private_ThreeOrderTable_Fast_SSE2_2();  
  50.         asm movdqa  xmm6,xmm0  
  51.         asm lea     eax,[eax+edx*2]  //+pic.byte_width  
  52.         asm lea     ebx,[ebx+32]  
  53.         //asm call _private_ThreeOrderTable_Fast_SSE2_2  
  54.         _private_ThreeOrderTable_Fast_SSE2_2();  
  55.         asm paddsw      xmm6,xmm0  
  56.         asm movdqa      xmm5,xmm6  
  57.         asm psrldq      xmm6,8   //srl 8*8 bit!  
  58.         asm paddsw      xmm5,xmm6  
  59.         asm psraw       xmm5,3  
  60.         asm packuswb    xmm5,xmm7  
  61.         asm movd        eax,xmm5  
  62.     }  
  63.     must_inline long getSizeBorder(long x,long maxx){  
  64.   if (x<=0)  
  65.    return 0;  
  66.   else if (x>=maxx)  
  67.    return maxx;  
  68.   else  
  69.    return x;  
  70.     }  
  71.     must_inline UInt32 ThreeOrderTable_Border_SSE2(const TPixels32Ref& pic,const long x0_sub1,const long y0_sub1,const TMMXData64* v4,const TMMXData64* u4){  
  72.         Color32 pixel[16];  
  73.         long height_sub_1=pic.height-1;  
  74.         long width_sub_1=pic.width-1;  
  75.         Color32* pbuf=pixel;  
  76.         for (long i=0;i<4;++i,pbuf+=4){  
  77.             long y=getSizeBorder(y0_sub1+i,height_sub_1);  
  78.             Color32* pLine=pic.getLinePixels(y);  
  79.             pbuf[0]=pLine[getSizeBorder(x0_sub1+0,width_sub_1)];  
  80.             pbuf[1]=pLine[getSizeBorder(x0_sub1+1,width_sub_1)];  
  81.             pbuf[2]=pLine[getSizeBorder(x0_sub1+2,width_sub_1)];  
  82.             pbuf[3]=pLine[getSizeBorder(x0_sub1+3,width_sub_1)];  
  83.         }  
  84.         return ThreeOrderTable_Fast_SSE2(pixel,4*sizeof(Color32),v4,u4);  
  85.     }  
  86. void PicZoom_ThreeOrderTable_SSE2(const TPixels32Ref& Dst,const TPixels32Ref& Src)  
  87. {  
  88.     if (  (0==Dst.width)||(0==Dst.height)  
  89.         ||(0==Src.width)||(0==Src.height)) return;  
  90.     long dst_width=Dst.width;  
  91.     long dst_height=Dst.height;  
  92.     long xrIntFloat_16=((Src.width)<<16)/dst_width+1;  
  93.     long yrIntFloat_16=((Src.height)<<16)/dst_height+1;  
  94.     const long csDErrorX=-(1<<15)+(xrIntFloat_16>>1);  
  95.     const long csDErrorY=-(1<<15)+(yrIntFloat_16>>1);  
  96.     //计算出需要特殊处理的边界  
  97.     long border_y0=((1<<16)-csDErrorY)/yrIntFloat_16+1;//y0+y*yr>=1; y0=csDErrorY => y>=(1-csDErrorY)/yr  
  98.     if (border_y0>=dst_height) border_y0=dst_height;  
  99.     long border_x0=((1<<16)-csDErrorX)/xrIntFloat_16+1;  
  100.     if (border_x0>=dst_width ) border_x0=dst_width;  
  101.     long border_y1=(((Src.height-3)<<16)-csDErrorY)/yrIntFloat_16+1; //y0+y*yr<=(height-3) => y<=(height-3-csDErrorY)/yr  
  102.     if (border_y1<border_y0) border_y1=border_y0;  
  103.     long border_x1=(((Src.width-3)<<16)-csDErrorX)/xrIntFloat_16+1;;  
  104.     if (border_x1<border_x0) border_x1=border_x0;  
  105.     UInt8* _bufMem=new UInt8[(dst_width*4*sizeof(TMMXData64)+15)+dst_width*sizeof(Int32)];  
  106.     TMMXData64* uList=(TMMXData64*)((((ptrdiff_t)_bufMem)+15)>>4<<4); //16byte对齐  
  107.     Int32* xList=(Int32*)(uList+dst_width*4);  
  108.     {//init u table  
  109.         long srcx_16=csDErrorX;  
  110.         for (long x=0;x<dst_width*4;x+=4){  
  111.             xList[x>>2]=(srcx_16>>16)-1;  
  112.             long u=(srcx_16>>8)&0xFF;  
  113.             uList[x+0]=SinXDivX_Table64_MMX[256+u];  
  114.             uList[x+1]=SinXDivX_Table64_MMX[u];  
  115.             uList[x+2]=SinXDivX_Table64_MMX[256-u];  
  116.             uList[x+3]=SinXDivX_Table64_MMX[512-u];  
  117.             srcx_16+=xrIntFloat_16;  
  118.         }  
  119.     }  
  120.     TMMXData64 _v4[8+2];  
  121.     TMMXData64* v4=(&_v4[0]); v4=(TMMXData64*)( (((ptrdiff_t)v4)+15)>>4<<4);  
  122.     asm pxor    xmm7,xmm7  
  123.     Color32* pDstLine=Dst.pdata;  
  124.     long srcy_16=csDErrorY;  
  125.     for (long y=0;y<dst_height;++y){  
  126.         //v table  
  127.         const long srcy_sub1=(srcy_16>>16)-1;  
  128.         const long v=(srcy_16>>8)&0xFF;  
  129.         v4[0]=SinXDivX_Table64_MMX[256+v];  
  130.         v4[1]=v4[0];  
  131.         v4[2]=SinXDivX_Table64_MMX[v];  
  132.         v4[3]=v4[2];  
  133.         v4[4]=SinXDivX_Table64_MMX[256-v];  
  134.         v4[5]=v4[4];  
  135.         v4[6]=SinXDivX_Table64_MMX[512-v];  
  136.         v4[7]=v4[6];  
  137.         if ((y<border_y0)||(y>=border_y1)){  
  138.             for (long x=0;x<dst_width;++x)  
  139.                 pDstLine[x].argb=ThreeOrderTable_Border_SSE2(Src,xList[x],srcy_sub1,v4,&uList[x*4]); //border  
  140.         }else{  
  141.             for (long x=0;x<border_x0;++x)  
  142.                 pDstLine[x].argb=ThreeOrderTable_Border_SSE2(Src,xList[x],srcy_sub1,v4,&uList[x*4]);//border  
  143.             const Color32* pixelLine=Src.getLinePixels(srcy_sub1);  
  144.             long byte_width=Src.byte_width;  
  145.             for (long x=border_x0;x<border_x1;++x)  
  146.                 pDstLine[x].argb=ThreeOrderTable_Fast_SSE2(&pixelLine[xList[x]],byte_width,v4,&uList[x*4]);//fast MMX !  
  147.             for (long x=border_x1;x<dst_width;++x)  
  148.                 pDstLine[x].argb=ThreeOrderTable_Border_SSE2(Src,xList[x],srcy_sub1,v4,&uList[x*4]);//border  
  149.         }  
  150.         srcy_16+=yrIntFloat_16;  
  151.         ((UInt8*&)pDstLine)+=Dst.byte_width;  
  152.     }  
  153.     delete []_bufMem;  
  154. }  


你可能感兴趣的:(优化,table,border,图形,DST,图像处理)