PDA

View Full Version : Pollution from other windows



AGL_Music
01-16-2010, 01:49 PM
EDIT: I don't get this problem when windows Aero is enabled, although I prefer to have it off. I suppose I can chalk the bug up to "crappy legacy support in Windows", but I'd still like to hear what anyone has to say about it.

---

I've been searching for information on this bug (and still am), but haven't had any luck just yet, so I figured I would check with you guys quickly...if it's a known issue, please be nice.

Here's my set-up:
OS: Windows Vista
GFX: Intel GMA65 - X3100 - Latest (still shitty) drivers

My program works fine 100% of the time, until I start moving other windows that use OpenGL around it. For example, I use WinAmp to play music, and if the WinAmp (drawn with openGL) window goes over top of the program I'm working on, when I minimize the winamp window, a "stencil" is created for my window, and nothing will draw outside of the area that the winamp window used to be.

I'm using a Thinkpad, which has pop-up menus that are specific to the computer, and these cause the same problem. When I change the volume on the computer, a strange little stencil is created in my program, and it will only draw inside of a small area that says "Volume - (Volume Level)".

The only solutions I've found are:

-Resizing or moving the window to make the problem go away.

-Changing the SwapBuffer(H_DC) command into:

SwapBuffer(H_DC);
SwapBuffer(H_DC);
SwapBuffer(H_DC);

Thus putting the SAME buffer to the screen twice. This makes the stencil to away as well(no idea why), but I can't stand using such awful code.

I tried using gl_Disable(GL_STENCIL), but this didn't do anything..

Any ideas?
Thanks in advance.

ZbuffeR
01-16-2010, 02:45 PM
What do you clear ?
Maybe you need an explicit clear on depth+color+stencil at the start of each frame, right after swapbuffers.

Dee.cz
01-16-2010, 04:06 PM
I reported this Vista error in broken window refresh in Vista (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=248466) thread.

All GL apps in Vista without Aero are affected. All apps based on freeglut, qt, wxwidgets show this error. Apps based on glut show different, less serious error. So there's probably some difference in initialization, if you do things in ancient glut way, Vista rewards you by less serious error.

AGL_Music
01-16-2010, 04:50 PM
ZBuffeR: I think that using 3 buffer swaps implies that the buffer *is* being drawn to properly, but not displayed properly, although I'm honestly unsure of this.

Still, I tried clearing all buffers and disabling as much stuff as I could, to no avail..doesn't seem to be a clearing or state management issue.

Dee.cz: Looks like the same problem...I can offer you some details if it interests you...

1) I'm using a manual initialization routine, not GLUT or anything like that.
2) There doesn't seem to be a problem on a single buffered window, although I don't like using single buffers
3) On programs designed to run at full-fps, with the draw routine in the main windows loop, I have *no* problems. My program only runs draw operations for mouse movements, mouse clicks, and refresh messages, and the bug is quite bad.

Point #3 is strange, because there are still loads of draw operations issued by using the mouse, but the problem still persists.

Iulian B
01-17-2010, 04:09 AM
Before vista (with aero), windows were drawing (through a device context) directly to a screen. They were notified through the WM_PAINT message that they need to refresh their part of the screen because something else happened that invalidated what they were displaying ( like a window passed over and painted in that region of the screen, which was ok, but then that window was moved away and left some garbage in the screen buffer). So what an application would need to do in order to behave nicely would be to respond properly to the WM_PAINT message. Failure to do so will result in some trails of other windows content being left on the window. (that's why, when a program was being unresponsive, if you dragged a window over it, it would look completly screwed).

Now, with Aero, the guys from M$ actually did something nice: they gave each window their own offscreen buffer to draw into, and then Aero composition (a 3d application that is drawn as the desktop) will take these "textures" that represent the windows content and, using information about window placement and z order, would redraw all the desktop whenever it is needed. And, by doing so, they have two benefits: unresponsive windows (which is not M$'s fault, but the app's developer) would not look that weird anymore, but would be "faded out" by aero when it detects that they don't respond AND composition effects can be applied, like the nice effect of minimising and maximising a window in aero, and the Win+Tab flip.

The third issue is that any "real" 3d application, running under Aero'd vista or plain old GDI, would, most of the times, run "at full-fps", basically because almost at all times there's something changing, like "idle" animations and whatever else. So any real 3d application (ok,most 3d editors could get away with less frequent refreshes, but that is app dependent) would automagically resond properly to WM_PAINT, even if they don't threat the message in the message queue, just by swapping the buffers.

Now, the issues: of course, since we're talking about intel gma, we still have some doubts , either to the quality of the drivers or to the actual quality of the video "card", so even assuming you behave nicely with WM_PAINT, some weird OGL + GDI combination could still result in some failure. BUT, you say that if you flip the buffer 3 times, all is ok. So, to me, it looks like you don't do the whole "redraw the scene and swap the buffers" as a response to WM_PAINT.

P.S. If you don't want to run the app 'full frame', you could introduce some sleeps in the app (I don't recomend it) or use glSwapInterval with a number greather than or equal to 1. Assuming your drivers (a bold assumtion, being that we talk about GMA) don't do stuff to override the setting, you will draw at most 60 / that number frames... So, if you don't have a very interactive app glSwapInterval(6) should do the trick, drawing at most 10 frames per second... Of course, you'd have to first check that you have that extension and get the function's pointer and bla bla bla... but researching WM_PAINT and glSwapInterval will do you good.

