例子还是从我opengl例程中一段代码说起,在我opengl例程有这样一段代码。
for (int i = 0;i < h;i++) {
for (int j = 0;j < w;j++) {
int pos = i*w + j;
DWORD dw = pdw[pos];
if (dw > 0) {
if (dw & 0x00ffffff) dw |= 0xff000000;
}
pdw[pos] = dw;
}
}
这段代码有两次,一次是载入的时候,另一次是渲染的时候。由于没采取每帧刷新,优化显得不是很必要,
1000ms内都能接受。这段代码作用是为opengl的alpha测试做准备。把纹理有颜色的alpha都标注为不透明,
黑色的alpha值标注为0,这样alpha测试比较函数就不显示黑色,达到透明。 它是双字操作。一般优化高不了多少,
这里是为学会多媒体,专门提出来讲一讲。
为了学习,再简化一下代码,用下面这段,区别避免双循环,讲起来麻烦。
void CCAlphatest(BYTE *p, UINT len)
{
DWORD*pdw = (DWORD*)p;
len /= 4;
for (UINT i = 0;i < len;i++) {
DWORD dw = pdw[ i ];
if (dw > 0) {
if (dw & 0x00ffffff) dw |= 0xff000000;
}
pdw = dw;
}
}从反汇编开始:
[ i ]
看之前,一定要注意,不要一讲什么汇编,就一定是高效率,C编译过去都是汇编。汇编是常态,不是什么很稀奇的东西。
看了这段反汇编,这段反汇编的印象最深的是什么?
没什么印象,那就自己以后慢慢看。只用自己摸索出来,才能深深刻在记忆里。
我下面的例程就是用32,64,128位分别实现上述代码。含C代码,没剔除。
数据是临时构建地,这几个函数执行的结果是一样。在注释行已经详解了代码。
和反汇编那段是有点区别地,是在寄存器上操作。还用了两种:1掩码,2移位来实现,
主要让人明白。方法越多,越能找到自己钟爱的。
所用指令都是最常见地,现行编译器支持地,不明白就到网上搜。
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <sstream>
#include <Windows.h>
#include <intrin.h>
#include <mmintrin.h>
#include <emmintrin.h>
using namespace std;
//不用掩码,用移位的32位数据操作
void alphatest32l(BYTE *p, int len)
{
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
cont:
mov eax, [esi];取4字节数据
shl eax,8;
shr eax,8
cmp eax, 0;检测是否存在颜色数据
jle nextstep;
or eax, 0ff000000h;有颜色数据置不透明
nextstep :
mov[esi], eax;写回源位置
add esi, 4;
sub ecx, 4;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
}
}
//用掩码的32位数据操作
void alphatest32(BYTE *p,int len)
{
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
cont:
mov eax, [esi];取4字节数据
mov edx, 000ffffffh;
and eax,edx;屏蔽a
cmp eax, 0;检测是否存在颜色数据
jle nextstep;
not edx;
or eax, edx;有颜色数据置不透明
nextstep:
mov[esi], eax;写回源位置
add esi, 4;
sub ecx, 4;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
}
}
//不用掩码,用移位的64位数据操作
void alphatest64l(BYTE *p, int len)
{
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
cont:
;取8字节数据
movq mm0, [esi];
;屏蔽a
pslld mm0, 8;
psrld mm0, 8;
;将64位数据高32位拆到mm1
pxor mm1, mm1;
punpckhdq mm1, mm0;
;移到低位,先处理高32位
psrlq mm1, 32;
movd eax, mm1;
cmp eax, 0;
jle aaaa;
;重置a
mov eax,0ff000000h;
movd mm3, eax;
psllq mm3, 32;
por mm0, mm3
aaaa:
;处理低32位,也可以不拆,直接传送低32位数据到寄存器
pxor mm1, mm1;
punpckldq mm1, mm0;
psrlq mm1, 32;
movd eax, mm1;
cmp eax, 0;
jle bbbb;
;重置a
mov eax, 0ff000000h;
movd mm3, eax;
por mm0, mm3;
bbbb:
movq[esi], mm0;
add esi, 8;
sub ecx, 8;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
emms;
}
}
//用掩码的64位数据操作
void alphatest64(BYTE *p, int len)
{
//abgr
unsigned __int64 mask = 0x00ffffff00ffffff;
unsigned __int64 mask1 = 0xff00000000000000;
unsigned __int64 mask2 = 0x00000000ff000000;
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
movq mm3, mask;
movq mm4, mask1;
movq mm5, mask2;
cont:
;取8字节数据
movq mm0, [esi];
;屏蔽a
pand mm0, mm3;mask
;将64位数据高32位拆到mm1
pxor mm1, mm1;
punpckhdq mm1, mm0;
;移到低位,先处理高32位
psrlq mm1, 32;
movd eax, mm1;
cmp eax, 0;
jle aaaa;
;重置a
por mm0, mm4;mask1
aaaa:
;处理低32位,也可以不拆,直接传送低32位数据到寄存器
pxor mm1, mm1;
punpckldq mm1, mm0;
psrlq mm1, 32;
movd eax, mm1;
cmp eax, 0;
jle bbbb;
;重置a
por mm0, mm5;mask2
bbbb:
movq[esi], mm0;
add esi, 8;
sub ecx, 8;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
emms;
}
}
//不用掩码,用移位的128位数据操作
void alphatest128l(BYTE *p, int len)
{
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
cont:
;取16字节数据
movdqu xmm0, [esi];
;屏蔽a
pslld xmm0,8
psrld xmm0,8
;将128位拆分为两个64位数
pxor xmm1, xmm1;
pxor xmm2, xmm2;
punpckhqdq xmm1, xmm0;
punpcklqdq xmm2, xmm0;
;将64位数移到低64位
psrldq xmm1, 8
psrldq xmm2, 8
;将xmm低64位移到mmx64位寄存器
movdq2q mm0, xmm1;
movdq2q mm1, xmm2;
;将mmx64位数拆到通用寄存器32位数
movd edx, mm0;
psrlq mm0, 32;
movd eax, mm0;
;
;处理32位数
;
;第1个双字
cmp eax, 0;
jle aaaa;
mov eax, 0ff000000h;
movd xmm3, eax;
pslldq xmm3, 12;
por xmm0, xmm3;
aaaa :
;第2个双字
cmp edx, 0;
jle bbbb;
mov eax, 0ff000000h;
movd xmm3, eax;
pslldq xmm3, 8;
por xmm0, xmm3;
bbbb :
;将mmx64位数拆到通用寄存器32位数
movd edx, mm1;
psrlq mm1, 32;
movd eax, mm1;
;第3个双字
cmp eax, 0;
jle cccc;
mov eax, 0ff000000h;
movd xmm3, eax;
pslldq xmm3, 4;
por xmm0, xmm3;
cccc :
;第4个双字
cmp edx, 0;
jle dddd;
mov eax, 0ff000000h;
movd xmm3, eax;
;pslld xmm3, 0;
por xmm0, xmm3;
dddd :
movdqu[esi], xmm0;
add esi, 16;
sub ecx, 16;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
emms;
}
}
//用掩码的128位数据操作
void alphatest128(BYTE *p, int len)
{
//注意:128位数据用字节描述,与字节的顺序是反地,最低字节为128位最高字节
// 128位数据 - abgr 字节 rgba
BYTE mask[16] = { 0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0x00 };
BYTE mask1[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff };
BYTE mask2[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00 };
BYTE mask3[16] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
BYTE mask4[16] = { 0x00,0x00,0x00,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 };
_asm {
;lea esi, p;
mov esi, p;
mov ecx, len;
movdqu xmm3, mask;
movdqu xmm4, mask1;
movdqu xmm5, mask2;
movdqu xmm6, mask3;
movdqu xmm7, mask4;
cont:
;取16字节数据
movdqu xmm0, [esi];
;屏蔽a
pand xmm0, xmm3;mask
;将128位拆分为两个64位数
pxor xmm1, xmm1;
pxor xmm2, xmm2;
punpckhqdq xmm1, xmm0;
punpcklqdq xmm2, xmm0;
;将64位数移到低64位
psrldq xmm1,8
psrldq xmm2,8
;将xmm低64位移到mmx64位寄存器
movdq2q mm0, xmm1;
movdq2q mm1, xmm2;
;将mmx64位数拆到通用寄存器32位数
movd edx, mm0;
psrlq mm0, 32;
movd eax, mm0;
;
;处理32位数
;
;第1个双字
cmp eax, 0;
jle aaaa;
por xmm0, xmm4;mask1
aaaa:
;第2个双字
cmp edx, 0;
jle bbbb;
por xmm0, xmm5;mask2
bbbb:
;将mmx64位数拆到通用寄存器32位数
movd edx, mm1;
psrlq mm1, 32;
movd eax, mm1;
;第3个双字
cmp eax, 0;
jle cccc;
por xmm0, xmm6;mask3
cccc:
;第4个双字
cmp edx, 0;
jle dddd;
por xmm0, xmm7;mask4
dddd:
movdqu[esi], xmm0;
add esi, 16;
sub ecx, 16;
cmp ecx, 0;
jle endt;
jmp cont;
endt:
emms;
}
}
void CAlphatest(BYTE *p, int len)
{
DWORD*pdw = (DWORD*)p;
int h = 3;
int w = 4;
for (int i = 0;i < h;i++) {
for (int j = 0;j < w;j++) {
int pos = i*w + j;
DWORD dw = pdw[pos];
if (dw > 0) {
if (dw & 0x00ffffff) dw |= 0xff000000;
}
pdw[pos] = dw;
}
}
}
void CCAlphatest(BYTE *p, UINT len)
{
DWORD*pdw = (DWORD*)p;
len /= 4;
for (UINT i = 0;i < len;i++) {
DWORD dw = pdw[ i ];
if (dw > 0) {
if (dw & 0x00ffffff) dw |= 0xff000000;
}
pdw[ i ] = dw;
}
}
int main()
{
DWORD data[] = {
RGB(255,0,0),
RGB(255,255,0),
RGB(255,255,255),
RGB(0,0,0),
RGB(0,255,0),
RGB(0,255,255),
RGB(255,255,0),
RGB(0,0,0),
RGB(128,128,0),
RGB(255,0,0),
RGB(0,0,128),
RGB(0,0,128),
};
//之前数据
int len = (sizeof data / sizeof data[0]);
cout << "before data:" << endl;
for (int i = 0;i < len;i++)
{
cout <<"0x" << setw(8)<< setfill('0') << hex <<data[ i ]<<dec<< " ";
if (i % 2 == 1) cout << endl;
}
cout << endl;
int datalen = len * sizeof(DWORD);
//这些函数需要取消注释一个一个测试,因为数据是共享地,否则就看不到效果
//alphatest32((BYTE*)data,datalen);
//alphatest64((BYTE*)data, datalen);
//alphatest128((BYTE*)data, datalen);
//CAlphatest((BYTE*)data, datalen);
//alphatest32l((BYTE*)data,datalen);
//alphatest64l((BYTE*)data, datalen);
alphatest128l((BYTE*)data, datalen);
//之后数据
cout << "after data:" << endl;
for (int i = 0;i < len;i++)
{
cout << "0x" << setw(8) << setfill('0') << hex << data[ i ] << dec << " ";
if (i % 2 == 1) cout << endl;
}
cout << endl;
system("pause");
return 0;
}
不知道看懂的有多少,看不懂就保存吧,等懂的时候再看。
通过它绝对能学会,但是学不学的会,不是我说了算。
|