Advertisement

I've got a couple choke points in my program

Started by November 22, 2004 03:56 AM
11 comments, last by Steve132 20 years ago
I'm creating a virtual desktop program, like the kind on Mac computers. Basically, I hold the windows key and hit either left or right and the entire desktop rotates to reveal another desktop with completely different window space. I have the entire program created, and it works quite well except for a few little things. The way the program works, is when it first loads it creates a window and intializes OpenGL and everything. When the user hits the hotkey, the program takes a screenshot and uses TexSubImage2D to stick it in a texture real quick. Then it shows the window and draws a little animation. Choke 1: SOLVED From ShowWindow and the first SwapBuffers call, the screen flickers while the blank window is shown. Is there anyway I can make it not draw the window until I call SwapBuffers? I've even tried drawing to the back buffer, and calling ShowWindow immediately before SwapBuffers... but there's still an annoying flicker. How I solved it: I set hbrBackground to NULL, and instead of using ShowWindow(hWnd, SW_SHOW) - I used SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOREDRAW) Choke 2: SOLVED When it goes to get a screenshot I call BitBlt from 0, 0 to the edges of the screen... and it hangs up a little bit while it's taking the screen. I don't think there's anyway I can speed that up, but if anyone can think of a way to grab a screenshot and put it into a texture very fast, let me know. Edit: Ok, I have almost solved #2 as well. Right before the BitBlt and TexSubImage2D I set my thread's priority to THREAD_PRIORITY_TIME_CRITICAL and my process's priority to REALTIME_PRIORITY_CLASS. Even with that, though, it still takes almost a full second to get the screenshot from the screen to a texture. It looks like an alternate method is the only way to go... which I can't think of any right now. This is what I'm doing right now: Mipmaped textures take too long to build, so I'm just using an oversized texture. I get the closest base power of 2 dimensions from their resolution. Example: If they're running 640x480, I make a 1024x512 texture. Then I create a DIBitmap of that same size. I do all this at load time, so everything is generated when it comes time to get a screeshot. Then when I need to dump the current screenshot to one of my texture, I call BitBlt, and TexSubImage2D. TexSubImage2D runs very fast, but BitBlt is taking way too long. Edit 2, How I solved it: GL_TEXTURE_RECTANGLE_EXT instead of GL_TEXTURE_2D. GL_TEXTURE_RECTANGLE_EXT allows for bitmaps that aren't base powers of 2, with no mipmapping required. Since my bitmap is now the same size and color depth as the desktop, BitBlt doesn't need to convert anything. Everyone, research GL_TEXTURE_RECTANGLE_EXT... it is amazing. glTexCoord2D uses pixels instead of something from 0 to 1. Quite cool. [Edited by - LlamaGuy on November 23, 2004 1:04:51 AM]
#1. Are you using doubble buffering?
Advertisement
Quote: Original post by lc_overlord
#1. Are you using doubble buffering?


...yes.
I'm still not quite clear as to what you're program does but I think there might be a way around bitblt. Can you explain a bit more (or perhaps post the program)?

Cheers,
llvllatrix
Quote: Original post by llvllatrix
I'm still not quite clear as to what you're program does but I think there might be a way around bitblt. Can you explain a bit more (or perhaps post the program)?

Cheers,
llvllatrix


I would post the program, but I haven't tested enough and I don't think it would work on other systems quite yet. Basically what the program does is give you more screen space, it gives you "virtual desktops." Each virtual desktop will have programs running on it independently. So if your screen gets cluttered, you can hit the key and go to another virtual desktop to load up more windows. Then you can jump back and forth in between each desktop at will.

Of course, it's no fun to have a new desktop just appear - so I put a little animation in. It makes it look as if your entire screen rotates to reveal another desktop on the other side of a cube. When the user hits the hot key, it takes a screenshot using BitBlt to a DIBitmap, and then uses TexSubImage2D to get the screenshot into OpenGL. This is mainly where the program lags. It takes too much time to BitBlt the entire screen to a DIBitmap.

What this boils down to: I need a very fast method to get a screenshot of the entire desktop into an OpenGL texture. BitBlt is lagging me up.

Here's a couple of screenshots if you still can't visualize what I'm doing with the program:
http://img120.exs.cx/img120/2791/sc1.jpg
http://img120.exs.cx/img120/1580/sc2.jpg

[Edited by - LlamaGuy on November 22, 2004 6:31:13 PM]
I could be wrong, but as your program window opens and creates the opengl window, the framebuffer is still filled with the desktop underneath the window as long as you havent swapped the buffers yet. I *think* you might be able to use this to your advantage. the BitBlt screenshot probably takes so long because you are transferring from hardware AGP memory into software, resizing in software, and then uploading back to agp with openGL.

