图形图像处理-之-彩色转化到灰度的速度优化

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

               图形图像处理-之-彩色转化到灰度的速度优化
                   HouSisong@GMail.com  2009.02.08

tag:灰度算法,速度优化,定点数优化,MMX,SSE,SSE2,CPU缓存优化

摘要:
  彩色转化到灰度的速度优化文章包括图形图像处理简单Demo框架和灰度转换的实
现及其速度优化,并演示其使用SIMD指令集的优化;
   本篇文章将第一次提供完整的可以编译的图像处理完整项目代码;
   (以后会用这个框架逐步改写以前的图形图像处理文章)

正文:  
  为了便于讨论,这里只处理32bit的ARGB颜色;代码使用C++;使用的编译器为vc2008;
(经过测试代码也可以在DevC++和xcode下编译通过) 测试使用的CPU为AMD64x2 4200+(2.33G);

速度测试说明:
  只测试内存数据到内存数据的ARGB32颜色的灰度转化;
  测试图片是800*600; fps表示每秒钟的帧数,值越大表示函数越快;

A: 图形图像处理简单Demo框架
   
  我以前写的图形图像处理方面的blog文章都没有完整的可以编译运行的代码,
而仅仅列出了关键的核心代码;经常有网友看了我的文章,但因为不能实际运行看看,
从而对代码的理解不深,也不能把代码移植到自己的项目中使用; 所以决定为我的图形
图像处理系列blog文章建立一个简单的小型的框架;我把它命名为hGraphic32,
它会尽量的小,演示为主,仅支持ARGB32颜色,能够加载和保存bmp图片文件,能够在
多个编译器和平台下编译和运行;
   现在就下载完整项目源代码吧:  完整项目源代码 


  <hGraphic32>文件夹里的文件说明:
    "hColor32.h"  : 里面定义了32bitARGB颜色类型Color32,它占用4字节,代表一个颜色;
        TPixels32Ref是图像数据区的描述信息,可以把它理解为一个"指针",指向了Color32构成的像素区;
        IPixels32Buf是图像数据区接口,用于描述一个图像的缓冲区;
    "hPixels32.h" : 里面定义了TPixels32类,它实现了IPixels32Buf接口,用于申请和管理一块内存像素;
    "hStream.h"   : 里面定义了IInputStream输入流接口;
        IBufInputStream数据区输入流接口,继承自IInputStream;
        TFileInputStream文件输入流类,它实现了IBufInputStream接口;
        IOutputStream输出流接口;
        TFileOutputStream文件输出流类,它实现了IOutputStream接口;
     "hBmpFile.h" : 里面定义了TBmpFile类,它负责加载bmp和保存bmp;
     "hGraphic32.h" 文件include了上面的*.h头文件,所以使用的时候,只要#include "hGraphic32.h"就可以了

B: 灰度转化项目
  所有的转换和测试代码都在"ColorToGray/ColorToGray.cpp"文件中(带有main函数的命令行程序);
  "ColorToGray/win_vc/ColorToGray.sln"是windows系统下的vc2008项目文件(测试的时请设定调试运行目录为"..");
  "ColorToGray/win_DevC++/ColorToGray.dev"是windows系统下的DevC++项目文件;
  "ColorToGray/macosx_xcode/ColorToGray.xcodeproj"是macosx系统下的xcode项目文件;
  你也可以自己建立项目,包含ColorToGray.cpp文件和<hGraphic32>文件夹下的所有文件,就可以编译了;

C: 灰度转化公式和代码实现
  文章中用的灰度公式: Gray = R*0.299 + G*0.587  + B*0.114;
  
