CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 17
  1. #1
    Join Date
    Apr 2014
    Posts
    10

    Slow performances using Bitmap/GDI

    Hi.
    I am trying to do this:

    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
    }

    I have it working but the best i could get is 18 iteration (screenshots) per second.
    I need much more and i would like to ask you to help me improve that.

    This is what i do:

    Code:
        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 == oResizeImage.LockBits(&rect, Gdiplus::ImageLockModeRead , oResizeImage.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++;
        			}
        			oResizeImage.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
        	}

  2. #2
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: Slow performances using Bitmap/GDI

    You can replace the for loop with memcpy(). See http://msdn.microsoft.com/en-us/library/dswaw1wk.aspx
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  3. #3
    Join Date
    Apr 2014
    Posts
    10

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by 2kaud View Post
    You can replace the for loop with memcpy(). See http://msdn.microsoft.com/en-us/library/dswaw1wk.aspx

    Thanks but the 4 loop is not the problem.
    Here is the timing of each peace of the code:

    If we look at the while part then it runs 18 times a second. If i remove all the code in the while and leave only the BitBlt call then i get 300 loops per second. If I add the Bitmap oOrgDesktopImage(mhCompatibleBitmap, NULL); i get 160 loops a second. If i add the moGraphics->DrawImage(&oOrgDesktopImage, 0, 0, 1200, 900) call i get 19 loops per second. Adding the rest of the code (the for loop) reduce it to 18 loops

  4. #4
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Slow performances using Bitmap/GDI

    This is inherent of the Windows display system. It isn't at all optimized for live capture. This is because it isn't ever actually available as a buffer, instead it's the desktop composition that "composes" the desktop from subimages. If you want to capture, the composition has to be done in a secondary screen buffer (typically in memory via software) which will slow down the entire PC (it's not just the capture that's slow), this is true even if you're only reading 1 pixel.


    Possible ways out:
    1) Invest in a heavy duty videocard that allows fast software capture. Note that will typically be a videocard that won't be doing 3D all that well.
    2) Write your own videodriver, and capture at the end of the composition chain (and then optionally send to the actual screen).
    3) if on Windows vista or above: Disable Windows desktop composition. This will disable several windows desktop features, and some of the newer propgrams won't like it at all.
    4) Don't capture the entire screen, capture only a single window. Assuming the window doesn't heavily rely on transparencies and you ARE using desktop composition, this will remove the slowdown entirely. This won't work for windows with DirectX content, which is only composed at the end.
    5) there are devices to capture the VGA or HDMI output of your videocard at full framerate. Depending on situation, this might be dependant on DRM. They aren't too expensive, and it's technically the best solution for full speed/full frame capture.
    6) really cheap alternative to 5. get a VGA-RGB(A) cable and use an external recording device (this'll remove sharpness)

  5. #5
    Join Date
    Apr 2014
    Posts
    10

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by OReubens View Post
    This is inherent of the Windows display system. It isn't at all optimized for live capture. This is because it isn't ever actually available as a buffer, instead it's the desktop composition that "composes" the desktop from subimages. If you want to capture, the composition has to be done in a secondary screen buffer (typically in memory via software) which will slow down the entire PC (it's not just the capture that's slow), this is true even if you're only reading 1 pixel.


    Possible ways out:
    1) Invest in a heavy duty videocard that allows fast software capture. Note that will typically be a videocard that won't be doing 3D all that well.
    2) Write your own videodriver, and capture at the end of the composition chain (and then optionally send to the actual screen).
    3) if on Windows vista or above: Disable Windows desktop composition. This will disable several windows desktop features, and some of the newer propgrams won't like it at all.
    4) Don't capture the entire screen, capture only a single window. Assuming the window doesn't heavily rely on transparencies and you ARE using desktop composition, this will remove the slowdown entirely. This won't work for windows with DirectX content, which is only composed at the end.
    5) there are devices to capture the VGA or HDMI output of your videocard at full framerate. Depending on situation, this might be dependant on DRM. They aren't too expensive, and it's technically the best solution for full speed/full frame capture.
    6) really cheap alternative to 5. get a VGA-RGB(A) cable and use an external recording device (this'll remove sharpness)

    Thanks for that , but all the 6 are not practical for me since i do not control the hardware of my customer.
    And full screen is needed - not just active window.
    The question is if i am using the gdi+ right and if I can somehow optimize the code.
    Like reuse the memory buffer inside the Bitmap object so it will not be created on each loop but only overwritten ...

  6. #6
    Join Date
    Jan 2012
    Location
    India
    Posts
    193

    Re: Slow performances using Bitmap/GDI

    I am not very sure , but you can try fast graphics libraries .. I am using FastGraph .. You can discuss your need and then purchase ..
    The graphics activities become very fast .. also u can use 3d and directX if desired .

  7. #7
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Slow performances using Bitmap/GDI

    GDI+ will make things WORSE.
    GDI+ is an entirely software implementation of a higher level graphics subsystem. When Microsoft designed it, they had hoped that the videocard manufacturers would welcome the new approach, but it backfired, and to my knowledge none of the videocard manufacturers ended up making the hardware layer for the GDI+ abstraction layer so it'll remain to be in software for everything.

    That doesn't mean GDI+ is useless, it offers some very nice nifty features that allow you to create effects in an windows GUI program without having to resort to external libraries or something like DirectX. It's software, but for desktop type apps that is typically more than fast enough. Animation in GDI+ is another matter entirely

    Quote Originally Posted by JimCip12 View Post
    Like reuse the memory buffer inside the Bitmap object so it will not be created on each loop but only overwritten ...
    You can (and should) remove stuff outside of the loop even for the GDI solution.
    but this won't make a huge amount of impact. You can maybe get a few percent of extra speed, but it won't remove the inherent desktop composition issue.


    If you create even a bare bones app that reads 1 pixel from the screen, you'll notice that there's a cap to how many times you can do that per second, and you'll notice that if you have an animation app (a game, or videoplayback) that the refresh rates of those will drop considerably (to 25-50%) during the pixelreads.


    Quote Originally Posted by JimCip12 View Post
    Thanks for that , but all the 6 are not practical for me since i do not control the hardware of my customer.
    You can make 3 a requirement for your software. Even to the point where you disable desktop composition when your app closes (and restore it when it exits). But as said, Some of the newer programs are tested only on Windows systems where desktop composition is enabled and it has an impact on the interaction of the app and the display. I have seen several apps go totally bananas when DCM is disabled.
    Just note that even 3 won't be without impact. It'll still take time to capture and process the screen, and overal system performance will drop, just not as much as with DCM enabled.
    There's a couple videocards that don't really support disabled DCM and it will make little performance impact with it enabled or disabled.
    Last edited by OReubens; April 19th, 2014 at 02:48 AM.

  8. #8
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by new_2012 View Post
    I am not very sure , but you can try fast graphics libraries .. I am using FastGraph .. You can discuss your need and then purchase ..
    The graphics activities become very fast .. also u can use 3d and directX if desired .
    FastGraph is just a layer on top of GDI. It can't do anything faster than GDI, it just provides stuff GDI doesn't directly. such as image conversions and some special effects.

    It can't speed up capture.

    Similar for Direct3D, DirectX and Direct2D. They're great for specific types out graphics OUTPUT, but they aren't suited for screen capture.

  9. #9
    Join Date
    Jan 2012
    Location
    India
    Posts
    193

    Re: Slow performances using Bitmap/GDI

    Thank u OReubens sir ..

    I will keep this in mind .. I have done screen capture using FastGraph .. just a simple command and things work fine.

    Sir , In FastGraph , screen is drawn in the screen buffer all the time .. u need to update buffer to screen .. so is it possible that
    while capturing screen .. you need to save that buffer with bitmap format and thus it is faster .... ?????

    Also can we install screen capture software ? will it help ?

  10. #10
    Join Date
    Apr 2014
    Posts
    10

    Re: Slow performances using Bitmap/GDI

    Thanks for your reply.
    Quote Originally Posted by OReubens View Post
    GDI+ will make things WORSE.
    You can (and should) remove stuff outside of the loop even for the GDI solution.
    but this won't make a huge amount of impact. You can maybe get a few percent of extra speed, but it won't remove the inherent desktop composition issue.
    There is nothing left to get outside the while loop.


    Quote Originally Posted by OReubens View Post
    You can make 3 a requirement for your software.
    I did more than that. I checked the Adjust for best performance option (which automatically disable the desktop composition but it changed nothing - same loop count).

  11. #11
    Join Date
    May 2005
    Posts
    4,954

    Re: Slow performances using Bitmap/GDI

    My two (4) cents:
    1. after the BitBlt when you have the images - don't use GDI anymore. this (article) can give you some tips.
    2. You can resize and make conversion to 24 bit with simple C code in same loop! without GDI it will be faster.
    3. if is not enough you can do the conversion and resize using SSE which will give you at least factor of 2.
    4. if 3 is not enough, if you have some cores available on the cpu you can do stage 3 on more than one core.

    Cheers
    If a post helped you dont forget to "Rate This Post"

    My Article: Capturing Windows Regardless of Their Z-Order

    Cheers

  12. #12
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by new_2012 View Post
    I will keep this in mind .. I have done screen capture using FastGraph .. just a simple command and things work fine.

    Sir , In FastGraph , screen is drawn in the screen buffer all the time .. u need to update buffer to screen .. so is it possible that
    while capturing screen .. you need to save that buffer with bitmap format and thus it is faster .... ?????

    Also can we install screen capture software ? will it help ?
    FastGraph has a mode in which output is done onto a memory DC, which is then drawn in a single blit to the window DC
    it's usually done to avoid flicker or to avoid the user seeing intermediate drawing operations. For some operations this can even be considerably faster than directly to screen.

    You can capture your own Memory DC quickly, but the OP wanted to capture the whole screen.

    This means you first need to go through the window desktop composer, only then can you extract composed pixel values.
    It's this extracaction process that is slow.

    Screen capture software won't help since it too needs to do all this, EXCEPT if you have extraction software that installs a virtual videodriver (see #4, option 2) and captures it's output from there. It often means you won't see anything actually on the screen (or it'll be delayed, or it has to be a capture option built into the videodriver for the video hardware card). I know matrox has one of those (see #4, 1), but to my knowledge neither NVidea nor ATI have such option built into the driver (some models do have it as a hardware addon, see #4, 5).

  13. #13
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by golanshahar View Post
    My two (4) cents:
    1. after the BitBlt when you have the images - don't use GDI anymore. this (article) can give you some tips.
    2. You can resize and make conversion to 24 bit with simple C code in same loop! without GDI it will be faster.
    3. if is not enough you can do the conversion and resize using SSE which will give you at least factor of 2.
    4. if 3 is not enough, if you have some cores available on the cpu you can do stage 3 on more than one core.
    Depending on the videocard and driver specs, this might be faster, or it might not be. Either way, the main issue remains, it's the actual capture that's the bottleneck, you can make all the rest take 0 time, and it'll still be limited to 15-20 frames/sec.

  14. #14
    Join Date
    May 2005
    Posts
    4,954

    Re: Slow performances using Bitmap/GDI

    Quote Originally Posted by OReubens View Post
    Depending on the videocard and driver specs, this might be faster, or it might not be. Either way, the main issue remains, it's the actual capture that's the bottleneck, you can make all the rest take 0 time, and it'll still be limited to 15-20 frames/sec.
    Out of curiosity I made this quick & dirty test on my nVidia Quarto 1000m
    I wrote this sample code:
    Code:
    class CaptureDesktop{
    public:
    
    	CaptureDesktop()
    	{
    		rc;
    		hWnd = ::GetDesktopWindow();
    		::GetWindowRect (hWnd,&rc); 
    
    		Width	= rc.right-rc.left;
    		Height	= rc.bottom-rc.top;
    
    		hDC = ::GetDC(0);
    		memDC = ::CreateCompatibleDC ( hDC );
    		memBM = ::CreateCompatibleBitmap ( hDC, Width, Height );
    		OldBM = (HBITMAP)::SelectObject(memDC, memBM );
    
    		Bpp = ::GetDeviceCaps(hDC,BITSPIXEL);
    		size = Bpp/8 * ( Width * Height );
    		lpBits1	= new BYTE[size];
    	}
    	~CaptureDesktop()
    	{
    		delete [] lpBits1;
    		::SelectObject(hDC, OldBM);
    		::DeleteObject(memBM);
    		::DeleteDC(memDC);
    		::ReleaseDC( 0, hDC );
    	}
    
    	void Capture()
    	{
    		// should be called in timer/thread
    
    		::BitBlt( memDC, 0, 0, Width, Height , hDC, rc.left, rc.top , SRCCOPY );
    		::GetBitmapBits( memBM, size, lpBits1 );
    
    		// do something with lpBits1
    		
    	}
    	RECT rc;
    	HWND hWnd;
    	int Width;
    	int Height;
    	HDC hDC;
    	HDC memDC;
    	HBITMAP memBM;
    	HBITMAP OldBM;
    	int Bpp;
    	int size;
    	BYTE *lpBits1;
    
    };
    
    
    // usage:
    	CaptureDesktop cdesk;
    	float T = MyGetTickCount();
    	for (int i=0;i<100;i++)
    		cdesk.Capture();
    	float T1 = MyGetTickCount();
    	FILE *fp = fopen("c:\\time.txt","w");
    	fprintf(fp,"%.3f\r\n",(T1-T)/100.0f);
    	fclose(fp);
    I made only the capture function + getting bits without any manipulations.
    The results are ~30 milisec/ screen capture which leads roughly to 33 frames/sec (on my laptop of course )

    After doing all this I have a question to OP – why do you want to get images in that frequency? What is the goal? Why 20 frames/sec is not enough?

    Cheers
    If a post helped you dont forget to "Rate This Post"

    My Article: Capturing Windows Regardless of Their Z-Order

    Cheers

  15. #15
    Join Date
    Jan 2012
    Location
    India
    Posts
    193

    Re: Slow performances using Bitmap/GDI

    Thank you all .. I will need all this in future ..

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured