VC驿站

 找回密码
 加入驿站

QQ登录

只需一步,快速开始

搜索
查看: 450|回复: 4

这一回学会多媒体指令

[复制链接]
001
75_avatar_middle
在线会员 发表于 2019-5-26 14:57:22 | 显示全部楼层 |阅读模式
     例子还是从我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;
}

这一回学会多媒体指令  不知道看懂的有多少,看不懂就保存吧,等懂的时候再看。
              通过它绝对能学会,但是学不学的会,不是我说了算。



评分

参与人数 1驿站币 +2 热心值 +2 收起 理由
58_avatar_small 敏敏 + 2 + 2 很给力!

查看全部评分





上一篇:大家来找茬挂
下一篇:推箱子
58_avatar_middle
online_vip 发表于 2019-5-27 16:49:24 | 显示全部楼层
我有信心,如果一行代码,一行代码分析一定能学会,只是目前在搞别的方法。收藏,楼主出品,必为精华!
51_avatar_middle
online_admins 发表于 2019-5-28 01:38:46 | 显示全部楼层
网友们还真是不识货啊,这么好的文章还不回复拜读!顶起
61_avatar_middle
donate_vip 发表于 2019-5-28 09:09:00 | 显示全部楼层
这是嘛呀?,咱也不知道,咱也不敢问那!这一回学会多媒体指令
36_avatar_middle
在线会员 发表于 2019-6-8 08:29:57 | 显示全部楼层
本帖最后由 王者归来339 于 2019-6-8 08:59 编辑

加精华,应该是好贴了
您需要登录后才可以回帖 登录 | 加入驿站 qq_login

本版积分规则

关闭

站长提醒上一条 /2 下一条

QQ|小黑屋|手机版|VC驿站 ( 辽ICP备09019393号tongdun|网站地图wx_jqr

GMT+8, 2019-6-25 20:55

Powered by Discuz! X3.4

© 2009-2019 cctry.com

快速回复 返回顶部 返回列表