用SSE指令集如何实现RGBA转RGB

woaiwcy 2011-03-31 06:39:39
如题,请大家帮忙想想思路~谢谢!!
...全文
528 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
woaiwcy 2011-04-10
  • 打赏
  • 举报
回复
谢谢大家这些天的关注!结贴!
G_Spider 2011-04-06
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 delphiguy 的回复:]
用movsd可能还不如用2条mov快。(未测试)
[/Quote]
可能吧,主要是这里不能用rep 前缀,不然也会很快,不过还是要多条指令,形如
int __declspec(naked) _stdcall  RGBATORGB(char *dest, char *src, unsigned int len)
{
_asm
{
push ebp
mov ebp,esp

mov edx,[ebp+8] ;//dest
mov eax,[ebp+12] ;//src
mov ecx,[ebp+16] ;//len

shr ecx,2
test ecx,ecx ;//长度为0,直接返回0
jz A01
;===================
A00:
push DWORD PTR [eax]
pop DWORD PTR [edx]
add eax,4
add edx,3
dec ecx
jnz A00
;===================
mov BYTE ptr [edx],0 ;//清理最后一个无用字节
A01:
mov eax,edx
sub eax,[ebp+8] ;//RGB有效字节数,作为返回值

leave
ret 12
}
}

woaiwcy 2011-04-06
  • 打赏
  • 举报
回复
[Quote=引用 28 楼 delphiguy 的回复:]

引用 5 楼 woaiwcy 的回复:

2、xmm中存的是数组的下标,要根据下标查表,这种情况又怎样尽量并行做啊?


就我所知的有限范围,应该没法并行。
因为xmm寄存器不能做间接寻址,没有movdqa xmm1,[xmm0]这种指令,只能movdqa xmm1,[mem128]、movdqa xmm1,[esi]这类指令。
所以xmm中存的是数组的下标,还得转出到通用寄存器中……
[/Quote]
恩 那看来这应该算是SSE并行优化的一个小瓶颈吧,因为在优化程序中查表用的还是蛮多的,就像我现在要优化的,它是有3个字节根据一定的规则形成一个地址来查表,对应的结果是我们想要的,我只能把它都拆下来一个个地址算,很痛苦
diego24 2011-04-06
  • 打赏
  • 举报
回复
有点复杂
  • 打赏
  • 举报
回复
稍微优化一点:
sub esp,16
movdqu [esp],xmm0 // 假设xmm0中存了4个int型下标
lea esi,array // esi中装入数组首地址
pop eax
pop ebx
pop ecx
pop edx
mov eax,[esi+eax*4]
mov edx,[esi+edx*4]
mov ecx,[esi+ecx*4]
mov ebx,[esi+ebx*4]
push edx
push ecx
push ebx
push eax
movdqu xmm1,[esp] // 装入查表后的4个数组元素
add esp,16
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 woaiwcy 的回复:]

2、xmm中存的是数组的下标,要根据下标查表,这种情况又怎样尽量并行做啊?
[/Quote]

就我所知的有限范围,应该没法并行。
因为xmm寄存器不能做间接寻址,没有movdqa xmm1,[xmm0]这种指令,只能movdqa xmm1,[mem128]、movdqa xmm1,[esi]这类指令。
所以xmm中存的是数组的下标,还得转出到通用寄存器中才能做查表。

大致可以这样做(未测试):
sub esp,16
movdqu [esp],xmm0 // 假设xmm0中存了4个int型下标
lea esi,array // esi中装入数组首地址
pop eax
pop ebx
pop ecx
pop edx
mov eax,[esi+eax*4]
mov ebx,[esi+ebx*4]
mov ecx,[esi+ecx*4]
mov edx,[esi+edx*4]
push edx
push ecx
push ebx
push eax
movdqu xmm1,[esp] // 装入查表后的4个数组元素
add esp,16
woaiwcy 2011-04-06
  • 打赏
  • 举报
回复
讨论了这么多 大家换一个话题吧 帮我看看我5楼提的问题2有什么思路~这个应该也是做并行优化时经常遇到的问题吧
  • 打赏
  • 举报
回复
用movsd可能还不如用2条mov快。(未测试)
woaiwcy 2011-04-04
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 aiwnx 的回复:]
楼主试试 OpenMP 吧,说不定会更快呢
[/Quote]
谢谢关注!刚搜了下,OpenMP是用于多核编程的,这里我还是先学习SSE优化吧,发现要学的东西太多了~
woaiwcy 2011-04-04
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 delphiguy 的回复:]
你的代码不错,不过稍微有一点问题:
RGBAToRGB16每次只转换4个像素,频繁调用效率就降低了,每次执行都要加载2个指针、1个mask,还有call和ret的开销。
另外,emms是不需要的。
[/Quote]
这样都效率低了啊~前辈有什么更好的方法~
woaiwcy 2011-04-04
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 g_spider 的回复:]
我就来一个pshufb的吧。

C/C++ code
#include <stdio.h>

