Solved

CreateDIBSection and Display-Setting "Hardware acceleration"

Posted on 2006-07-06
26
677 Views
Last Modified: 2013-11-20
OK, I tried very hard to reduce the time it takes to get the DIB from the hdc.
The only way I could do it in a reasonable time (40ms) is by setting the "Hardware Acceleration" to none.
But now the video games don't work.
You suggested that there may be another way using DrawDIB functions but I could not see how I can get the DIB from the hdc, or using Direct-Show, but again I don't understand how to do it.

It is extremely important for me to solve this problem because the whole project depends on it.
0
Comment
Question by:VapiSoft
  • 13
  • 8
  • 4
26 Comments
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17056294
0
 

Author Comment

by:VapiSoft
ID: 17056885
I looked at these links and the direct-x  examples.
All of them are ways to draw faster to the screen.
There is no example in that shows how to get the DIB from the screen.
Also, please note that the rest of my code uses 8 bpp (bits per pixel) DIB.
Because I compare bitmaps and save only the differences (like PC Anywhere).
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17056988
look at 'Various methods for capturing the screen'
http://www.codeproject.com/dialog/screencap.asp#And%20The%20DirectX%20way%20of%20doing%20it%20: <== The DirectX way of doing it

-MAHESH
0
 

Author Comment

by:VapiSoft
ID: 17057240
I read it and it seems to have the same problem. He says that GetFrontBuffer() is slow and to fix it we need to set the "Hardware acceleration" to None.
For me it has two more limitations.
1. The user must have "Media 9.0 SDK" installed.
2. He does not show how to transfer the bitmap to a 8bpp DIB (which is my main problem).
0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17057267
>>1. The user must have "Media 9.0 SDK" installed.

thats for if you are capturing the screen using Windows Media API .. for capturing screen using DirectX you dont need Media SDK..

Have you looked at DrawDib samples ?

-MAHESH
0
 

Author Comment

by:VapiSoft
ID: 17057388
I looked but I did not understand how to get the DIB from the screen using DrawDib.
Do you know of any sample that does it?
0
 

Author Comment

by:VapiSoft
ID: 17057415
Is there any way to ask aomeone in Microsoft if there is an undocumented API  to set the "Hardware Acceleration" to none just for one operation (the BitBlt). It seems like it is something very useful and will solve the problem.
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17057768
Setting hardware accelleration to none determines which calls get sent to the display driver and which are emulated by the gdi. What's probably happening is that your call to get the screen image is going to the display driver and it contains very inefficient code for copying and converting the format of the screen to an 8bbp DIB.

Try doing it in a few intermediate steps instead. First BitBlt from the screen hdc to a temporary bitmap (created with CreateBitmap - but in the same format as the screen). Then copy this bitmap to your 8bpp DIB.

0
 

Author Comment

by:VapiSoft
ID: 17058086
I tried it, it does not help (it does improve the time but it is still to much)
The problem now is not the DIB and the 8bpps, because the time is wasted on the first BitBlt

      HDC memDC   =CreateCompatibleDC(hdc);
 HBITMAP hbmp=CreateCompatibleBitmap(hdc, wr.cx, wr.cy);
      DWORD t3=GetTickCount();
 HBITMAP oldBmp=(HBITMAP) SelectObject(memDC,hbmp);
      DWORD t31=GetTickCount();
 BitBlt(memDC,0,0, wr.cx, wr.cy, hdc, x_offset, y_offset, SRCCOPY); <===== This takes 400ms
      DWORD t32=GetTickCount();

      HDC memDC1  =CreateCompatibleDC(memDC);
      HBITMAP hbmp1=getDIBS(memDC, wr.cx, wr.cy); // //
 BitBlt(memDC1,0,0, wr.cx, wr.cy, hdc, 0, 0, SRCCOPY);

      DWORD t4=GetTickCount();

 msg->hDIB=getPictureHandle(hbmp,memDC,wr.cy,wr.cx,msg->pixels);
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17059333
So the underlying problem is that reading from video memory on the video card is very slow. This is because of two factors, one is that reading from the video ram chips is slow, and the other is that it relies on the code in the display driver to do it, and this probably is not optimised to read from the video ram because this is not a very common operation.