代码实现:

  1. //灰度转换系数  
  2. const double gray_r_coeff=0.299;  
  3. const double gray_g_coeff=0.587;  
  4. const double gray_b_coeff=0.114;  
  5.     //处理一个点  
  6.     must_inline double toGray_float(const Color32& src){  
  7.         return (src.r*gray_r_coeff +src.g*gray_g_coeff +src.b*gray_b_coeff);  
  8.     }  
  9.     //处理一行  
  10.     void colorToGrayLine_float(const Color32* src,Color32* dst,long width){  
  11.         for (long x = 0; x < width; ++x){  
  12.             int gray=(int)toGray_float(src[x]);  
  13.             dst[x]=Color32(gray,gray,gray,src[x].a);//R,G,B都设置为相同的亮度值,A不变  
  14.         }  
  15.     }  
  16. void colorToGray_float(const TPixels32Ref& src,const TPixels32Ref& dst){  
  17.     long width=std::min(src.width,dst.width);  
  18.     long height=std::min(src.height,dst.height);  
  19.     Color32* srcLine=src.pdata;  
  20.     Color32* dstLine=dst.pdata;  
  21.     for (long y = 0; y < height; ++y){  
  22.         colorToGrayLine_float(srcLine,dstLine,width);  
  23.         src.nextLine(srcLine);  
  24.         dst.nextLine(dstLine);  
  25.     }  
  26. }  


//速度测试
//==============================================================================
// colorToGray_float           145.49 FPS