void RGBAToRGB16(char *d,char *s)
{
//s=abcdefghijklmnop
//d=abcefgijdmnoplhd
//前12个为RGB有效字节,即abcefgijdmno

/* 128 bits mask struct */
/……
[/Quote]
我也试了下用pshufb的方法,不过我把循环也用汇编写了,速度是比原方法快的~
G_Spider 2011-04-04
  • 打赏
  • 举报
回复
写了个x86版本的,应该也不会慢。

#include <stdio.h>

int _stdcall RGBATORGB(char *dest, char *src, unsigned int len);

int main()
{
char *Src="abcdefghijklmnoabcdefghijklmnoabcdefghijklmnoabcdefghijklmno";
char Dst[64]={0};
unsigned int len,lenrgb;
len = strlen(Src);

lenrgb=RGBATORGB(Dst,Src,len);

printf("RGB_LEN =%d\nRGB_BYTE=%s\n",lenrgb,Dst);

return 0;
}
//==================================================================
int __declspec(naked) _stdcall RGBATORGB(char *dest, char *src, unsigned int len)
{
_asm
{
push ebp
mov ebp,esp
push esi
push edi
mov edi,[ebp+8] ;//dest
mov esi,[ebp+12] ;//src
mov ecx,[ebp+16] ;//len
;===================
shr ecx,2
cld
A00:
movsd
dec edi
loop A00
;===================
mov BYTE ptr [edi],0 ;//清理最后一个无用字节
mov eax,edi
sub eax,[ebp+8] ;//RGB有效字节数,作为返回值
pop edi
pop esi

leave
ret
}
}
G_Spider 2011-04-04
  • 打赏
  • 举报
回复
也就是写成一个函数,而不是子程序调用(开销过大)。(由于本机不支持SSE3所以没有改),上面的小程序仅仅是试试pshufb指令。其实考虑各种情况还是有些复杂的,首先要有个数据块对齐,一般数据头四字节对齐,处理到16字节对齐后,再用SSE,还有个最后的扫尾。并且最好有多个版本,比如X86的和SSE的。不然不支持SSE3等指令集的就没辄了。

对于x86的想一个好的算法也是不错的,对于多平台也是必须的。

到最后还是最大带宽的限制。OpenMP也没用了。
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 woaiwcy 的回复:]

引用 18 楼 delphiguy 的回复:
你的代码不错,不过稍微有一点问题:
RGBAToRGB16每次只转换4个像素,频繁调用效率就降低了,每次执行都要加载2个指针、1个mask,还有call和ret的开销。
另外,emms是不需要的。

这样都效率低了啊~前辈有什么更好的方法~
[/Quote]

你不都说了吗?“我把循环也用汇编写了”。
就是要把整个32位图像转24位图像的过程用汇编写一个函数,这样转换一幅图像只需要调用一次,加载一个源指针、一个目标指针、一个mask。
aiwnx 2011-04-03
  • 打赏
  • 举报
回复
楼主试试 OpenMP 吧,说不定会更快呢
  • 打赏
  • 举报
回复
你的代码不错,不过稍微有一点问题:
RGBAToRGB16每次只转换4个像素,频繁调用效率就降低了,每次执行都要加载2个指针、1个mask,还有call和ret的开销。
另外,emms是不需要的。
G_Spider 2011-04-02
  • 打赏
  • 举报
回复
我就来一个pshufb的吧。
#include <stdio.h>

void RGBAToRGB16(char *d,char *s)
{
//s=abcdefghijklmnop
//d=abcefgijdmnoplhd
//前12个为RGB有效字节,即abcefgijdmno

/* 128 bits mask struct */
//__declspec(align(16)) char \
//mask[16]={0,1,2,4,5,6,8,9,10,12,13,14,15,11,7,3};
__declspec(align(16)) unsigned int \
mask[4]={0x04020100,0x09080605,0x0e0d0c0a,0x03070b0f};
_asm
{
mov esi,s
mov edi,d
movaps xmm7, mask

movdqu xmm0,[esi] /* load src */
pshufb xmm0, xmm7 /* bytes swap */
movdqu [edi], xmm0 /* store dest */
emms
}

}


void RGBAToRGB(char *dest, char *src)
{
unsigned int i,j,len = strlen(src),lenrest=0;

char *s = src ;
char *d = dest;
len&=~3;//len为四字节的倍数
lenrest=len&0xf; //剩余0~15字节
len>>=4;

for(i=0;i<len;i++)
{
RGBAToRGB16(d,s);
d+=12;
s+=16;
}
d[0]=0;//注意扫尾最后的四个无用字节
//处理剩余的0~15字节
for(i=j=0;i<lenrest;i+=4,j+=3)
{
d[j]=s[i];
d[j+1]=s[i+1];
d[j+2]=s[i+2];
}
}
int main()
{
char *Src="abcdefghijklmnoabcdefghijklmnoabcdefghijklmnoabcdefghijklmno";
char Dst[64]={0};

RGBAToRGB(Dst,Src);
printf("%s\n",Dst);

return 0;
}

woaiwcy 2011-04-01
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 oexpress 的回复:]

恭喜搂住,你可以参考INTEL的例子来学习SSE2/SSE3指令集来达到更好的性能
[/Quote]
谢谢您的关注!能不能帮我想想我那两个问题怎么解决啊~
woaiwcy 2011-04-01
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 delphiguy 的回复:]

引用 9 楼 woaiwcy 的回复:

十分感谢前辈关注!之前都是看的SSE/SSE2的指令,这条真没看到~对了, 我学习SSE都是在网上找的些资料,前辈有没有这方面系统点的资料~谢谢!


看intel文档就可以了,主要是Intel 64 and IA-32 Architectures Software Developer’s Manual Volume 1~3:
http://……
[/Quote]
恩,下下来慢慢看~谢谢前辈! 不过现在程序还得优化,对于查表的部分不知道怎么用SSE实现,前辈有什么好的建议没
woaiwcy 2011-04-01
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 g_spider 的回复:]

RGBA 到RGB 的内存字节流数据是怎样变化的呢? 能不能给个例子
[/Quote]
0RGB0RGB...0RGB0RGB -> RGBRGB...RGBRGB,低位在右~
加载更多回复(13)

21,459

社区成员

发帖
与我相关
我的任务
社区描述
汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器或其他可编程器件的低级语言,亦称为符号语言。
社区管理员
  • 汇编语言
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