【笔记】COA课内实验-MMX指令集
前言
参考资料
关于BMP文件格式的详解
SetDIBitsToDevice函数
SetDIBitsToDevice function | Microsoft docs
BITMAPINFO structure
BITMAPINFOHEADER structure
MMX汇编指令优化
MMX指令集系列之三----数据饱和压缩与重排指令
原理学习
1. BMP-DIB位图编码
- 什么是BMP
BMP(全称Bitmap,位图)是Windows中的标准图像文件格式,其中有一类叫做设备无关位图(DIB)。
BMP文件存储数据时,图像的扫描方式是按从下到上,从左到右的顺序。
BMP文件按深度分为多类,如16色,256色,24位,32位,以下均按32位位图。
BMP文件编码依次为:位图文件头+位图信息头+调色板+数据区。(32位位图没有调色板) - 位图信息编码
仅列举需要用到的编码,单位为字节(8位)
0x02-0x05 表示整个文件的大小。(注意要把每个区域按字节倒过来读,即0x05,0x04,0x03,0x02,下同)
0x0A-0x0D 表示从文件开始到数据区的偏移量
0x12-0x15 位图宽度(单位为像素,下同)
0x16-0x19 位图高度
0x1C-0x1D 像素位数,24位即0x18
0x22-0x25 数据区的大小 - 位图数据编码
一般从0x36开始。
32位位图一个像素正好需要四个字节,从左到右4个字节分别是BGRA,即蓝,绿,红,透明。
32位位图不需要强制对齐,因为它本身就四字节对齐。
2. 绘图API
- GetDC function
HDC GetDC(HWND hWnd
);
得到一个DeviceContext句柄对象,可以在上面画像素,调用时输入null即可。
- SetDIBitsToDevice function
使用来自图片的颜色数据来设置目标设备矩形区域上的像素
int SetDIBitsToDevice(HDC hdc, //目标区域句柄int xDest, //目标区域左上角的横坐标int yDest, //目标区域左上角的纵坐标DWORD w, //图片宽度DWORD h, //图片高度int xSrc, //图片左下角的横坐标int ySrc, //图片左下角的纵坐标UINT StartScan, //扫描线开始的位置UINT cLines, //扫描线个数const VOID *lpvBits, //指向位图数据部分的指针,一般为位图首地址+0x36const BITMAPINFO *lpbmi, //指向位图信息头部分的指针,一般为位图首地址+0x0eUINT ColorUse //表明颜色板种类,可选的有DIB_PAL_COLORS(16位颜色索引),DIB_RGB_COLORS(RGB逐字颜色)
);
- BITMAPINFO 数据结构
内部还有一个BITMAPFILEHEADER数据结构,可以获得一些位图的信息,包括
info->bmiHeader.biWidth, //位图宽度
info->bmiHeader.biHeight, //位图高度
info->bmiHeader.biBitCount, //颜色位数
info->bmiHeader.biSizeImage, //实际占用的字节数,注意这里会考虑字节对齐
- 图片文件的读取
我自己手写的函数,别问,问就是查文档。
char* readpic(const char *filename)
{HFILE pic = _lopen(filename, OF_READ);int size = GetFileSize((HANDLE)pic, NULL);char *buf = (char*)malloc(size);_lread(pic, buf, size); _lclose(pic);return buf;
}
返回值buf即为图片在内存中的首地址,记得要释放它。
3. 淡入淡出原理
使用一张全黑图片A和一张待显示的图片B,显示度fade表示每个点的像素颜色 = A*(1-fade)+B*fade。让fade从0变化到1即可实现淡入效果,淡出同理。
简单来说,需要把每个点的像素组合起来,对每个字节进行上边的运算。
4. MMX
MMX采用处理器的80位的浮点寄存器的低64位作为MMX寄存器,一共有8个,从mm0到mm7,因为是“借用”浮点寄存器的低64位所以每次在用完MMX指令后一定要用EMMS指令将寄存器清空,MMX主要是针对整数运算进行优化,一个64位的MMX寄存器可以同时存入8个8位或者4个16位的整数,估计一次性就可以完成8次8位运算或者4次16位运算,要注意的MMX指令不能直接对32位数进行2次运算,但可以把32位拆分成两个16位再进行运算。MMX技术还有一个非常有用的特性是饱和运算,比如两个8位数相加:128+129相加后很明显超过了8位的最大值256,但是进行饱和运算相加的结果将是最大值256,饱和运算将运算结果控制在相应位数的范围内。
MMX指令集的优势在于,它可以对64位的寄存器的每16位并行计算,只需要一个时钟周期。
指令集不列举了,可以查看参考资料。
项目代码
完整的项目文件可以直接从我的github上下载(记得点个star)。下面是核心代码:
编译环境是MSVC,可以直接用VS或者VC,也可以参考【笔记】C++独立MSVC编译配置(命令行+sublime)进行配置。
#include <windows.h>
#include <stdio.h>const char *filename[] = {"../pic/black-1920-1080-32.bmp","../pic/back-1920-1080-32.bmp"
};
const int WIDTH = 1920, HEIGHT = 1080, BITS = 32;
int filesize;BYTE *readpic(const char *filename)
{HFILE pic = _lopen(filename, OF_READ);filesize = GetFileSize((HANDLE)pic, NULL);BYTE *buf = (BYTE*)malloc(filesize);_lread(pic, buf, filesize); _lclose(pic);return buf;
}void n_mmx(BYTE *p1, BYTE *p2, BYTE *ptar, int size, int fade)
{while(size--){int res = (*p2) - (*p1);res = (res * fade) >> 8; // p2*fade/256 - p1*fade/256res += *p1; // p2*fade/256 + p1*(1-fade/256)*ptar = res;++p1, ++p2, ++ptar;}
}void y_mmx(BYTE *pic1,BYTE *pic2,BYTE *pic,int size,int fade)
{size /= 4;__int32 *p1 = (__int32*)(pic1);__int32 *p2 = (__int32*)(pic2);__int32 *ptar = (__int32*)(pic);__int16 fade1[4] = {255-fade, 255-fade, 255-fade, 255-fade};__int16 fade2[4] = {fade, fade, fade, fade};_asm {movq mm3, [fade1]; // 00RR 00RR 00RR 00RRmovq mm4, [fade2];}/* 不能先减再乘除,可能产生负数 */for (unsigned int i = 0; i < size; ++i){__asm{pxor mm0, mm0 // 清除mm0//将所需数据移入寄存器mov esi, p1 mov edx, p2 mov edi, ptarmovd mm1, [esi] // UUUU UUUU XXXX XXXXmovd mm2, [edx] // UUUU UUUU YYYY YYYY//将mm1和mm2解开,构成 00XX 00XX 00XX 00XX形式punpcklbw mm1, mm0 // 00XX 00XX 00XX 00XXpunpcklbw mm2, mm0 // 00YY 00YY 00YY 00YYpmullw mm1, mm3pmullw mm2, mm4paddw mm1, mm2 // (p1*(255-fade) + p2*fade) psrlw mm1, 8 // 00ZZ 00ZZ 00ZZ 00ZZpackuswb mm1, mm0 // 0000 0000 ZZZZ ZZZZ//将结果传回目标位置movd [edi], mm1}++p1, ++p2, ++ptar;}_asm EMMS
}int main(void)
{BYTE *buf1 = readpic(filename[0]), *buf2 = readpic(filename[1]);BYTE *buf = (BYTE*)malloc(filesize);HDC hdc = GetDC(NULL);BITMAPINFO *info = (BITMAPINFO*)(buf + 0x0e);for(int mmx=0;mmx<2;++mmx){memcpy(buf,buf1,filesize);DWORD start_time = GetTickCount();for(int step=-50;step<556;step+=2) //图一到图二,图二到图一{int fade;if(step<0) fade = 0;else if(step>=300) fade = 555 - step;else if(step>=256) fade = 256;else fade = step;if(mmx) y_mmx(buf1+0x36, buf2+0x36, buf+0x36, info->bmiHeader.biSizeImage, fade );else n_mmx(buf1+0x36, buf2+0x36, buf+0x36, info->bmiHeader.biSizeImage, fade );SetDIBitsToDevice(hdc,0, 0, WIDTH, HEIGHT, /* 目标区域左上角坐标,图片长宽 */0, 0, 0, HEIGHT, /* 图片左下角坐标,开始行数,有效行数 */buf + 0x36, info, DIB_RGB_COLORS);}DWORD end_time = GetTickCount();printf("%s method spend %d ms.\n",mmx?"MMX":"Normal",(end_time - start_time)); //输出运行时间}ReleaseDC(NULL, hdc);free(buf1), free(buf2), free(buf);return 0;
}
【笔记】COA课内实验-MMX指令集相关推荐
- 【数据库系统原理】数据库课内实验
说明:这是武汉理工大学计算机学院[数据库系统原理]课程课内实验. >>点击查看武汉理工大学计算机专业课程资料汇总 >>点击查看WUTer计算机专业实验汇总 谨记:纸上得来终觉浅 ...
- 武汉理工大学操作系统 课内实验
文章目录 前言 主要仪器设备及耗材 一.动态分区管理 实验内容描述 实验基本原理与设计 二.磁盘调度 实验内容描述 实验基本原理与设计 总结 前言 操作系统课内实验有两个,验收的学姐人贼好,只看了验收 ...
- 武汉理工大学数值分析课内实验
文章目录 前言 主要仪器设备及耗材 一.用C语言实现几个多项式插值的程序.(Lagrange插值.Newton插值) 实验内容描述 实验基本原理与设计 分析与设计 实验结果 二.用C语言实现几个求常微 ...
- webservice-UML课内实验报告实验三
1.webservice 现将网上关于webservice的讲解提炼出来,通过一个最简单使用并且方便的例子,告诉大家什么是webservice. 简单来说,webservice就是远程调用技术,也叫X ...
- 计算机组成与结构课内实验:16位模型机的设计
我们当时是有两个实验的.一个是计组课内的实验:16位模型机的设计.还有一个是计组的最终大课设:计算机组成与结构综合实验,另一篇文章我将给出综合实验的报告 第一个是课内的设计实验: 引言 1.1 设计目 ...
- 计算机组成原理课内实验,【计算机基础论文】计算机组成原理课程实验教学改革(共2885字)...
摘要:目前<计算机组成原理>的实验内容存在与课程定位目标相悖的问题,一味追求实验内容的复杂性,而忽视了计算机组成原理实验教学的完整性和概念性.针对上述问题,本文对<计算机组成原理&g ...
- 课内实验记录|信用卡号的合法性检查
题目要求 (附加题6.31 信用卡号的合法性,可选做) 信用卡号遵循下面的模式.一个信用卡号必须是13-16位的整数.它的开头必须是: 4,指visa卡 5,指master卡 37,指American ...
- 转载自---课内实验记录|信用卡号的合法性检查 2019年05月05日 21:37:45 @退堂鼓一级演员
题目要求 (附加题6.31 信用卡号的合法性,可选做) 信用卡号遵循下面的模式.一个信用卡号必须是13-16位的整数.它的开头必须是: 4,指visa卡 5,指master卡 37,指American ...
- 计算机网络基础课内实验报告答案,计算机网络基础课内实验报告-20210418131414.docx-原创力文档...
<计算机网络基础>课内实验 学部:经济与管理学院 专业:市场营销(网络营销) 班级: 学号 : 姓名 : 指导教师 :唐芳萍 2016年 6月 21日 实验一 用双绞线制作网线(3 课时) ...
最新文章
- The 2014 ACM-ICPC Asia Mudanjiang Regional First Round C
- 初识【jQuery】,入门必看!
- uml+oopc嵌入式c语言开发精讲_新的程序开发模式出现,传统的嵌入式C语言程序员快要灭绝了?...
- 数据分析Power BI数据建模教程(三)——如何优化数据模型
- objective-c block 讲解
- Google Cloud资源层级, IAM Identity and Access Management, 控制台云交互
- 汇编环境搭建 Windows10 VS2019 MASM32
- DirectX修复工具(DirectX Repair)修复工具V4.0增强版
- 南京工程学院《DSP技术及应用》期末试卷
- 智能优化算法——布谷鸟搜索算法原理(附代码)
- 自己动手修理单击变双击的鼠标
- 上海交通大学2004年数学分析考研试题
- 苹果电脑 / Mac 开机密码忘记了应该如何操作?
- GoLand No Tests Were Run : 不能使用 fmt.Printf() BUG
- UE5笔记【四】UE5主材质Master Materials和材质实例MI
- 全球及中国雾化铜基粉末行业运营状况与发展动态分析报告2022-2028年
- 【译学】数据分析手册学习01: 导言、学习目标、指导原则
- sim卡没坏但苹果手机无服务_苹果6sp无服务信号不好解决办法
- fedora下载工具
- 修改win7开机登陆界面背景图片