CreateDIBSection and Display-Setting "Hardware acceleration"

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.
VapiSoftAsked:
Who is Participating?

Improve company productivity with a Business Account.Sign Up

x
 
Mikeh926Connect With a Mentor Commented:
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
 
VapiSoftAuthor Commented:
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
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 
mahesh1402Commented:
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
 
VapiSoftAuthor Commented:
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
 
mahesh1402Commented:
>>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
 
VapiSoftAuthor Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
VapiSoftAuthor Commented:
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
 
Mikeh926Commented:
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
 
mahesh1402Commented:
How fast something like this for you ? : http://web6.codeproject.com/tools/screen_snaper.asp  <== it uses some snaphelper library / dll

-MAHESH
0
 
VapiSoftAuthor Commented:
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
 
VapiSoftAuthor Commented:
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.