PDA

View Full Version : GDI lag problem (nvidia thing ?)



bpeers
08-07-2002, 06:54 AM
Hi, I've brought this up in the past but couldn't find a complete solution.. and it's about time I find a definite fix or else it looks like management might press me into ditching OGL altogether and go with D3D :\

The difficulty is getting Win32 GDI and OGL to get along nicely.

I'm drawing GDI stuff over a double buffered OGL window. Singlebuffering is not an option, neither is rendering to a bitmap via software, and neither is reimplementing half the GDI to go via OGL.

What happens, apparently only on NVidia (but I'm not 100% sure), is that the GDI is drawn before the swapbuffer is finished. So, some parts of the GDI are drawn, others are not.

The problem is almost completely gone if I add a sleep (50 msecs) between the Swapbuffers and the GDI calls -- clearly suggesting a timing issue.

What really bugs me though is that I can't always do this. When a user closes a menu (so it nicely alpha-fades out, you know the win2k stuff) or does other things that cause win32 to draw GDI over the OGL backdrop, the image becomes wrong again. I seem to get lagged frames, almost as if the swap was done before the driver realizes that the area where the menu/dialogbox used to be is now clear again and should be swapped too. So it swaps the buffer, but leaves the used-to-be-covered area unswapped, showing an old frame. Disastreous.

I've been messing with swapping extensions, doing readpixels to force a 3d pipeline flush, adding more sleep, etc... Nothing helps.

So does this sound familiar to anybody ? _Any_ tips or ideas ?... :[

knackered
08-07-2002, 07:01 AM
You can't draw GDI stuff on a double buffered opengl window.
As far as I remember, you can't draw GDI stuff on a direct3d window (at least not in exclusive mode).
Your best bet is to probably draw your GDI objects into a bitmap all the time, and in your WM_PAINT, gltexsubimage that bitmap into a pre-created texture, then draw a screen sized quad over the opengl viewport with alpha blending or somesuch thing.
Or, keep your GDI objects off the window!

[This message has been edited by knackered (edited 08-07-2002).]

ehart
08-07-2002, 07:48 AM
It is unclear to me what GDI elements you would need to draw over the context itself. Most of the time GDI elements can be drawn as child windows at the same level as the GL window. (not overlapping) Naturally, this doesn't work for floating tool windows and the menu thing you mentioned, but if these don't work I would highly suspect a driver issue, but I would not rule out a case of poorly defined interaction semantics.

-Evan

Dan82181
08-07-2002, 10:08 AM
I am personally using MFC in my applications. What I do is use a menu at the top of my GL window to select different options and have it create child windows with all my tools and edit boxes and what not. Even though the application itself has focus, I stop rendering to the GL window unless the frame itself has focus or a redraw of the frame has been issued. Even when dragging the child windows and messageboxes over the main window, I have never gotten your swapping problems with either NV or ATI cards.

I myself cannot say that I have had any experience with DX so I cannot agree nor disagree with knackered or ehart, but obviously they know more about it than me.

Dan

AdrianD
08-07-2002, 10:15 AM
Originally posted by knackered:
You can't draw GDI stuff on a double buffered opengl window.
(...)


of course you can draw buttons and other controls over an openGL window!
if it wouldn't be possible, you couldn't display any messagebox over an opengl-window. And you wouldn't be able to move any other window over a running OpenGL window...
but you can do it!
that's because pageflipping is only used in fullscreen mode if the window is NOT overlapped. In all other cases the backbuffer is blitted using the current visible region(=masking) for the openGL window.
If you put other windows(any gdi-control is basically a window) over your openGL window, the regions of this windows are excluded from its visible region.
this works fine with my apps.(without any sleep)


bpeers:
my window class style for my openGL window to has CS_OWNDC enabled. maybe this is the difference to your code?
are you using MFC ?

V-man
08-07-2002, 10:50 AM
>>>realizes that the area where the menu/dialogbox used to be is now clear again and should be swapped too. So it swaps the buffer, but leaves the used-to-be-covered area unswapped, showing an old frame. Disastreous.
<<<

I don't know but may it never swap a second time. Windows is suppose to restore the window after the menu/dialog disappears.

Maybe I misunderstood something.

Also, I would like to mention that this happens with all windows versions and is only noticeable when there is animation in the window, so you might want to suspend the animation when a menu or dialog is popped.
V-man

jwatte
08-07-2002, 11:57 AM
It's not supported to use GDI calls in a HDC that also has a HGLRC rendering into it.

However, you can create opaque child windows of the window that owns the OpenGL HDC, and render using GDI into THOSE windows.

For dialogs/buttons/text controls, that approach works very well. If what you need is, say, GDI text rendering, I find that the performance of rendering to an offscreen bitmap and uploading as a texture is very reasonable -- probably because the text rendering works faster on cached memory than if it's trying to bang the graphics card frame buffer. And if it _isn't_ trying to bang the frame buffer, then it's doing the same thing you're doing, just hidden from view, so performance should be identical.

Beware though, that with current drivers, if the parent window is full screen, showing the first GDI child window may switch the driver from buffer flipping to buffer blitting mode, which introduces a delay of a full second! This is said to be fixed in future drivers. The work-around is to always allocate the HGLRC with PFD_SWAP_COPY.

bpeers
08-08-2002, 12:25 AM
Hi all, first off, many thanks for all the comments and suggestions !

I'd read the note in MSDN that mentions you shouldn't mix GDI with doublebuffering, but it seemed to pertain to the software renderer, it didn't really say anything about the validity of this "in general" (ie with vendor drivers). Hence my hope that it can be done.

A bit of clarification first..

The issue is more about GDI drawing to annotate the 3D scenery with stuff like lines, text, points. As true GDI programmers, the clients are using all the fancy stuff such as special pen styles, line joints, fancy text stuff, etc, so duplicating all that with 2D-in-3D is a headache.
Unless I delay this drawing a bit, some GDI just doesn't show (is annihilated by the blit).

That's the one thing. The other thing is that win32 draws stuff over the GLRC'd area, and I redraw it "right after" the win32 stuff disappears (menu item selected, menu disappears, I get a WM_COMMAND, I redraw the frame : win32 restores the area it made dirty with the previous frame, seemingly not realizing it was already swapped so it's clean now.

On to the fix then..

Doing GDI into a bitmap seems both wasteful, and complicating things. It's wasteful because at a (common) resolution of, say, 1400x1100 (MFC cad/cam-ish app rendering into a window), the texture'd have to be 1400x1100, uploaded into a 2048x2048. Uploading 1400x1100x4 bytes to blit 3 lines is silly http://www.opengl.org/discussion_boards/ubb/smile.gif And the huge texture sizes will probably mean I end up using tiling textures, panning and reblitting as I walk the screen. Ugh.
Erecting mini-textures around every element on demand is um.. interesting but also complicating stuff http://www.opengl.org/discussion_boards/ubb/smile.gif

I especially don't want to do all that if windows can't even get the basic blit right, as evidenced by the menu. For clarity, the menu is just the mainframe menu, which happens to overlap the GLRC'd client area when opened.

Dan, what do you do if clicking some tool or edit box requires a rerender, eg because you changed a rendering parameter ? At that moment, you have to rerender the scene to show the change, even though the frame does not have focus.. It'd be interesting to hear if that works, or also gives you ghost trails.

Adrian, I believe OWNDC is in place -- but I'll double check http://www.opengl.org/discussion_boards/ubb/smile.gif Your note about the region exclusion is also how I assume win32 works -- and the problem seems to be that regions are still being excluded from the flip-blit, even though they are visible.

V-man, it restores properly under normal conditions, it's just that when the scene is rerendered while some areas are covered, and the cover is then removed (by windows), the previous buffer shows. Hm, now that I formulate it this way, I'm starting to wonder if this isn't actually normal behavior !

But that still wouldn't explain why a sleep() is required to get GDI stuff to show up -- unless that is indeed just plain invalid code.

I'll check out PFD_SWAP_COPY.

Thanks again !

[This message has been edited by bpeers (edited 08-08-2002).]

bpeers
08-08-2002, 01:45 AM
Hm, check this out :

the code (http://users.chello.be/sf15772/vaag/updatebug.zip)

On ATI Radeon 8500, Matrox G200 and Matrox G500 this works as expected.
On a Geforce2Go, I always get the desktop color where the menu has been.
On a Geforce3, it looks like this (http://users.chello.be/sf15772/vaag/ogltest.gif) .

humhum :\

Edit: Hallelujah, 30.82 seems to fix this, at least in the test program (was using rather.old). Gonna try the G2Go's etc now,
then back to the original problem. Praise the lord :]

[This message has been edited by bpeers (edited 08-08-2002).]

V-man
08-08-2002, 03:04 AM
It just came to me,

there is actually a command for flushing GDI

Flush() <-- or something like this.

Personally, I would stick to only GL rendering instead of messing around like this. The only problem I had was AA text, but I will fix that another day.

V-man

Dan82181
08-08-2002, 07:48 AM
The only thing I get that remotely appears to be some kind of 'ghosting' is not because of anything between GDI and OpenGL. Because I only use double-buffering, everytime a user moves a dialog box, the frame recieves a redraw command. So the dialog box then has to wait until the frame is finished redrawing until it draws itself in the new position. I don't get ghosting, I get what every gamer hates, lag. My dialog box refreshes end up getting refreshed at the same rates as the OpenGL frame (unless the dialog is not overlapping any part of the frame.)

But normally, anything that requires a redraw of the frame, I wait until the user hits the OK button and the dialog is closed before any new rendering is done. If you really require that the frame be redrawn and it doesn't have focus, you could close the dialog box, redraw the frame, and reopen the dialog in the same window position, but I don't see how refreshing the frame's display would cause any type of ghosting, but I could try and see if it does for me.

Dan

tcobbs
08-08-2002, 08:20 AM
Are you familiar with the WS_CLIPCHILDREN and WS_CLIPSIBLINGS window styles? Are you using them correctly? I could be wrong, but if all you're trying to do is use GDI in other windows that happen to be above the OpenGL window (and NOT trying to perform GDI operations in the OpenGL window itself), it should work as long as you properly make use of these styles. If you set it up so the OpenGL window is clipped by the other windows, there's no way for the swapbuffers to overwrite the other windows.

Presumably this forces COPY mode in the swapbuffers, since it has to clip, but I would assume that would happen anyway when not in fullscreen mode.

jwatte
08-08-2002, 06:10 PM
> Erecting mini-textures around every
> element on demand is um.. interesting but
> also complicating stuff

What fun would life be if it always was easy?

And, besides, it's not that complicated. You can do the small-disposable-textures thing, and it's not really that hard. And it works great!

Or you can allocate a texture with texture rectangle, or four textures of better size to fit the actual rectangle (use GL_NEAREST interpolation mode). Then draw into a bitmap as large as the screen (nothing wasteful about that these days :-) and TexSubImage only the parts that actually changed, into the respective four textures that cover your area.

For example, with a 1400x1100 window, you'd make one texture 1024x1024, the one to the right of that 512x1024, the one below the big one 1024x128, and the one in the lower right corner 512x128. You can subdivide more if you want a tighter fit, but I think that should be sufficient.

Last: the reason the menu can draw over the OpenGL area is that it is its own GDI child window. If you made your own GDI child window, you, too, could draw into that in the middle of your OpelGL viewport.

NitroSR
08-09-2002, 06:08 AM
This is just a long shot, but are you responding to windows paint messages to update your OpenGL display? The issue may be linked to your GL renderer not synchronizing properly with Win32's WM_PAINT messages.

Just a thought.

bpeers
08-09-2002, 06:15 AM
Yep...

I've been doing some more testing with the source I upped (see higher) and there definitely had to be some sort of driver bug involved here. OEM dell drivers for the G2Go from "2/6/2002" (be that feb 6 or june 2) haven't fixed it yet, detonator 30.82 has, so I duno, I guess I just hit a bug. That was the windows-restores-with-old-frontbuffer thing, I wonder if the "GDI is drawn before the swap is completed" thing is also fixed now, still need to test.

Oh and btw this doesn't mean the whole thread is in vein http://www.opengl.org/discussion_boards/ubb/smile.gif I'll probably need to reconsider doing GDI to a bitmap anyway due a. its alleged illegalness, b. the flickering is damn ugly :^)

-- Thanks again all..