With hardware acceleration turned on, the gdi has to call the video driver to read back from video memory because the format of data in video ram is entierly up to the driver. It has to use the DrvBitBlt routine in the display driver.

When you set hardware acceleration to zero, I believe that the GDI dramatically simplifies how it uses the display driver. Basically it double buffers all of the screen output so that it only ever copies to video ram. If you BitBlt from the screen it is able to copy from it's off screen surface, bypassing the video driver altogether. Most modern video cards are optimised for 3D, so 2D GDI drawing is not very optimial, and in most cases it's quicker to work with bitmaps in main memory than on the video card.

You might find that you get competely different timings if you try a different video card/driver.

Have you tried using any other routines to get the bitmap data, like GetDIBits()?

What you really need is a copy of the screen in main memory that you can access, without having to call the video driver. One way to do this would be to write a display mirror driver, and simply mirror all of the video output to an off screen surface (and you could possible do your format conversion to 8bpp at the same time). This would be fairly straightforward if you are familier with video drivers, but would require administrator priviledges to install such a mirror driver.

Another way you could explore is to see what happenes if you have a layered semi-transparent window on the screen. The presence of layered windows alters how XP composes the desktop (it starts working more like Vista) so might dramatically affect your timings.


0
 

Author Comment

by:VapiSoft
ID: 17065980
I use GetDIBits after I do the BitBlt to get the pixels.
If I could lno how "PC Anywhere" captures the screen I will have the answer how to do it.

I did not understand the last part with "layered semi-transparent window".
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17071482
PC Anyware chains the display driver DLL. This involves replacing the display driver with their own module that pretends to be the display driver. This captures all of the display output and also calls through to the original display driver so that the display still works. This technique is not supported by MS, however it is used by a number of people, including some Accessibility Aids. See http://msdn.microsoft.com/library/en-us/dnacc/html/atg_driverchain.asp

A layered window is a type of semi-transparent window you can create in XP.
See http://www.msdn.microsoft.com/library/techart/layerwin.htm

The point is that when layered windows are used, the GDI double buffers the content of the screen so it _might_ have a copy of the display in main memory. This means that BitBlt's from video ram may be quicker (although I haven't tried this).

Mike.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:VapiSoft
ID: 17073022
I tried it (the layered window) and although it is much faster (20-30 ms) I receive only a white bitmap (with a blue caption).
It is interesting that I had to set the ALPHA paramter to 0 otherwise I don't get any mouse-clicks.
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17073089
Ok, so when you bitblt from the screen, it's actually giving you a copy of your layered window! How bizarre.. Are you trying to capture the whole screen or a specific application window?
0
 

Author Comment

by:VapiSoft
ID: 17073234
What I need are specific windows (that some time are full screen).
It could have been a good solution because I can cut the rectangle.

I don't understand why BitBlt from the layered-window dc was so fast, but from any other window (including the desktop window) is so slow.

I am sure that there is a way to do it, or that there is an API to change the "Hardware Accelaration" on the fly.
0
 
LVL 3

Accepted Solution

by:
Mikeh926 earned 500 total points
ID: 17073325
Ok, so we know that layered windows are faster, so if you just want to bitblt from a specific window then get the bits from the dc associated with that window instead of the desktop. Call GetDC() to get a dc for the hwnd you are interested in and call GetDIBits or BitBlt with that DC. That should give you direct access to the bits in the off-screen surface representing that window.

Instead of creating a layered window and sticking it over the top, could you change the attributes of the window you want to grab to a layered window and set it's transparency to opaque?

0
 

Author Comment

