SSE指令集加速之 I420转BGR24
void yuv420_to_rgb24_sse3(uint8_t *yp, uint8_t *up, uint8_t *vp, int sy, int suv, int width, int height,
uint8_t *rgb, int srgb)
{
//定义空间
__m128i y0r0, y0r1, u0, v0;
__m128i y00r0, y01r0, y00r1, y01r1;
__m128i u00, u01, v00, v01;
__m128i rv00, rv01, gu00, gu01, gv00, gv01, bu00, bu01;
__m128i r00, r01, g00, g01, b00, b01;
__m128i rgb0123, rgb4567, rgb89ab, rgbcdef;
__m128i gbgb;
__m128i ysub, uvsub;
__m128i zero, facy, facrv, facgu, facgv, facbu;
__m128i *srcy128r0, *srcy128r1;
uint8_t *dstrgbr0, *dstrgbr1;
__m128i maskrgb;
__m64 *srcu64, *srcv64; //定义核,公式定量
//ysub = 0x0010 ...... 8 times
ysub = _mm_set1_epi16(0x0010);
uvsub = _mm_set1_epi16(0x0080);
zero = _mm_set1_epi16(0x0000); maskrgb = _mm_set_epi8(, , , , , , , , , , , , , , , ); facy = _mm_set1_epi16(0x2543);
facrv = _mm_set1_epi16(0x3313);
facgu = _mm_set1_epi16(0xF377);
facgv = _mm_set1_epi16(0xE5FC);
facbu = _mm_set1_epi16(0x408D); for (int y = ; y < height; y += ) {
//源数据指针
srcy128r0 = (__m128i *)(yp + sy*y);
srcy128r1 = (__m128i *)(yp + sy*y + sy);
srcu64 = (__m64 *)(up + suv*(y / ));
srcv64 = (__m64 *)(vp + suv*(y / )); dstrgbr0 = rgb + srgb*y;
dstrgbr1 = rgb + srgb*y + srgb; for (int x = ; x < width; x += ) {
//加载行数据
u0 = _mm_loadl_epi64((__m128i *)srcu64); srcu64++; //0000 0000 0000 xxxx <= uuuu
v0 = _mm_loadl_epi64((__m128i *)srcv64); srcv64++; y0r0 = _mm_load_si128(srcy128r0++);// xxxx xxxx xxxx xxxx <= yyyy yyyy yyyy yyyy
y0r1 = _mm_load_si128(srcy128r1++); //计算YUV中的Y向量
// a = 0y0y 0y0y 0y0y 0y0y
// b = a - 0x0010 .... = 0y-0x0010 ;
// c = `b<<3 (8 times)
// d = (c*0x2543)>>16 ......8times
y00r0 = _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_unpacklo_epi8(y0r0, zero), ysub), ), facy);
y01r0 = _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_unpackhi_epi8(y0r0, zero), ysub), ), facy);
y00r1 = _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_unpacklo_epi8(y0r1, zero), ysub), ), facy);
y01r1 = _mm_mulhi_epi16(_mm_slli_epi16(_mm_sub_epi16(_mm_unpackhi_epi8(y0r1, zero), ysub), ), facy); //展开u和v,使它们与y值对齐
// u0 = [0][u3] [0][u2] ......
//a = [0][u3][0][u3] ........[0][u0][0][u0]
//b = [0][u3] - 0x0080 .... 8times
//u00 = [0][u3] <<3 ... 8 times;
//u00 =[00000u3000]
//u01 = u00;
u0 = _mm_unpacklo_epi8(u0, zero);
u00 = _mm_slli_epi16(_mm_sub_epi16(_mm_unpacklo_epi16(u0, u0), uvsub), );
u01 = _mm_slli_epi16(_mm_sub_epi16(_mm_unpackhi_epi16(u0, u0), uvsub), ); v0 = _mm_unpacklo_epi8(v0, zero);
v00 = _mm_slli_epi16(_mm_sub_epi16(_mm_unpacklo_epi16(v0, v0), uvsub), );
v01 = _mm_slli_epi16(_mm_sub_epi16(_mm_unpackhi_epi16(v0, v0), uvsub), ); //计算两行UV的向量
// short 乘法 然后移位
// rv00 其实等于rv01
rv00 = _mm_mulhi_epi16(facrv, v00);
rv01 = _mm_mulhi_epi16(facrv, v01); //([00000u3000]*0xF377)>>8 8 times overflow??
gu00 = _mm_mulhi_epi16(facgu, u00);
gu01 = _mm_mulhi_epi16(facgu, u01);
gv00 = _mm_mulhi_epi16(facgv, v00);
gv01 = _mm_mulhi_epi16(facgv, v01);
bu00 = _mm_mulhi_epi16(facbu, u00);
bu01 = _mm_mulhi_epi16(facbu, u01); //计算出最后RGB 行0
//r00 = 0r0r 0r0r 0r0r 0r0r
r00 = _mm_add_epi16(y00r0, rv00);
r01 = _mm_add_epi16(y01r0, rv01);
g00 = _mm_add_epi16(_mm_add_epi16(y00r0, gu00), gv00);
g01 = _mm_add_epi16(_mm_add_epi16(y01r0, gu01), gv01);
b00 = _mm_add_epi16(y00r0, bu00);
b01 = _mm_add_epi16(y01r0, bu01); //排列RGB数据
r00 = _mm_packus_epi16(r00, r01); // rrrr.. 组合计算
g00 = _mm_packus_epi16(g00, g01); // gggg.. 组合计算
b00 = _mm_packus_epi16(b00, b01); // bbbb.. 组合计算 r01 = _mm_unpacklo_epi8(r00, zero); // 0r0r..//取低位
gbgb = _mm_unpacklo_epi8(b00, g00); // gbgb..
rgb0123 = _mm_unpacklo_epi16(gbgb, r01); // 0rgb0rgb..
rgb4567 = _mm_unpackhi_epi16(gbgb, r01); // 0rgb0rgb.. rgb0123 == rgb4567?? r01 = _mm_unpackhi_epi8(r00, zero); //取高位
gbgb = _mm_unpackhi_epi8(b00, g00);
rgb89ab = _mm_unpacklo_epi16(gbgb, r01);
rgbcdef = _mm_unpackhi_epi16(gbgb, r01); //输出RGB数据
//rgb0123 = 0000rgb rgb rgb rgb
rgb0123 = _mm_shuffle_epi8(rgb0123, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr0, rgb0123);
//_mm_store_si128 dstrgbr0 += ; rgb4567 = _mm_shuffle_epi8(rgb4567, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr0, rgb4567);
dstrgbr0 += ; rgb89ab = _mm_shuffle_epi8(rgb89ab, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr0, rgb89ab); dstrgbr0 += ; rgbcdef = _mm_shuffle_epi8(rgbcdef, maskrgb);
memcpy(dstrgbr0, &rgbcdef, ); dstrgbr0 += ; //计算出最后RGB 行1
r00 = _mm_add_epi16(y00r1, rv00);
r01 = _mm_add_epi16(y01r1, rv01);
g00 = _mm_add_epi16(_mm_add_epi16(y00r1, gu00), gv00);
g01 = _mm_add_epi16(_mm_add_epi16(y01r1, gu01), gv01);
b00 = _mm_add_epi16(y00r1, bu00);
b01 = _mm_add_epi16(y01r1, bu01); r00 = _mm_packus_epi16(r00, r01); // rrrr.. saturated
g00 = _mm_packus_epi16(g00, g01); // gggg.. saturated
b00 = _mm_packus_epi16(b00, b01); // bbbb.. saturated r01 = _mm_unpacklo_epi8(r00, zero); // 0r0r..
gbgb = _mm_unpacklo_epi8(b00, g00); // gbgb..
rgb0123 = _mm_unpacklo_epi16(gbgb, r01); // 0rgb0rgb..
rgb4567 = _mm_unpackhi_epi16(gbgb, r01); // 0rgb0rgb.. r01 = _mm_unpackhi_epi8(r00, zero);
gbgb = _mm_unpackhi_epi8(b00, g00);
rgb89ab = _mm_unpacklo_epi16(gbgb, r01);
rgbcdef = _mm_unpackhi_epi16(gbgb, r01); rgb0123 = _mm_shuffle_epi8(rgb0123, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr1, rgb0123); dstrgbr1 += ; rgb4567 = _mm_shuffle_epi8(rgb4567, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr1, rgb4567); dstrgbr1 += ; rgb89ab = _mm_shuffle_epi8(rgb89ab, maskrgb);
_mm_storeu_si128((__m128i *)dstrgbr1, rgb89ab); dstrgbr1 += ; rgbcdef = _mm_shuffle_epi8(rgbcdef, maskrgb);
memcpy(dstrgbr1, &rgbcdef, ); dstrgbr1 += ;
}
}
}
SSE指令集加速之 I420转BGR24的更多相关文章
- c/c++ 代码中使用sse指令集加速
使用SSE指令,首先要了解这一类用于进行初始化加载数据以及将暂存器的数据保存到内存相关的指令, 我们知道,大多数SSE指令是使用的xmm0到xmm8的暂存器,那么使用之前,就需要将数据从内存加载到这些 ...
- AVX图像算法优化系列二: 使用AVX2指令集加速查表算法。
查表算法,无疑也是一种非常常用.有效而且快捷的算法,我们在很多算法的加速过程中都能看到他的影子,在图像处理中,尤其常用,比如我们常见的各种基于直方图的增强,可以说,在photoshop中的调整菜单里8 ...
- SSE指令集学习:Compiler Intrinsic
大多数的函数是在库中,Intrinsic Function却内嵌在编译器中(built in to the compiler). 1. Intrinsic Function Intrinsic Fun ...
- SSE指令集优化学习:双线性插值
对SSE的学习总算迈出了第一步,用2天时间对双线性插值的代码进行了优化,现将实现的过程梳理以下,算是对这段学习的一个总结. 1. 什么是SSE 说到SSE,首先要弄清楚的一个概念是SIMD(单指令多数 ...
- 【转】【SSE】基于SSE指令集的程序设计简介
基于SSE指令集的程序设计简介 作者:Alex Farber 出处:http://www.codeproject.com/cpp/sseintro.asp SSE技术简介 Intel公司的单指令多数据 ...
- 【转】【SEE】基于SSE指令集的程序设计简介
SSE技术简介 Intel公司的单指令多数据流式扩展(SSE,Streaming SIMD Extensions)技术能够有效增强CPU浮点运算的能力.Visual Studio .NET 2003提 ...
- Instructions函数对照表:02 xmmintrin.h与SSE指令集[转]
更多详情见——http://www.cnblogs.com/zyl910/archive/2012/04/26/md00.htmlSIMD函数整理:00 索引贴 R:寄存器.M:64位MM寄存器:X: ...
- SIMD指令集——一条指令操作多个数,SSE,AVX都是,例如:乘累加,Shuffle等
SIMD指令集 from:https://zhuanlan.zhihu.com/p/31271788 SIMD,即Single Instruction, Multiple Data,一条指令操作多个数 ...
- SSE优化指令集编译错误: inlining failed in call to always_inline 'xxx': target specific option mismatch xxx
在用QtCreator编译SSE优化指令的时候,出现了如下错误, inlining failed in call to always_inline '__m128i _mm_packus_epi32( ...
随机推荐
- Jetson TX2介绍
Jetson TX2是NIVDIA瞄准人工智能在Jetson TK1和TX1推出后的升级 TX2的GPU和CPU都进行了升级,内存增加到了8GB.存储增加到了32GB,支持Wifi和蓝牙,编解码支持H ...
- kotlin之MutableMap委托
fun main(arg: Array<String>) { val map = mutableMapOf("name" to "tom", ) v ...
- Tomcat发布项目
WEB项目的目录结构 演示动态项目的创建 把项目打包成war包: 进入这个项目中,使用命令: jar cvf aaa.war * 发布动态项目的三种方式: 1. 直接复制项目到webapps下 2. ...
- 010-HTTP协议
一.概述 HTTP协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议.它可以使浏览器更加高效,使网络传输减少.它不仅保证 ...
- delete和析构函数
new一个类的时候,调用这个类的构造函数,然后在这个类的生命周期内可能会动态生成很多指向堆上的内存,所以应该在析构函数里回收这些内存: 当delete这个类的时候,会首先调用这个类的析构函数,即回收生 ...
- Reset Password 重置密码 (CentOS 5,6,7 ; Juniper Networks: SRX100 )
一些重置root 密码的文档分享(来自官网): CentOS 5,6,7 Juniper Networks : SRX100 链接:https://share.weiyun.com/5BM4kwK ...
- 部署 --- Nginx
Nginx介绍 简介: Nginx是由伊戈尔.塞索耶夫开发的,在04年10月开源的一款高性能HTTP和反向代理服务器. 因为它的稳定性好,功能丰富,有示例配置文件和较低的系统资源消耗而闻名 同时也是一 ...
- OpenCV.20190628
1.OpenCV提取ORB特征并匹配 - 简书.html(https://www.jianshu.com/p/420f8211d1cb) OpenCV提取ORB特征并匹配 - 简书.html(http ...
- elasticsearch基本概念理解+elasticsearch 的shards unassigned处理方法 -- 最佳运维实践 - 集群规划
1.es与MySQL的概念对比 2.概念理解 2.1 Index : 一个索引即是文档的集合 2.2 Document : 一个文档即是一个可被索引的基础单元信息,一条记录: 2.3 Replicas ...
- noi openjudge7627:鸡蛋的硬度
http://noi.openjudge.cn/ch0206/7627/ 描述 最近XX公司举办了一个奇怪的比赛:鸡蛋硬度之王争霸赛.参赛者是来自世界各地的母鸡,比赛的内容是看谁下的蛋最硬,更奇怪的是 ...