Cheers,
Iulian

Stephen A
01-17-2010, 06:06 AM
Indeed, this sounds like a missing WM_PAINT response (although with GMA you never know).

AGL_Music
01-17-2010, 09:45 AM
First thing, I noticed that the Swap*3 fix only works for the Lenovo-pop up menus. With winamp, there is still a large problem, so scratch that.

Thanks for the big response, very helpful. I had managed to intuit a good deal of the improvements used in Vista, but I hadn't considered that they all turn OFF when you switch to basic. Being that I'm designing an audio application, it stands to reason that most users will disable crap like Aero + silly windows animations before using it, to give more time to the audio processing. Furthermore, the swapinterval idea will be taken care of by the audio driver, providing "light" refreshes to the interface per audio buffer.

So it's important that it works well in basic mode.

The program is a 2d-orthographic interface, with 3d elements to be introduced later on (replete with a proper fps). The draw-ops will get more complicated, but right now it's pretty inane.

At the moment, my code looks like this:
Move mouse -> Draw Entire screen + Swap
Mouse Click -> Draw Entire Screen + Swap
WM_Paint -> BeginPaint + Draw Entire Screen + Swap + EndPaint

It really seems like a problem with my code, because I have absolutely no trouble with:

Loop -> PeekMessage, etc -> Draw Entire Screen -> Swap -> End Loop

Which is infuriating, as there doesn't seem to be any difference at all in terms of the workings of the redraw and swap. My only guess is some strange never-to-be-fixed glitch residing somewhere in windows basic.

Furthermore, with the WM_Paint consideration, remember that I only get the problem from overlapping GL windows. Other windows don't affect mine.

I think what I'll try next is forcing windows to provide a buffer refresh whenever the program gains focus, hopefully fixing their problem...

AGL_Music
01-17-2010, 11:55 AM
Okay, I'm an idiot.

It was the WM_Paint message, as I wasn't setting the invalidation region. I suppose this region stays stored in the DC, and would never have existed when I was using the windows loop for drawing. Like some sort of obnoxious secondary Stencil.

Solved by two lines of code (uhg) before BeginPaint

getwindowRect(H_Wnd, R);
invalidateRect(h_wnd, @R, false);

Iulian B
01-17-2010, 12:35 PM
Hmm, what you are basically doing with getWindowRect/invalidateRect is to say that you want to redraw the whole window, therefore negating any good thing that the beginpaint/endpaint along with the invalidated rect would bring... But, since you're redrawing the whole scene, that's good... Btw, I never call beginpaint/endpaint in my code ever and not even threat WM_PAINT, but this is because I always redraw the entire thing at full frame...

On a different note, since now I know what you want to use your app for, I can recommend you to take a look into WPF. It's quite mature now, can do 3dlike interface and it contains lots of stuff "for free", interface-wise. Plus, you can customise the look of the interface as much or as less as you want. Anyhow, it is just a recomandation, you're free to do as you like; just remember, choose the right tool for the job.

Also, you can mix and match your technologies, I myself have succesfully integrated an OGL/win32 window inside a WPF app and I was surprised that I got way less WM_PAINT messages than I would get in the normal way of just putting that window "on the loose". That is because, even with aero's optimisations, windows has to play by the old rules in Win32 api, which I assume you're basing your app on...