D: 将浮点运算转化为定点数(整数)运算
    
  1. must_inline int toGray_int16(const Color32& src){  
  2.     const long bit=16;  
  3.     const int gray_r_coeff_int=(int)( gray_r_coeff*(1<<bit)+0.4999999 );  
  4.     const int gray_g_coeff_int=(int)( gray_g_coeff*(1<<bit)+0.4999999 );  
  5.     const int gray_b_coeff_int=(1<<bit)-gray_r_coeff_int-gray_g_coeff_int;  
  6.     return (src.r*gray_r_coeff_int +src.g*gray_g_coeff_int +src.b*gray_b_coeff_int) >> bit;  
  7. }  
  8. inline void colorToGrayLine_int16(const Color32* src,Color32* dst,long width){  
  9.     for (long x = 0; x < width; ++x){  
  10.         int gray=toGray_int16(src[x]);  
  11.         dst[x]=Color32(gray,gray,gray,src[x].a);  
  12.     }  
  13. }  
  14.  colorToGray_int16(const TPixels32Ref& src,const TPixels32Ref& dst){  
  15. long width=std::min(src.width,dst.width);  
  16. long height=std::min(src.height,dst.height);  
  17. Color32* srcLine=src.pdata;  
  18. Color32* dstLine=dst.pdata;  
  19. for (long y = 0; y < height; ++y){  
  20.     colorToGrayLine_int16(srcLine,dstLine,width);  
  21.     src.nextLine(srcLine);  
  22.     dst.nextLine(dstLine);  
  23. }  



//速度测试
//==============================================================================
// colorToGray_int16           355.33 FPS


E: 做一个简单的循环代码展开
  1. //四路展开  
  2. void colorToGrayLine_int16_expand4(const Color32* src,Color32* dst,long width){  
  3.     long widthFast=width>>2<<2;  
  4.     for (long x = 0; x < widthFast; x+=4){  
  5.         int gray0=toGray_int16(src[x  ]);  
  6.         int gray1=toGray_int16(src[x+1]);  
  7.         dst[x  ]=Color32(gray0,gray0,gray0,src[x  ].a);  
  8.         dst[x+1]=Color32(gray1,gray1,gray1,src[x+1].a);  
  9.         int gray2=toGray_int16(src[x+2]);  
  10.         int gray3=toGray_int16(src[x+3]);  
  11.         dst[x+2]=Color32(gray2,gray2,gray2,src[x+2].a);  
  12.         dst[x+3]=Color32(gray3,gray3,gray3,src[x+3].a);  
  13.     }  
  14.     //border  
  15.     if (width>widthFast)  
  16.         colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  17. }  
  18.  colorToGray_int16_expand4(const TPixels32Ref& src,const TPixels32Ref& dst){  
  19. long width=std::min(src.width,dst.width);  
  20. long height=std::min(src.height,dst.height);  
  21. Color32* srcLine=src.pdata;  
  22. Color32* dstLine=dst.pdata;  
  23. for (long y = 0; y < height; ++y){  
  24.     colorToGrayLine_int16_expand4(srcLine,dstLine,width);  
  25.     src.nextLine(srcLine);  
  26.     dst.nextLine(dstLine);  
  27. }  



//速度测试
//==============================================================================
// colorToGray_int16_expand4   413.22 FPS


F: 一个特别的版本
   在高级语言范围内进行单条指令多数据流计算,减少需要的乘法量;
在乘法运算代价比较高昂的cpu上应该效果不错; (x86上速度可能慢)
  1. must_inline UInt32 toGray_int8_opMul(const Color32* src2Color){  
  2.     const UInt32 gray_r_coeff_8=(UInt32)( gray_r_coeff*(1<<8)+0.4999999);  
  3.     const UInt32 gray_g_coeff_8=(UInt32)( gray_g_coeff*(1<<8)+0.4999999);  
  4.     const UInt32 gray_b_coeff_8=(1<<8)-gray_r_coeff_8-gray_g_coeff_8;  
  5.     UInt32 RR,GG,BB;  
  6.     BB=src2Color[0].b | (src2Color[1].b<<16);  
  7.     GG=src2Color[0].g | (src2Color[1].g<<16);  
  8.     RR=src2Color[0].r | (src2Color[1].r<<16);  
  9.     BB*=gray_b_coeff_8;  
  10.     GG*=gray_g_coeff_8;  
  11.     RR*=gray_r_coeff_8;  
  12.     return BB+GG+RR;  
  13. }  
  14. void colorToGrayLine_int8_opMul(const Color32* src,Color32* dst,long width){  
  15.     long widthFast=width>>2<<2;  
  16.     for (long x = 0; x < widthFast; x+=4){  
  17.         UInt32 gray01=toGray_int8_opMul(&src[x  ]);  
  18.         int gray0=(gray01&0x0000FF00)>>8;  
  19.         int gray1=gray01>>24;  
  20.         dst[x  ]=Color32(gray0,gray0,gray0,src[x  ].a);  
  21.         dst[x+1]=Color32(gray1,gray1,gray1,src[x+1].a);  
  22.         UInt32 gray23=toGray_int8_opMul(&src[x+2]);  
  23.         int gray2=(gray23&0x0000FF00)>>8;  
  24.         int gray3=gray23>>24;  
  25.         dst[x+2]=Color32(gray2,gray2,gray2,src[x+2].a);  
  26.         dst[x+3]=Color32(gray3,gray3,gray3,src[x+3].a);  
  27.     }  
  28.     //border  
  29.     if (width>widthFast)  
  30.         colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  31. }  
  32.  colorToGray_int8_opMul(const TPixels32Ref& src,const TPixels32Ref& dst){  
  33. long width=std::min(src.width,dst.width);  
  34. long height=std::min(src.height,dst.height);  
  35. Color32* srcLine=src.pdata;  
  36. Color32* dstLine=dst.pdata;  
  37. for (long y = 0; y < height; ++y){  
  38.     colorToGrayLine_int8_opMul(srcLine,dstLine,width);  
  39.     src.nextLine(srcLine);  
  40.     dst.nextLine(dstLine);  
  41. }  


//速度测试
//==============================================================================
// colorToGray_int8_opMul      387.97 FPS


G: 内联汇编的MMX实现版本
   注意:这里的MMX代码都只支持x86CPU(奔腾MMX以上CPU);
   在x64下不再有MMX寄存器,而应该使用SEE的XMM寄存器;
   而且在x64模式下vc2008编译器还没有提供内联汇编的直接支持,而必须使用函数指令方式的实现;
   GCC编译器也支持内联汇编模式,但是汇编语法不同,请参考相应的说明;

  1.     void colorToGrayLine_MMX(const Color32* src,Color32* dst,long width){  
  2.         //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );  
  3.         //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );  
  4.         //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;  
  5.         // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]  
  6.         const  UInt64   csMMX_rgb_coeff_w  = (((UInt64)0x00000026)<<32) | 0x004b000f;  
  7.         long widthFast=width>>1<<1;  
  8.         if (widthFast>0){  
  9.             asm{  
  10.                     pcmpeqb        mm5,mm5                // FF  FF  FF  FF  FF  FF  FF  FF  
  11.                     mov        ecx,widthFast  
  12.                     pxor        mm7,mm7                // 00  00  00  00  00  00  00  00  
  13.                     pcmpeqb        mm4,mm4                // FF  FF  FF  FF  FF  FF  FF  FF  
  14.                     mov     eax,src  
  15.                     mov     edx,dst  
  16.                     movq        mm6,csMMX_rgb_coeff_w  
  17.                     psrlw        mm5,15                //      1       1       1       1  
  18.                     lea     eax,[eax+ecx*4]  
  19.                     lea     edx,[edx+ecx*4]      
  20.                     pslld        mm4,24                // FF  00  00  00  FF  00  00  00  
  21.                     neg     ecx  
  22.                      
  23.                   loop_beign:  
  24.                     movq        mm0,[eax+ecx*4]        // A1  R1  G1  B1  A0  R0  G0  B0  
  25.                     movq        mm1,mm0  
  26.                     movq        mm3,mm0  
  27.                     punpcklbw   mm0,mm7                // 00  A0  00  R0  00  G0  00  B0  
  28.                     punpckhbw   mm1,mm7                // 00  A1  00  R1  00  G1  00  B1  
  29.                     pmaddwd     mm0,mm6             // R0*r_coeff      G0*g_coeff+B0*b_coeff  
  30.                     pmaddwd     mm1,mm6             // R1*r_coeff      G1*g_coeff+B1*b_coeff  
  31.                     pand        mm3,mm4             // A1  00  00  00  A0  00  00  00  
  32.                     packssdw    mm0,mm1             // sR1     sG1+sB1 sR0     sG0+sB0  
  33.                     pmaddwd     mm0,mm5             // sR1+sG1+sB1     sR0+sG0+sB0  
  34.                     psrld       mm0,7               // 00 00 00 Gray1  00 00 00 Gray0  
  35.                     movq        mm1,mm0  
  36.                     movq        mm2,mm0  
  37.                     pslld        mm1,8                // 00 00 Gray1 00  00 00 Gray0 00  
  38.                     por         mm0,mm3  
  39.                     pslld        mm2,16                // 00 Gray1 00 00  00 Gray0 00 00  
  40.                     por         mm0,mm1  
  41.                     por         mm0,mm2             // A1 Gray1 Gray1 Gray1  A0 Gray0 Gray0 Gray0  
  42.                     movq [edx+ecx*4],mm0  
  43.                     add     ecx,2                   
  44.                     jnz     loop_beign  
  45.             }  
  46.         }  
  47.         //border  
  48.         if (width>widthFast)  
  49.             colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  50.     }  
  51. void colorToGray_MMX(const TPixels32Ref& src,const TPixels32Ref& dst){  
  52.     long width=std::min(src.width,dst.width);  
  53.     long height=std::min(src.height,dst.height);  
  54.     Color32* srcLine=src.pdata;  
  55.     Color32* dstLine=dst.pdata;  
  56.     for (long y = 0; y < height; ++y){  
  57.         colorToGrayLine_MMX(srcLine,dstLine,width);  
  58.         src.nextLine(srcLine);  
  59.         dst.nextLine(dstLine);  
  60.     }  
  61.     asm{  
  62.         emms //MMX使用结束  
  63.     }  
  64. }  



//速度测试
//==============================================================================
// colorToGray_MMX             590.84 FPS


H: 优化写缓冲的内联汇编的MMX实现版本
  该版本相应于上面的MMX版本只改写了两句:
   一是写内存的movq [edx+ecx*4],mm0 改成了 movntq [edx+ecx*4],mm0 绕过缓存
   二是函数结束的时候调用sfence刷新写入
  完整代码如下:

  1. void colorToGrayLine_MMX2(const Color32* src,Color32* dst,long width){  
  2.     //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );  
  3.     //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );  
  4.     //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;  
  5.     // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]  
  6.     const  UInt64   csMMX_rgb_coeff_w  = (((UInt64)0x00000026)<<32) | 0x004b000f;  
  7.     long widthFast=width>>1<<1;  
  8.     if (widthFast>0){  
  9.         asm{  
  10.                 pcmpeqb        mm5,mm5                // FF  FF  FF  FF  FF  FF  FF  FF  
  11.                 mov        ecx,widthFast  
  12.                 pxor        mm7,mm7                // 00  00  00  00  00  00  00  00  
  13.                 pcmpeqb        mm4,mm4                // FF  FF  FF  FF  FF  FF  FF  FF  
  14.                 mov     eax,src  
  15.                 mov     edx,dst  
  16.                 movq        mm6,csMMX_rgb_coeff_w  
  17.                 psrlw        mm5,15                //      1       1       1       1  
  18.                 lea     eax,[eax+ecx*4]  
  19.                 lea     edx,[edx+ecx*4]      
  20.                 pslld        mm4,24                // FF  00  00  00  FF  00  00  00  
  21.                 neg     ecx  
  22.                  
  23.               loop_beign:  
  24.                 movq        mm0,[eax+ecx*4]        // A1  R1  G1  B1  A0  R0  G0  B0  
  25.                 movq        mm1,mm0  
  26.                 movq        mm3,mm0  
  27.                 punpcklbw   mm0,mm7                // 00  A0  00  R0  00  G0  00  B0  
  28.                 punpckhbw   mm1,mm7                // 00  A1  00  R1  00  G1  00  B1  
  29.                 pmaddwd     mm0,mm6             // R0*r_coeff      G0*g_coeff+B0*b_coeff  
  30.                 pmaddwd     mm1,mm6             // R1*r_coeff      G1*g_coeff+B1*b_coeff  
  31.                 pand        mm3,mm4             // A1  00  00  00  A0  00  00  00  
  32.                 packssdw    mm0,mm1             // sR1     sG1+sB1 sR0     sG0+sB0  
  33.                 pmaddwd     mm0,mm5             // sR1+sG1+sB1     sR0+sG0+sB0  
  34.                 psrld       mm0,7               // 00 00 00 Gray1  00 00 00 Gray0  
  35.                 movq        mm1,mm0  
  36.                 movq        mm2,mm0  
  37.                 pslld        mm1,8                // 00 00 Gray1 00  00 00 Gray0 00  
  38.                 por         mm0,mm3  
  39.                 pslld        mm2,16                // 00 Gray1 00 00  00 Gray0 00 00  
  40.                 por         mm0,mm1  
  41.                 por         mm0,mm2             // A1 Gray1 Gray1 Gray1  A0 Gray0 Gray0 Gray0  
  42.                 movntq [edx+ecx*4],mm0  //和colorToGrayLine_MMX的不同之处  
  43.                 add     ecx,2                   
  44.                 jnz     loop_beign  
  45.         }  
  46.     }  
  47.     //border  
  48.     if (width>widthFast)  
  49.         colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  50. }  
  51.  colorToGray_MMX2(const TPixels32Ref& src,const TPixels32Ref& dst){  
  52. long width=std::min(src.width,dst.width);  
  53. long height=std::min(src.height,dst.height);  
  54. Color32* srcLine=src.pdata;  
  55. Color32* dstLine=dst.pdata;  
  56. for (long y = 0; y < height; ++y){  
  57.     colorToGrayLine_MMX2(srcLine,dstLine,width);  
  58.     src.nextLine(srcLine);  
  59.     dst.nextLine(dstLine);  
  60. }  
  61. asm{  
  62.     sfence  //刷新写入  
  63.     emms  
  64. }  




//速度测试
//==============================================================================
// colorToGray_MMX2            679.50 FPS


I: 使用MMX函数指令方式的实现
  MMX/SSE等特殊指令除了内联汇编来使用外,也可以使用函数指令方式的实现,从而在多种
编译器下都可以使用SIMD相关指令,可移植性也会好很多;
  但现在看来,vc对此的优化还不够,还可能遇到编译器的实现bug;
  (可以考虑使用intel的编译器编译这些代码,感觉优化能力很不错)

  1. #include <mmintrin.h>   //mmx  
  2. //#include <mm3dnow.h>    //3dnow  
  3. #include <xmmintrin.h>  //sse  
  4. //#include <emmintrin.h>  //sse2  
  5. //#include <pmmintrin.h>  //sse3  
  6. //#include <tmmintrin.h>  //ssse3  
  7. //#include <intrin.h>     //sse4a  
  8. //#include <smmintrin.h>  //sse4.1  
  9. //#include <nmmintrin.h>  //sse4.2  
  10. //----------------------------------  
  11.     void colorToGrayLine_MMX_mmh(const Color32* src,Color32* dst,long width){  
  12.         //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );  
  13.         //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );  
  14.         //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;  
  15.         // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]  
  16.         long widthFast=width>>1<<1;  
  17.         if (widthFast>0){  
  18.             const UInt64 csMMX_rgb_coeff_w  =(((UInt64)0x00000026)<<32) | 0x004b000f;  
  19.             const __m64 mm6=*(const __m64*)&csMMX_rgb_coeff_w;  
  20.             const __m64 mm7=_mm_setzero_si64();     //mm?变量值同colorToGrayLine_MMX中的mmx值一致  
  21.             __m64 mm5=_mm_cmpeq_pi8(mm7,mm7);       //想写成__m64 mm5; mm5=_mm_cmpeq_pi8(mm5,mm5);但会出错:(  
  22.             const __m64 mm4=_mm_slli_pi32(mm5,24);  // ...  
  23.             mm5=_mm_srli_pi16(mm5,15);              // ...  
  24.             for (long x = 0; x < widthFast; x+=2){  
  25.                 __m64 mm0=*(__m64*)&src[x];  
  26.                 __m64 mm1=mm0;  
  27.                 __m64 mm3=mm0;  
  28.                 mm0=_mm_unpacklo_pi8(mm0,mm7);  
  29.                 mm1=_mm_unpackhi_pi8(mm1,mm7);  
  30.                 mm0=_mm_madd_pi16(mm0,mm6);  
  31.                 mm1=_mm_madd_pi16(mm1,mm6);  
  32.                 mm3=_mm_and_si64(mm3,mm4);  
  33.                 mm0=_mm_packs_pi32(mm0,mm1);  
  34.                 mm0=_mm_madd_pi16(mm0,mm5);  
  35.                 mm0=_mm_srli_pi32(mm0,7);  
  36.                 mm1=mm0;  
  37.                 __m64 mm2=mm0;  
  38.                 mm1=_mm_slli_pi32(mm1,8);  
  39.                 mm0=_mm_or_si64(mm0,mm3);  
  40.                 mm2=_mm_slli_pi32(mm2,16);  
  41.                 mm0=_mm_or_si64(mm0,mm1);  
  42.                 mm0=_mm_or_si64(mm0,mm2);  
  43.                 *(__m64*)&dst[x]=mm0;  
  44.             }  
  45.         }  
  46.         //border  
  47.         if (width>widthFast)  
  48.             colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  49.     }  
  50. void colorToGray_MMX_mmh(const TPixels32Ref& src,const TPixels32Ref& dst){  
  51.     long width=std::min(src.width,dst.width);  
  52.     long height=std::min(src.height,dst.height);  
  53.     Color32* srcLine=src.pdata;  
  54.     Color32* dstLine=dst.pdata;  
  55.     for (long y = 0; y < height; ++y){  
  56.         colorToGrayLine_MMX_mmh(srcLine,dstLine,width);  
  57.         src.nextLine(srcLine);  
  58.         dst.nextLine(dstLine);  
  59.     }  
  60.     _mm_empty(); //MMX使用结束  
  61. }  



//速度测试
//==============================================================================
// colorToGray_MMX_mmh         508.69 FPS



 优化写缓冲的使用MMX函数指令方式的实现

  1.     void colorToGrayLine_MMX2_mmh(const Color32* src,Color32* dst,long width){  
  2.         //const UInt32 gray_r_coeff_7=(UInt32)( gray_r_coeff*(1<<7)+0.4999999 );  
  3.         //const UInt32 gray_g_coeff_7=(UInt32)( gray_g_coeff*(1<<7)+0.4999999 );  
  4.         //const UInt32 gray_b_coeff_7=(1<<7)-gray_r_coeff_7-gray_g_coeff_7;  
  5.         // csMMX_rgb_coeff_w= short[ 0 , gray_r_coeff_7 , gray_g_coeff_7 , gray_b_coeff_7 ]  
  6.         long widthFast=width>>1<<1;  
  7.         if (widthFast>0){  
  8.             const UInt64 csMMX_rgb_coeff_w  =(((UInt64)0x00000026)<<32) | 0x004b000f;  
  9.             const __m64 mm6=*(const __m64*)&csMMX_rgb_coeff_w;  
  10.             const __m64 mm7=_mm_setzero_si64();     //mm?变量值同colorToGrayLine_MMX中的mmx值一致  
  11.             __m64 mm5=_mm_cmpeq_pi8(mm7,mm7);       // ...  
  12.             const __m64 mm4=_mm_slli_pi32(mm5,24);  // ...  
  13.             mm5=_mm_srli_pi16(mm5,15);              // ...  
  14.             for (long x = 0; x < widthFast; x+=2){  
  15.                 __m64 mm0=*(__m64*)&src[x];  
  16.                 __m64 mm1=mm0;  
  17.                 __m64 mm3=mm0;  
  18.                 mm0=_mm_unpacklo_pi8(mm0,mm7);  
  19.                 mm1=_mm_unpackhi_pi8(mm1,mm7);  
  20.                 mm0=_mm_madd_pi16(mm0,mm6);  
  21.                 mm1=_mm_madd_pi16(mm1,mm6);  
  22.                 mm3=_mm_and_si64(mm3,mm4);  
  23.                 mm0=_mm_packs_pi32(mm0,mm1);  
  24.                 mm0=_mm_madd_pi16(mm0,mm5);  
  25.                 mm0=_mm_srli_pi32(mm0,7);  
  26.                 mm1=mm0;  
  27.                 __m64 mm2=mm0;  
  28.                 mm1=_mm_slli_pi32(mm1,8);  
  29.                 mm0=_mm_or_si64(mm0,mm3);  
  30.                 mm2=_mm_slli_pi32(mm2,16);  
  31.                 mm0=_mm_or_si64(mm0,mm1);  
  32.                 mm0=_mm_or_si64(mm0,mm2);  
  33.                 //*(__m64*)&dst[x]=mm0;  
  34.                 _mm_stream_pi((__m64*)&dst[x],mm0);  
  35.             }  
  36.         }  
  37.         //border  
  38.         if (width>widthFast)  
  39.             colorToGrayLine_int16(&src[widthFast],&dst[widthFast],width-widthFast);  
  40.     }  
  41. void colorToGray_MMX2_mmh(const TPixels32Ref& src,const TPixels32Ref& dst){  
  42.     long width=std::min(src.width,dst.width);  
  43.     long height=std::min(src.height,dst.height);  
  44.     Color32* srcLine=src.pdata;  
  45.     Color32* dstLine=dst.pdata;  
  46.     for (long y = 0; y < height; ++y){  
  47.         colorToGrayLine_MMX2_mmh(srcLine,dstLine,width);  
  48.         src.nextLine(srcLine);  
  49.         dst.nextLine(dstLine);  
  50.     }  
  51.     _mm_sfence();//刷新写入  
  52.     _mm_empty(); //MMX使用结束  
  53. }  



//速度测试
//==============================================================================
// colorToGray_MMX2_mmh        540.78 FPS


J:把测试成绩放在一起:


//CPU: AMD64x2 4200+(2.33G)  800*600 to 800*600
//==============================================================================
// colorToGray_float           145.49 FPS
// colorToGray_int16           355.33 FPS
// colorToGray_int16_expand4   413.22 FPS
// colorToGray_int8_opMul      387.97 FPS
// colorToGray_MMX             590.84 FPS
// colorToGray_MMX2            679.50 FPS
// colorToGray_MMX_mmh         508.69 FPS
// colorToGray_MMX2_mmh        540.78 FPS


ps:用SSE的浮点指令的版本/用SSE2整数指令的版本/利用SSE3的水平加指令等的实现版本有机会时再补充
ps:SIMD特殊指令集的使用框架请参见我的<YUV视频格式到RGB32格式转换的速度优化 中篇>一文,从而
根据CPU对指令集的支持情况动态的调用最优的实现函数版本;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值