because of the fact that the buffers do not clear themselves until you tell them to with a call to glClear or SwapBuffers(HDC), you MAY be able to very quickly copy the desktop framebuffer to an opengl texture by creating your window, making sure not to clear the framebuffer on the init, and then making a new opengl texture and calling glCopyTexImage2D to copy the frame buffer current contents into an OpenGL texture. then clear and continue with your OpenGL animation. That is what I would try if I were you, but then again, I cant guaruntee that it works
Advertisement
Quote: Original post by Steve132
I could be wrong, but as your program window opens and creates the opengl window, the framebuffer is still filled with the desktop underneath the window as long as you havent swapped the buffers yet. I *think* you might be able to use this to your advantage. the BitBlt screenshot probably takes so long because you are transferring from hardware AGP memory into software, resizing in software, and then uploading back to agp with openGL.

because of the fact that the buffers do not clear themselves until you tell them to with a call to glClear or SwapBuffers(HDC), you MAY be able to very quickly copy the desktop framebuffer to an opengl texture by creating your window, making sure not to clear the framebuffer on the init, and then making a new opengl texture and calling glCopyTexImage2D to copy the frame buffer current contents into an OpenGL texture. then clear and continue with your OpenGL animation. That is what I would try if I were you, but then again, I cant guaruntee that it works


No sir, the desktop beneath is not on the frame buffer at all. When you show your window and don't clear or swap the buffers, the reason you see your desktop is because nothing has been drawn over it yet. If you were to create a GL window and swap the buffers twice, you wouldn't be left with your desktop again - you'd be left with a color pattern of random static.

You say "The BitBlt screenshot probably takes so long because you are transferring from hardware AGP memory into software, resizing in software, and then uploading back to agp with openGL." which is not the case. I'm fairly sure Windows GDI doesn't use much hardware to draw its graphics. It draws all the windows to a buffer in ram, and then just displays that buffer. So the BitBlt is actually copying from RAM to RAM to AGP. The RAM -> AGP transfer is nothing, there's practically no overhead on that (glTexSubImage2D), but the RAM -> RAM transfer takes a long time (BitBlt).

I'm not streching the bits at all. I'm copying them into an oversized texture, and then only displaying part of the texture on the quad.

What I need to find is someway to bypass the BitBlt and just be able to pass a pointer to the desktop DC's data... but the Desktop isn't a DIBitmap.

Edit: Now that I think about it, that wouldn't work - because the desktop won't be a base power of 2. The only way to get around the power 2 rule is with mipmapping, which takes even longer than BitBlt.

The only other solution I can think of is to have a thread running alongside my program constantly caching the screen. It would have to keep track of areas that are changing, and areas that aren't. I would have to constantly BitBlt little tiny areas over time so the user wouldn't notice any performance difference. Then when it comes time to get a screenshot, I wouldn't have as much to BitBlt. But that algorithm is going to be a lot of work.
Quote:
Steve132's sig:
Yay! Sorta funny, but I am probably the only person on earth who wrote a 3D driving game prior to actually driving :)


Nope. thats quite common. I'm one.


As for the point of this post, this may be of use. Or then again may not.
well, I tried at least :) like I said, I didn't know if it would work, I was only trying to come up with some creative solutions to help you.

I came up with something else... this may be no better than what you are doing, but can you do something like
HDC DesktopDC;HBITMAP hBmp;hBmp = GetCurrentObject(DesktopDC,OBJ_BITMAP);CBitmap B;B.FromHandle(hBmp);BITMAP V;V.GetBitmap(&V);glTexImage() //with V.bmBits and GL_BGR_EXT


if not, what the hell, I might as well have tried again :)
and Riptorn: Cool! I didn't even know that! how old are you?
Quote: Original post by Steve132
well, I tried at least :) like I said, I didn't know if it would work, I was only trying to come up with some creative solutions to help you.

I came up with something else... this may be no better than what you are doing, but can you do something like
HDC DesktopDC;HBITMAP hBmp;hBmp = GetCurrentObject(DesktopDC,OBJ_BITMAP);CBitmap B;B.FromHandle(hBmp);BITMAP V;V.GetBitmap(&V);glTexImage() //with V.bmBits and GL_BGR_EXT


if not, what the hell, I might as well have tried again :)
and Riptorn: Cool! I didn't even know that! how old are you?


I tried something similar, without the MFC classes... and I couldn't get it to work. When it OpenGL goes to make a texture out of the data it screws up. What I think is happening is is that Windows is using CMYK color, and OpenGL is using RGB which don't interact well. I get a texture, and I can see my windows... kind of. But everything is scrambled. If there is anyway I could get OpenGL to use CMYK color, or Windows to use RGB color I would be set. The whole CMYK\RGB conflict is why I have to BitBlt to a DIBitmap.

This topic is closed to new replies.

Advertisement