see ya,
Iulian

AGL_Music
01-17-2010, 02:10 PM
In terms of the interface, think "solid modelling-ish and linux portable" moreso than "next generation of microsoft". Still, if it weren't for the linux part, I'd consider WPF for cleartype fonts alone.

Stealing WM_Paint from the default window procedure seems to be like opening Pandora's box to the OGL programmer. Perhaps it's a bit much of a paradigm shift, when you've been thinking mostly in 3d..(and fullscreen).

Thanks again!

Brolingstanz
01-17-2010, 11:23 PM
>> Still, if it weren't for the linux part, I'd consider WPF for cleartype fonts alone.

I bet well see an implementation of WPF eventually in e.g. Mono; its just way too cool from a design standpoint. Though part of the coolness is undoubtedly the VS designer front end, using a markup language to describe a UI scene is pretty cool in and of itself IMHO.

Iulian B
01-18-2010, 01:44 AM
Ok, ok, I see. if you bring linux in the equation then I can understand, I was misleaded by the fact that we we're talking about WM_PAINT all the time, so I assumed Windows only ;).

And, about intercepting WM_PAINT, there's no mistery there, things should just work. I don't intercept it because by default, it does what I want/need. Anyhow , you can invalidate the whole rectangle without getting the client rect of the window but by just passing NULL to the 2nd parameter of invalidaterect.

So, the last thing that worries me (but maybe I understood wrong) is that you say you redraw your window for each mouse move and mouse click... I hope in the events you just store the fact that you have to redraw the window and not redraw it in the message handler, because you could have more than one mouse event "per frame".

Anyhow, good to hear that you fixed your problem.

Good luck with your project,
Iulian

Shinta
01-18-2010, 03:10 AM
So, the last thing that worries me (but maybe I understood wrong) is that you say you redraw your window for each mouse move and mouse click... I hope in the events you just store the fact that you have to redraw the window and not redraw it in the message handler, because you could have more than one mouse event "per frame".
Exactly, don't draw on other events than WM_PAINT. If you need a refresh of your opengl-context just invalidate it. This is also the way to go from onIdle- or timer-events. Even worker threads can use this way to refresh a window. (Don't forget to invalidate on resize (WM_SIZE).)

so long,
Shinta

Iulian B
01-18-2010, 07:14 AM
Exactly, don't draw on other events than WM_PAINT. If you need a refresh of your opengl-context just invalidate it. This is also the way to go from onIdle- or timer-events. Even worker threads can use this way to refresh a window. (Don't forget to invalidate on resize (WM_SIZE).)

so long,
Shinta


