Optimization 使用位图/GDI的性能较慢
嗯。 我正在尝试这样做:Optimization 使用位图/GDI的性能较慢,optimization,bitmap,gdi+,Optimization,Bitmap,Gdi+,嗯。 我正在尝试这样做: while(1) { CaptureScreenshot (as BMP) Convert screenshot to 24 bit instead of 32 bit Resize screenshot size Get the BMP bits array of the resized screenshot } 我有它的工作,但我可以得到最好的是18次迭代(截图)每秒。 我需要更多,我想请你帮我改进 我就是这么做的: Start(
while(1)
{
CaptureScreenshot (as BMP)
Convert screenshot to 24 bit instead of 32 bit
Resize screenshot size
Get the BMP bits array of the resized screenshot
}
我有它的工作,但我可以得到最好的是18次迭代(截图)每秒。
我需要更多,我想请你帮我改进
我就是这么做的:
Start()
{
ULONG_PTR gdiplusToken=0;
HDC mhCompatibleDC;
HBITMAP mhCompatibleBitmap;
HWND mhDesktopWnd;
HDC mhDesktopDC;
byte*piRGB=new byte[1200*900*3]
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
mhDesktopDC = GetDC(GetDesktopWindow());
mhCompatibleDC = CreateCompatibleDC(mhDesktopDC);
mhCompatibleBitmap = CreateCompatibleBitmap(mhDesktopDC, 1440, 900);
SelectObject(mhCompatibleDC, mhCompatibleBitmap);
moResizeImage = new Bitmap(1200, 900, PixelFormat24bppRGB);
moGraphics = Gdiplus::Graphics::FromImage(moResizeImage);
//as you can see to optimize the code, i pre allocate the CompatibleDC (which speed things)
//I also use the same moGraphics and not creating moResizeImage again and again - BUT from my tests
//that does not speed things so i guess that DrawImage reallocate moResizeImage memory on each call
While(1)
{
BitBlt(mhCompatibleDC, 0, 0, 1440, 900, mhDesktopDC, 0, 0, SRCCOPY)
Bitmap oOrgDesktopImage(mhCompatibleBitmap, NULL);//here i have the original desktop image 32 bit (as my display)
moGraphics->DrawImage(&oOrgDesktopImage, 0, 0, 1200, 900);(here it converts it to 24 bit as i need and do the resize)
//now I take the bits part of the BMP and copy it to piRGB
Gdiplus::BitmapData bitmapData;
Gdiplus::Rect rect(0, 0, 1200, 900);
if (Gdiplus::Ok == moResizeImage->LockBits(&rect, Gdiplus::ImageLockModeRead , moResizeImage->GetPixelFormat(),&bitmapData))
{
int len = bitmapData.Height * std::abs(bitmapData.Stride);
for (int i = 0; i < len; i = i + 1)//18
{
*piRGB = ((BYTE*)bitmapData.Scan0)[i++];
piRGB++;
}
moResizeImage->UnlockBits(&bitmapData);
}
//here i do things with piRGB but these things are not counted it the timer so you can assume here the code ends
//as said as the code looks now, i can fill piRGB ~18 times (18loops) in 1 second. I must improve that/
//my knowledge in GDI is very poor and i hope you can provide code to your suggestions - THANKS
}
Start()
{
ULONG_PTR gdiplusToken=0;
HDC-mh相容性;
HBITMAP MH兼容EBITMAP;
HWND mhDesktopWnd;
HDC-mhdc;
字节*piRGB=新字节[1200*900*3]
GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);
mhDesktopDC=GetDC(GetDesktopWindow());
mhCompatibleDC=CreateCompatibleDC(mhDesktopDC);
mhCompatibleBitmap=CreateCompatibleBitmap(mhDesktopDC,1440900);
选择对象(mhCompatibleDC、mhCompatibleBitmap);
moResizeImage=新位图(1200、900,像素格式24bpprgb);
moGraphics=Gdiplus::Graphics::FromImage(moResizeImage);
//正如您所看到的,为了优化代码,我预先分配了CompatibleDC(这加快了速度)
//我也使用相同的图像,并不是一次又一次地创建moResizeImage,而是通过我的测试
//这并不能加快速度,所以我猜DrawImage会在每次调用时重新分配更多SizeImage内存
而(1)
{
BitBlt(mhCompatibleDC、0、0、1440、900、mhDesktopDC、0、0、SRCCOPY)
位图oOrgDesktopImage(mhCompatibleBitmap,NULL);//这里有原始桌面图像32位(作为我的显示器)
moGraphics->DrawImage(&oOrgDesktopImage,0,0,1200,900);(在这里,它根据需要将其转换为24位并调整大小)
//现在,我将BMP的位部分复制到piRGB
Gdiplus::BitmapData BitmapData;
Gdiplus::Rect Rect(0,0,1200,900);
if(Gdiplus::Ok==moResizeImage->LockBits(&rect,Gdiplus::ImageLockModeRead,moResizeImage->GetPixelFormat(),&bitmapData))
{
int len=bitmapData.Height*std::abs(bitmapData.Stride);
对于(int i=0;i解锁位(&bitmapData);
}
//在这里,我使用piRGB做一些事情,但是这些事情不计入计时器,所以您可以假设代码在这里结束
//正如代码现在看起来所说的,我可以在1秒内填充piRGB~18次(18个循环)。我必须改进这一点/
//我在GDI方面的知识非常贫乏,我希望您能为您的建议提供代码-谢谢
}
如果我们看一下while部分,那么它每秒运行18次。
如果我在while中删除所有代码并只保留
比特呼叫
然后我每秒有300个循环。
如果我加上
位图oOrgDesktopImage(mhCompatibleBitmap,NULL);
我每秒有160圈。
如果我添加moGraphics->DrawImage(&oOrgDesktopImage,0,0,1200,900)调用
我每秒有19个循环。
添加其余代码(for循环)将其减少到18个循环
Start(){
HDC mhCompatibleDC, mhDesktopDC, hdc;
HBITMAP hBitmap, hBitmapOld;
unsigned char *piRGB= NULL;
int i;
mhDesktopDC = GetDC(GetDesktopWindow());
hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
mhCompatibleDC = CreateCompatibleDC(hdc);
hBitmap = NewDIBSection(1200, 900, (void **)&piRGB);
if(hBitmap == NULL){/* Error */}
hBitmapOld = SelectObject(mhCompatibleDC, hBitmap);
//Now piRGB points to RGB data of mhCompatibleDC
DeleteDC(hdc);
//SetStretchBltMode(mhCompatibleDC, HALFTONE); //for better quality
for(i = 0; i < 200; i++){
BitBlt(mhCompatibleDC, 0, 0, 1200, 900, mhDesktopDC, 0, 0, SRCCOPY);
//StretchBlt(mhCompatibleDC, 0, 0, 1200, 900, mhDesktopDC, 0, 0, 1440, 900, SRCCOPY);
}
SelectObject(mhCompatibleDC, hBitmapOld);
DeleteDC(mhCompatibleDC);
DeleteObject(hBitmap);
ReleaseDC(GetDesktopWindow(), mhDesktopDC);
}
HBITMAP NewDIBSection(int cx, int cy, void **ppBits){
HBITMAP hbitmap = NULL;
LPBITMAPINFO lpbmi;
HDC hdc;
lpbmi = (LPBITMAPINFO)calloc(1, sizeof (BITMAPINFO) + 4 * sizeof(DWORD));
if(!lpbmi){return NULL;}
ZeroMemory(&lpbmi->bmiHeader, sizeof(BITMAPINFOHEADER));
lpbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbmi->bmiHeader.biWidth = cx;
lpbmi->bmiHeader.biHeight = -cy;
lpbmi->bmiHeader.biPlanes = 1;
lpbmi->bmiHeader.biBitCount = 24;
lpbmi->bmiHeader.biCompression = BI_RGB;
hdc = CreateIC(TEXT("DISPLAY"), NULL, NULL, NULL);
hbitmap = CreateDIBSection(hdc, lpbmi, DIB_RGB_COLORS, ppBits, NULL, 0);
DeleteDC(hdc);
free(lpbmi);
return hbitmap;
}
valter使用档案器,查看时间花在哪里。谢谢Eric,我已经编辑了问题-我在问题的末尾添加了时间使用
bitblt
可以获得300 fps的速度,这真是太奇怪了。通常,一辆桌面休闲车的速度是30-60 fps。无论如何,你在做一些多余的事情,比如你不需要oOrgDesktop图像
bitmap。您可以直接stretchblt
到mhCompatibleDC(1200x900)
然后从这个兼容的DC中获取位。在现代机器上,将数据从系统内存移到图形内存或移回图形内存通常是瓶颈。每秒可以BitBlt 300次,因为这只是将图形内存复制到图形内存中。当您尝试将所有数据移到系统内存中,以便可以使用G对其进行操作时DI+,你付出了高昂的代价。我会开始尝试减少通过图形总线移动的数据量的方法。尝试先在卡上进行大小调整和32到24位的转换,这样就可以减少数据量。嗨,瓦尔特。非常感谢你的代码。我添加了它,它改进了计时。现在1秒内有24个循环tead的18.i.E基本上StretchBlt()在一秒钟内执行24次,因为这是while循环中唯一的一行。很少有评论:1)如果我删除hdc=CreateIC(TEXT(“DISPLAY”),NULL,NULL,NULL;然后只放置hdc=NULL;那么它在同一时间运行。也就是说,至少在我的计算机上,设置hdc=CreateIC(TEXT(“DISPLAY”)没有提高时间-你知道为什么吗?除了最后一条注释(太长),2)这一行:lpbmi=(LPBITMAPINFO)calloc(1,sizeof(BITMAPINFO)+4*sizeof(DWORD))为什么+4*sizeof(DWORD)?不管怎样,我只是声明它是本地的,即BITMAPINFO obmi;它的工作原理是一样的。3)hbitmap最终需要发布吗?我在MSDN中没有发现任何提到这一点。4)你认为我能做的任何事,在一秒钟内拥有24个以上的屏幕截图-最终结果是将图像转换为YUV格式。也就是说,我真正需要的是尽可能多的以YUV格式(我已经有转换为YUV的功能)@user3547277当您使用mhCompatibleDC
(请参见编辑)时,必须在一秒钟内释放hBitmap。不幸的是,我知道没有办法使它更快,虽然我的每秒速度不是24帧,而是70帧。出于好奇,你能用bitblt
而不是StretchBlt
来测试它吗?用bitblt而不是StretchBlt,我每秒能收到700次呼叫。(我的图形卡中有点慢)例如x30更快。如果你尝试另一个高度,你的结果显示3600/360=X10,你会看到更糟糕的结果。例如,当组织图像和新图像的高度不一样时。如果运行200次代码,我会得到:BitBlt->312毫秒拉伸blt->8.5秒!@user3547277我要做的是:使用BitBlt
并用assemply a操作位ndxmm
寄存器。
BitBlt -> 368 msec
StretchBlt -> 2,5 - 3,6 sec!