by:VapiSoft
ID: 17073438
I dont understand the connection between the two parts.
The first part is exactly what I do:

 HDC hdc=GetWindowDC(hwnd);
 HBITMAP hbmp=CreateCompatibleBitmap(hdc, wr.cx, wr.cy);
 HBITMAP oldBmp=(HBITMAP) SelectObject(memDC,hbmp);
 BitBlt(memDC,0,0, wr.cx, wr.cy, hdc, x_offset, y_offset, SRCCOPY); <== this whre it takes 400ms
 msg->hDIB=getPictureHandle(hbmp,memDC,wr.cy,wr.cx,msg->pixels); <== here I do the GetDIBits from the hbmp

What do you mean: set it's transparency to opaque
These are any application's windows.
Please note that these are not my windows.

0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17073546
Yes, I know it's not your window, but that doesn't stop you modifying them because there is no security on window handles

Call SetLayeredWindowAttribute on the hwnd you want to capture and set it to an opacity of 255. Then see if your capture code goes any quicker.
0
 

Author Comment

by:VapiSoft
ID: 17073847
No it is even worse, When I set the SetLayeredWindowAttribute the whole desktop is blinkin, the window disapear, then the desktop becomes black and then it comes back OK.
The whold process takes about 800ms, but then the BitBlt takes 20 ms.
So probaly it could have worked.
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17073937
Yes but you only have to call SetLayeredWindowAttribute for a given hwnd once. Once the GDI has switched to layered mode you can BitBlt as many times as you like to capture the changing window contents.

0
 

Author Comment

by:VapiSoft
ID: 17074043
You are right, but I cannot have this scenario in my application.
No body will use it if it flickers like that every time he opens a new window.
My application should be used in the background without affecting the user's experience.
See vLog in www.vapisoft.com.
0
 
LVL 3

Expert Comment

by:Mikeh926
ID: 17079626
Ok, but it would be ok if it flickered just once when you start your app? What if you created a single transparent overlapped window that covered the entire desktop and put it as always on top? If you set the attributes correctly it should allow mouse and focus through. This may automatically cause every other window to be composed differently and speed up your bitblt's.

Your only other practical alternative is to write a mirror display driver. This could render all desktop output to your own bitmap in main memory so you could take a copy of it as and when you like without the overhead of reading video ram. This would also have the advantage of not causing any nasty visual effects, although you might run into difficulties if the user has multiple-monitors.

0
 
LVL 22

Expert Comment

by:mahesh1402
ID: 17079676
How fast something like this for you ? : http://web6.codeproject.com/tools/screen_snaper.asp  <== it uses some snaphelper library / dll

-MAHESH
0
 

Author Comment

by:VapiSoft
ID: 17080460
I looked at it. It looks fast enougth but I did not understand how it works (what functions calls should I call).
I will continue to look at it.
Also, it uses SnaperHelper.lib, but I could not the corresponding SnaperHelper.dll
It does work, but where is the DLL.

Also, regarding the layered window.
1. I tried to set the Desktopwindow as layered window, but for some reason, it did not change the time (400 ms).
Why?, when I did the same thing to a regular window the time (of the BitBlt was 10-20 ms).

I did not understand what you said about the "window that will cober the entire desktop" this is what I did in the first step (when you suggested the layered window). In any case if alpha is not 0 (even 1) mouse clicks and focus do not get through.

About display driver, it is to risky and complecated to play with.
0
 

Author Comment

by:VapiSoft
ID: 17088167
I manage to work with the SnaperHelper and it does not help.
First, when I click (even without my program) it takes a lot of time so it orobably has the same problem.
The second thing is that it is an application with its own User-Intercae and therefore canot be used with my
application.
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Replacement selected text 2 47
Expand to include initial dialog with two choices. 9 59
fizzArray2 challenge 1 56
Change to event 1 73
Here is how to use MFC's automatic Radio Button handling in your dialog boxes and forms.  Beginner programmers usually start with a OnClick handler for each radio button and that's just not the right way to go.  MFC has a very cool system for handli…
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now