I'm sure windows sends an WM_PAINT after a WM_SIZE (I'm certain it sends it after you enlarge your window, not sure it sends it when you shrink the window).However, it should be preety harmless to invalidate your rectangle on a resize, as WM_PAINT messages are cumulative (i.e. if you have it in the message queue once, windows won't post it again, but just update the invalidated rectangle with another rectangle that encompases the old stored one and the new one provided - good behaviour).

Anyhow, a resize should be a major event, viewports should be resized also, rendertargets (if any) should be recreated, stuff like that. Not to mention that the whole UI would/should get a relayout (right now at work I'm on the 2nd project I'm working on UI/ hud/ menus stuff...I started to even dream this stuff, of course in the shape of nightmares). Just make sure you avoid the whole recreation on the minimise event, you'll get a WM_SIZE with new size 0,0 , you should take care in that case( just had my a** bit at work by this)...

AGL_Music
01-18-2010, 08:33 AM
Oh dear, I've got miles to go before the window refreshing system makes sense. On the other hand, I get excellent audio performance when I'm not moving the mouse. Any more optimizations would be premature. One feature is pop up menus which appear when hovered over, so I am somewhat stuck with a metrics system that operates per MouseMove. But the draw event is only needed when it pops up.

WM_Paint was a pain as you simply can't intercept it. It _must_ provide calls to beginPaint and endPaint, or windows will bombard the program with WM_Paint messages endlessly, which seemed counterintuitive at first..

You've got to admit that making an OGL interface is a pretty decent challenge though, no? Aside from the nightmares :). I'm right with you on all of the resizing stuff, I had to bug fix the inevitable div0 @ minimize event last week.

Ilian Dinev
01-18-2010, 09:01 AM
WM_Paint was a pain as you simply can't intercept it. It _must_ provide calls to beginPaint and endPaint, or windows will bombard the program with WM_Paint messages endlessly, which seemed counterintuitive at first..




case WM_PAINT:
ValidateRect(hWnd,NULL);
break;

Iulian B
01-19-2010, 02:00 AM
or, better yet

in message handle
case WM_PAINT:
pMyWonderfulApplication->bISwearIWillRepaintTheSceneAndDoABufferSwapRightAf terIFinishProcessingAllTheRemainingWindowMessagesA sToAvoidRedrawingMoreThanNeeded = true;
return DefWindowProc(hWnd,msg,wParam,lPara);

case WM_ANY_MOUSE_MESSAGE_THAT_I_CARE_ABOUT:
pMyWonderfulApplication->bISwearToGodIWillRepaintTheSceneAndDoABufferSwapRi ghtAfterIFinishProcessingAllTheRemainingWindowMess agesAsToAvoidRedrawingMoreThanNeeded = true;
pMyWonderfulApplication->doNastyStuffWithThisMouseMessageToUpdateTheInterfa ceStateButDontRedraw();
return 0; //or defWindowProc, depending on what you wanna do


in main loop

while(GetWindowMessage(...))
{
TranslateMessage()
DispatchMessage()
}

if(pMyWonderfulApplication->bISwearIWillRepaintTheSceneAndDoABufferSwapRightAf terIFinishProcessingAllTheRemainingWindowMessagesA sToAvoidRedrawingMoreThanNeeded)
pMyWonderfulApplication->RenderTheNextAwesomeFrame();
SwapBuffers();

AGL_Music
01-19-2010, 07:44 AM
See, that's why you had your ass at work, as I'm sure that all of your code looks precisely like that.

That looks efficient though, I like. If it entertains you at all, how about adding a partial refresh @ 30fps, which merely blits to the already drawn interface?

I won't be able to implement it for months, but I was thinking

Copy pixels to back buffer
draw over it (mostly glRectF -> volume levels)
Swap;

I read in a doc that SwapBuffers leaves the back buffer undefined, but this isn't true on my system, it literally swaps them, in which case I wouldn't have to copy pixels, but is this just my computer acting strange?

I figure adding depth testing or a stencil might help with the blit too (not looking forward to that).

If it doesn't entertain you, feel free to ignore.

ZbuffeR
01-19-2010, 07:50 AM
"Undefined" means it will depend on inmplementation, hardware, driver, OS, etc.
So "literally swaps" is fine, as well as "leave random garbage all over the place" or "resets to black". Just don't rely on it.

Iulian B
01-20-2010, 09:59 AM
AGL_Music, I hope the first line on your reply was a joke :D. Either way, I didn't write the low level code at work, because when I joined the project it was happily running for a year or so already. I just had to fix it when I implemented something that was relying on a good behaviour when there was none.

Anyhow, the refreshing part might or might not make sence, depending on the general architecture of your stuff. If your app behaves nicely and responds to all the events(messages, sorry) that windows sends you and you also ensure that you actually do a redraw when something changes in your interface (some animation running, some state changing some ... whatever), then you can happily redraw stuff only when it's needed.

Now, about the backbufer, as Zbuffer already told you, it is implementation (nvidia/ati/(sadly, in your case,)intel drivers) dependent. In some cases, the video card just switches the back buffer address to the front buffer address without touching the contents (that's quite efficient) . In this mode, if you have two different frames and you just swap the buffers without doing anything you will see alternatively 2 frames. In another mode, when swapping the buffers, the driver will copy the entire content of the backbuffer over the content of the frontbuffer, those two buffers will then have the same content so flipping them over and over again will result in no apparent change. This is slower, however, due to copying... Also, the driver might decide that it's nice for it, after it swaps or copies the back buffer, to clear it with black or any other color of the rainbow, or whatever they want. Since it's not defined, assume you have garbage and either make sure you draw over the whole buffer or clear it first.

Now, the second part, you can draw your interface in a texture, keep it in memory and if you want to do a refresh, just draw that over the backbuffer and flip. Of course, that would mean this implementation requires a bit more video memory. As captain planet would say, the power is yours... But so is the responsability , so you choose whatever suits your app best. ;)

AGL_Music
01-23-2010, 01:32 PM
Oh, sure, I was kidding..

Well, if Captain Planet says so, then I feel far more confident.

Thanks :)