设为首页 加入收藏

TOP

14.2.2 MMX/SSE 2实现XviD CODEC(2)
2013-10-07 00:41:58 来源: 作者: 【 】 浏览:64
Tags:14.2.2 MMX/SSE 实现 XviD CODEC

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

经过分析,上述汇编函数的显示定义如下,可以看出汇编函数名称前必须加"_",以保证能够被C语言调用。传入的参数在堆栈中,使用ESP指针加偏移量读取。

;---------------------------------------------------------------------------
; void transfer_16to8copy_mmx(uint8_t * const dst,
;      const int16_t * const src,
;      uint32_t stride);
;---------------------------------------------------------------------------
SECTION .text
global _transfer_8to16copy_mmx
ALIGN 16
_transfer_8to16copy_mmx:
;汇编指令
;汇编指令
ret
.endfuncm32

上述代码是函数transfer_16to8copy_mmx的汇编实现。汇编中函数名称前加了下画线"_"。使用global关键字声明该函数为全局函数,使得C语言能调用该函数。

其他有的核心模块也使用了MMX汇编指令作优化。开发过程与transfer_ 8to16copy_mmx类似。详情参考xx_mmx.asm文件,这些模块的优化使用了MMX指令。

2.SSE 2汇编指令优化核心模块

还有一部分核心模块使用了SSE 2汇编指令作优化。SSE 2汇编语言的数据寄存器是128位,共8个,即XMM0~XMM7。这样SSE指令可以一次处理16字节,相比MMX指令的一次处理8字节,效率提高了一倍。

MMX和SSE 2的一般宏定义相同,常量同样放在.rodata段下,地址16字节对齐。

下面以sad模块的SSE 2汇编优化为案例,分析SSE 2汇编指令优化过程,优化思路是每次处理宏块的2行,执行8次宏处理。

sad16的C语言实现如下。

uint32_t sad16_c(const uint8_t * const cur, const uint8_t * const ref,
const uint32_t stride,  const uint32_t best_sad)
{
uint32_t sad = 0;
uint32_t i, j;
uint8_t const *ptr_cur = cur;    //当前帧指针
uint8_t const *ptr_ref = ref;    //参考帧指针
for (j = 0; j < 16; j++) {      //外循环
for (i = 0; i < 16; i++) { //内循环
int pixel = (ptr_cur[i] - ptr_ref2[i]); //对应位置相间
sad += abs(pixel);     //累加绝对值
}
ptr_cur += stride;         //指向下一行
ptr_ref += stride;         //指向下一行
}
return sad;                   //返回sad值
}
上述程序是计算对应块的sad值,两层循环,每次只计算一个像素点的差值,先采用SSE的指令优化该函数。下面代码是该函数的SSE优化结果。
;---------------------------------------------------------------------------
; uint32_t sad16_sse2 (const uint8_t * const cur, <- assumed aligned!
;                      const uint8_t * const ref,
;                    const uint32_t stride,
;                      const uint32_t /*ignored*/);
;---------------------------------------------------------------------------
%macro SAD_16x16_SSE2 0  ;定义宏
movdqu  xmm0, [edx]   ;为16字节对齐读取,=>xmm0
movdqu  xmm1, [edx+ecx]  ;为16字节对齐读取,=>xmm1
lea edx,[edx+2*ecx]  ;修改edx
movdqa  xmm2, [eax]   ;16字节对齐读取,=>xmm2
movdqa  xmm3, [eax+ecx]  ;16字节对齐读取,=>xmm3
lea eax,[eax+2*ecx]  ;修改eax
psadbw  xmm0, xmm2   ;8字节的sad值,结果放置在低16位
paddusw xmm6,xmm0   ;8个无符号16位饱和相加
psadbw  xmm1, xmm3   ;8个字节的sad值,结果放置在低16位
paddusw xmm6,xmm1   ;8个无符号16位饱和相加
%endmacro                   ;宏定义结束
ALIGN 16      ;16字节对齐
sad16_sse2:     ;函数声明,_sad16_see2
mov eax, [esp+ 4] ; cur (assumed aligned) ;取第一个参数,cur是16字节对齐
mov edx, [esp+ 8] ; ref ;取第二个参数,ref对齐不限制
mov ecx, [esp+12] ; stride  ;取第三个参数
pxor xmm6, xmm6 ; accum  ;xmm6 = 0
SAD_16x16_SSE2     ;宏展开,处理0、1行
SAD_16x16_SSE2     ;宏展开,处理2、3行
SAD_16x16_SSE2     ;宏展开,处理4、5行
SAD_16x16_SSE2     ;宏展开,处理6、7行
SAD_16x16_SSE2     ;宏展开,处理8、9行
SAD_16x16_SSE2     ;宏展开,处理10、11行
SAD_16x16_SSE2     ;宏展开,处理12、13行
SAD_16x16_SSE2     ;宏展开,处理14、15行
pshufd  xmm5, xmm6, 00000010b ;根据00000010b重排xmm6
paddusw xmm6, xmm5    ;8个无符号16位饱和相加
pextrw  eax, xmm6, 0   ;扩展字,前面补零
ret
.endfunc

在上述代码中,宏SAD_16x16_SSE 2处理16 16宏块的2行,16个的单字节的像素存储SSE的一个128位寄存器XMM中。调用8次宏,完成整个宏块的处理。

不论是MMX还是SSE 2汇编指令,优化的根本思路都是数据打包,单指令处理多数据源(SIMD)。

【责任编辑:云霞 TEL:(010)68476606】

回书目   上一节   下一节

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇14.2.1 MPEG-4编/解码设计与剖析.. 下一篇14.3.2 VC平台下编译和运行XviD C..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: