矩阵转置的SSE汇编优化艺术
来源:互联网 发布:阿里云企业邮箱地址 编辑:程序博客网 时间:2024/05/16 05:59
// http://blog.csdn.net/feixiang_john/article/details/8438658
平时我们做图像处理或者视频处理, 很多地方会用到矩阵转置:
比如: DCT变换, 图像旋转, 图像滤波, 以及一些数据的内存行和列的交换等, 会大量使用转置这个动作.
然而由于数据量很大,处理速度很慢!如何来提高处理速度呢?
下面看看分析:
HEVC中有个地方是如下这样实现(直接行和列对应的位置交换):
Pel tmp; for (k=0;k<blkSize-1;k++) { for (l=k+1;l<blkSize;l++) { tmp = pDst[k*dstStride+l]; pDst[k*dstStride+l] = pDst[l*dstStride+k]; pDst[l*dstStride+k] = tmp; } }
如何用汇编来实现呢?
我们先用SSE汇编来实现一个8X8的矩阵转置吧: 这里输入地址pSrc_128[i] 和输出地址pDst_128[i]可以相同也可以不同:
相同的话就是原地转置, 不同的话就是非原地转置.
__m128i* m_pSrc_tmp = pSrc_128[i]; __m128i* m_pDst_tmp = pDst_128[i]; __m128i Org_8_0,Org_8_1, Org_8_2, Org_8_3; __m128i tttt1,tttt2,tttt3,tttt4,tttt33,tttt44; __m128i tttt5,tttt6, tttt7, tttt8; int stride_ii = dstStride>>3;//one Org_8_0 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; Org_8_1 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; Org_8_2 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; Org_8_3 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1); tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3); tttt3 = _mm_unpackhi_epi16(Org_8_0, Org_8_1); tttt4 = _mm_unpackhi_epi16(Org_8_2, Org_8_3); tttt5 = _mm_unpacklo_epi32(tttt1, tttt2); tttt6 = _mm_unpackhi_epi32(tttt1, tttt2); Org_8_0 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8;; Org_8_1 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; Org_8_2 = _mm_load_si128(m_pSrc_tmp); m_pSrc_tmp+=8; Org_8_3 = _mm_load_si128(m_pSrc_tmp); //m_pSrc_tmp+=8; tttt1 = _mm_unpacklo_epi16(Org_8_0, Org_8_1); tttt2 = _mm_unpacklo_epi16(Org_8_2, Org_8_3); tttt33 = _mm_unpackhi_epi16(Org_8_0, Org_8_1); tttt44 = _mm_unpackhi_epi16(Org_8_2, Org_8_3); tttt7 = _mm_unpacklo_epi32(tttt1, tttt2); tttt8 = _mm_unpackhi_epi32(tttt1, tttt2); tttt1 = _mm_unpacklo_epi64(tttt5, tttt7); tttt2 = _mm_unpackhi_epi64(tttt5, tttt7); _mm_storeu_si128(m_pDst_tmp, tttt1); m_pDst_tmp+=stride_ii; _mm_storeu_si128(m_pDst_tmp, tttt2); m_pDst_tmp+=stride_ii; tttt5 = _mm_unpacklo_epi64(tttt6, tttt8); tttt7 = _mm_unpackhi_epi64(tttt6, tttt8); _mm_storeu_si128(m_pDst_tmp, tttt5); m_pDst_tmp+=stride_ii; _mm_storeu_si128(m_pDst_tmp, tttt7); m_pDst_tmp+=stride_ii;//tow tttt5 = _mm_unpacklo_epi32(tttt3, tttt4); tttt6 = _mm_unpackhi_epi32(tttt3, tttt4); tttt7 = _mm_unpacklo_epi32(tttt33, tttt44); tttt8 = _mm_unpackhi_epi32(tttt33, tttt44); tttt1 = _mm_unpacklo_epi64(tttt5, tttt7); tttt2 = _mm_unpackhi_epi64(tttt5, tttt7); _mm_storeu_si128(m_pDst_tmp, tttt1); m_pDst_tmp+=stride_ii; _mm_storeu_si128(m_pDst_tmp, tttt2); m_pDst_tmp+=stride_ii; tttt5 = _mm_unpacklo_epi64(tttt6, tttt8); tttt7 = _mm_unpackhi_epi64(tttt6, tttt8); _mm_storeu_si128(m_pDst_tmp, tttt5); m_pDst_tmp+=stride_ii; _mm_storeu_si128(m_pDst_tmp, tttt7);
要实现的是NXN的转置,如何实现呢:
基于8X8来实现NXN的块或者图像的转置:
这里先把NXN划分为size_case 个8X8, 然后循环调用8X8的转置!
__m128i* pDst_128[64]; __m128i* pSrc_128[64]; int size_case = (blkSize>>3); dstStride = dstStride_tmp; for(int y = 0; y<size_case; y++)//对所有8x8的块进行地址映射 for(int x = 0; x<size_case; x++) { pSrc_128[y*size_case + x] = (__m128i*)(pDst + 8*x + y*8*64); pDst_128[y*size_case + x] = (__m128i*)(rpDst + 8*y + x*8*dstStride); } size_case = size_case*size_case; for(int i = 0;i <size_case; i++)//开始转置 { 8x8转置的代码: }
通过比较, 用SSE汇编优化实现转置比用纯 C代码实现的转置速度快5倍左右!
- 矩阵转置的SSE汇编优化艺术
- 矩阵转置的SSE汇编优化艺术以及ARM cortext 汇编优化
- 矩阵转置的SSE汇编优化艺术以及ARM cortext 汇编优化 .
- 矩阵转置的SSE汇编优化艺术以及ARM cortext 汇编优化
- 矩阵乘法递推的优化艺术
- 利用SSE优化图像转置
- 使用MMX/SSE汇编指令集优化视频开发
- 使用MMX/SSE汇编指令集优化视频开发
- SIMD(SSE、)优化的数据对齐
- SIMD(SSE、)优化的数据对齐
- SIMD(SSE、)优化的数据对齐
- SIMD(SSE、)优化的数据对齐
- 图像转置的SSE优化(支持8位、24位、32位),提速4-6倍
- 代码优化的艺术
- 代码优化的艺术
- 代码优化的艺术
- 代码优化的艺术
- SSE图像算法优化系列十:简单的一个肤色检测算法的SSE优化。
- 技巧-使用翻转效果
- Linq 如何实现 in 与 not in
- UVA 11426 - GCD - Extreme (II) (数论)
- linux下常用的一些函数
- 异或的性质及运用
- 矩阵转置的SSE汇编优化艺术
- 【CityEngine教程文档】 ---03 地图控制教程
- ABAP程序优化方法
- 【现代操作系统】第5章 输入/输出
- 搜笔记 开源库
- Android 左右滑屏 方向判断 ViewPager
- JDBC3.0的特性
- Eclipse出现异常重启adb
- 《Java与模式》之观察者模式