MMX/SSE 2实现XviD CODEC(1)

来源:互联网 发布:科尼塞克agera rs数据 编辑:程序博客网 时间:2024/05/01 11:09

14.2.2  MMX/SSE 2实现XviD CODEC(1)

上一节对XviD CODEC的系统框架做了功能剖析和技术说明,现在开始对最底层的模块如DCT/IDCT、Q/IQ、VLC/VLD、SAD等作汇编优化和设计。第12章已经对MMX/SSE 2汇编编程、汇编指令结构等作了详细介绍。基于通用CPU进行多媒体编程,汇编语言提供了数据打包、单指令多数据处理等特点的高性能支持。

由于算法系统是C语言编程,而在使用汇编优化核心模块的时候,就涉及了混合编程技术。汇编编写的函数要被C语言调用,则在编程时要遵守一定的规则。如在汇编函数名称前加下画线'_'。

1.MMX汇编指令优化核心模块

XviD CODEC的汇编程序支持NASM汇编器,它是一个为可移植性与模块化而设计的80 86的汇编器。它支持相当多的目标文件格式,包括Linux、NetBSD/FreeBSD、a.out、ELF、COFF、微软16位的OBJ和Win32。它还可以输出纯二进制文件。它的语法设计得相当地简洁易懂,和Intel语法相似但更简单。它支持Pentium、P6、MMX、3DNow!、SSE和SSE 2指令集。

1)一般宏定义

下面的宏定义中使用了宏汇编中表达式操作符%,它把后面的文本解释为表达式,功能是取表达式的最终的值。使用这个操作符可以把表达式的值作为实参引用,而不是引用表达式文本本身。

%macro表示定义多行宏,%endmacro表示多行宏的结束。在%macro一行上宏名后面的数字1定义了宏可以接收的参数的个数,宏定义里面的%1用来引用宏调用中的第一个参数。对于一个有多个参数的宏,参数序列可以这样写:%2、%3等。%define用来定义单行宏,NASM的详细开发技术请参考Nasm中文手册。

BITS 32                                       ; 表明32位指令%macro cglobal 1                             ; cglobal宏定义%ifdef PREFIX%ifdef MARK_FUNCSglobal _%1:function %1.endfunc-%1%define %1 _%1:function %1.endfunc-%1%elseglobal _%1                     ;有效定义,定义全局函数%define %1 _%1                ;在汇编中,使用没有'_'的函数名称%endif%else%ifdef MARK_FUNCSglobal %1:function %1.endfunc-%1%elseglobal %1%endif%endif%endmacro
上面使用宏定义了函数的名称,宏名为cglobal,由于在汇编文件的汇编选项设置中定义了PREFIX,而没有定义MARK_FUNCS,所以宏的实际定义为上述代码中加黑显示的内容,例如:
global _myfuncdefine myfunc _myfunc
2)只读段.rodata存放常量
;===========================================================================; 只读数据段(Read Only Data);===========================================================================%ifdef FORMAT_COFFSECTION .rodata%elseSECTION .rodata align=16   ;只读数据段,16字节(128位)对齐%endifALIGN 16              ;16字节对齐mmx_one:dw 1, 1, 1, 1        ;定义的字

上述代码定义了16字节对齐的常量mmx_one,4个常量中每个常量长度为16比特,数据放置在只读段.rodata。

3)C语言函数transfer_8to16copy_c的功能

C语言函数transfer_8to16copy_c的功能是把像素值从8位扩展到16位。

voidtransfer_8to16copy_c(int16_t * const dst,  const uint8_t * const src,  uint32_t stride){uint32_t i, j;for (j = 0; j < 8; j++) {for (i = 0; i < 8; i++) {dst[j * 8 + i] = (int16_t) src[j * stride + i];}}}

上述代码有两层循环,每次处理一个单元,即把8位的像素值扩展为16位。

MMX的寄存器是64位,这样MMX指令可以一次处理8个字节。该函数的汇编优化是transfer_8to16copy_mmx(),该函数优化的思路是把要复制的数据打包形成64位,每次存储两行,执行4次宏处理,下面是汇编优化的结果。

SECTION .text     ;.text 段cglobal transfer_8to16copy_mmx ;函数声明:_ transfer_8to16copy_mmx%macro COPY_8_TO_16 1   ;定义宏COPY_8_TO_16开始movq mm0, [eax]    ;取64bit,第一行8个像素点movq mm1, [eax+edx]   ;取64bit,第二行8个像素点movq mm2, mm0     ;mm2=mm0movq mm3, mm1     ;mm3=mm1punpcklbw mm0, mm7    ;mm0的低4Byte扩展成wordmovq [ecx+%1*32], mm0   ;mm0的内容存到[ecx+%1*32]punpcklbw mm1, mm7    ;mm1的低4Byte扩展成wordmovq [ecx+%1*32+16], mm1  ;mm1的内容存到[ecx+%1*32+16]punpckhbw mm2, mm7    ;mm2的低4Byte扩展成wordpunpckhbw mm3, mm7    ;mm3的低4Byte扩展成wordlea eax, [eax+2*edx]   ;修改eax值,指向当前行的第三行movq [ecx+%1*32+8], mm2  ;mm2的内容存到[ecx+%1*32+8]movq [ecx+%1*32+24], mm3  ;mm3的内容存到[ecx+%1*32+24]%endmacro      ;定义宏COPY_8_TO_16结束ALIGN 16       ;下面地址是16字节对齐transfer_8to16copy_mmx:   ;实际是_transfer_8to16copy_mmx,前面有define定义。mov ecx, [esp+ 4] ; Dst  ;取第一个参数 dstmov eax, [esp+ 8] ; Src  ;取第二个参数 srcmov edx, [esp+12] ; Stride  ;取第三个参数 stridepxor mm7, mm7                   ;mm7清零COPY_8_TO_16 0                 ;第一次展开宏,处理0、1行COPY_8_TO_16 1                 ;第二次展开宏,处理2、3行COPY_8_TO_16 2                 ;第三次展开宏,处理4、5行COPY_8_TO_16 3                 ;第四次展开宏,处理6、7行ret                              ;函数返回.endfunc

0 0
原创粉丝点击