Why doesn't this work in windowed mode?

BlitzMax Forums/BlitzMax Programming/Why doesn't this work in windowed mode?

ImaginaryHuman(Posted 2006) [#1]
Hey folks.

I am trying to do a `test` to see if the display that is opened really has a double buffer. I can query OpenGL with glGetIntegerv() and it can say yes, but I also want to use a `graphics test` which proves whether separate backbuffer and frontbuffer are present. I am doing the test with an open display with words on it so I can SEE whether it is actually double buffered or not, but I am trying to get my test to comply with what is obvously true.

The test I am trying to do is as follows, but it doesn't seem to work right in all cases. It works in full-screen mode, with either single or double buffered displays. But in window mode it doesn't report correctly. I *should* be getting pixel values coming back from glReadPixels() but instead I get 0's. This appears to happen despite the fact that I can insert breaks which let me SEE that it actually does have a backbuffer, you can't see what's being drawn until it flips, etc.... and yet when I do the second set of DrawRect's to erase the backbuffer, it erases the front buffer, even though it is double-buffered! I have tried adding glDrawBuffer(GL_BACK) and all that, doesn't fix it.

Any ideas why this is not working in window mode, or how to test successfully in window mode?

(sorry about visual confusion from all the comments)
Local TestColor:Int=$FF
Local TestColor2:Int=$FFFFFF00
'We draw to the backbuffer and flip it rather than draw to the front 
'because on some systems it wont let you draw to the front 
glDrawBuffer(GL_BACK)      'Draw to backbuffer
Cls       'Erase backbuffer so when we flip it looks ok 
SetColor TestColor,TestColor,TestColor
DrawRect 0,0,2,2       'Put color on the backbuffer. If it appears on the 
'front buffer later there is no doublebuffer. (Make sure the whole 
'corner pixel is covered on all systems) 
DrawRect 0,MyHeight-2,2,2       'Some platforms, in window mode, have 0,0 
'topleft, others bottomleft. Unless you use GLGraphicsDriver() and set 
'up your own OpenGL display you can't be sure, so check 2 pixels 
glFlush() 
glFinish()       'Make sure it draws it, needed for single-buffered displays 
' particularly 
Flip 1       'Flip the display, back becomes front if there is one. If there 
'is a backbuffer it should now be blank, unless the flip is done by 
'copying the backbuffer to the front, in which case they are now 
'identical and the back has to be cleared 
SetColor $0,$0,$0       'Make it ready to do a mini cls - necessary in case 
'the backbuffer was copied to front or if the back has trash data on it, 
'the backbuffer HAS to have black on it 

'Works in full-screen single/double, maybe works in windowed singlebuffered, 
'doesn't work in windowed doublebuffered (this code erases the pixels!) 
DrawRect 0,0,2,2       'Clear the first pixel. This also clears the front 
'buffer in single-buffered mode - our test 
DrawRect 0,MyHeight-2,2,2       'Clear the second pixel. These are NEEDED to 
'handle copy/blit type Flip as in window mode 

glFlush() 
glFinish()       'Make sure it is drawn before we test - it may erase the 
'front buffer 
glReadBuffer(GL_FRONT)       'Read from the front buffer (this will be the 
'backbuffer in single buffered mode) 
Local pix2,pix3:Int=0 
glReadPixels(1,MyHeight-1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix2)) 
      'Check first pixel 
glReadPixels(1,1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix3))       'Check 
'second pixel 
Print Hex$(pix2)+" "+Hex$(pix3)+" "+Hex$(TestColor2)       'what?
enablepolledinput();WaitKey       'temporary
If (pix2=TestColor2) And (pix3=TestColor2)       'Pixel color is correct, 
'our test agrees 

...if this was true then we now know there is a doublebuffered display.

I thought maybe I need to put another glFinish() after Flip() to make sure it has finished copying the back to the front before I do the test?

Any other possibilities? Is there something I'm not seeing?

I know that you can never know whether your display will hardware-flip, copy, or whether the backbuffer will contain the previous frame, black, trash data, or a totally new backbuffer after the flip. Still doesn't seem to matter. Why does this code work fullscreen but not windowed?

It is mainly when I open a double-buffered window that it says there is no double buffering.


ImaginaryHuman(Posted 2006) [#2]
Does Flip() on a single buffered display somehow do something to the front buffer after it flips? Shouldn't it basically do nothing?


ImaginaryHuman(Posted 2006) [#3]
bump


skidracer(Posted 2006) [#4]
pretty hard to work out what you are doing from non functioning code, note the following requires the SetGraphicsDriver defaultFlags to be set to 0 for single buffering to work correctly (and adding a flip doesn't seem to affect output):
SetGraphicsDriver GLGraphicsDriver(),0

Graphics 640,480

glClear GL_COLOR_BUFFER_BIT

GLDrawText "'Raw' OpenGL Graphics! Hit any key...",0,0

glflush

WaitKey



ImaginaryHuman(Posted 2006) [#5]
Hey skid, yah I have the driver defaulting to 0 to make sure there is no doublebuffer that way. Thanks for the info. If I don't get something working soon I'll probably just listen to what OpenGL says and be done with it.


ImaginaryHuman(Posted 2006) [#6]
Here is a reproduction of the problem:

On my iBook G3, the data returned by glReadPixels() indicates that it is reading the same buffer, regardless of whether I tell it to read the front or the back. Clearly, after the final flip, the test pixels are visible on the front buffer. Before that they are not visible, due to the presence of the backbuffer.

I don't know if this will be reproduced on your system, maybe it is an iBook quirk based on how it handles OpenGL or how it does doublebuffering. I think I am going to give up trying to test, graphically, that the backbuffer really is there, because I can't for the life of me get this to work consistently. It appears to work in full-screen displays, but not in a window.

Ideas?

Strict
SetGraphicsDriver(GLMax2DDriver())
Local MyWidth:Int=640
Local MyHeight:Int=480
Graphics MyWidth,MyHeight,0,0,GRAPHICS_BACKBUFFER

glDrawBuffer(GL_BACK) 'Select to draw to the backbuffer. If there isn't one it draws to the front buffer
SetAlpha 1.0
SetClsColor $0,$0,$0 'Make certain it is black
Cls 'Initialize to remove any pre-existing pixel color
Flip
Cls
Local TestColor=$FF:Int
SetColor TestColor,TestColor,TestColor 'Set to our test color
DrawRect 0,0,2,2 'Draw a pixel top-left corner
DrawRect 0,MyHeight-2,2,2 'Draw a pixel bottom-left corner, we do both corners because some systems flip the corners
glFlush() 'Flush any buffered commands
glFinish() 'Make sure all rendering is totally finished before we test
glReadBuffer(GL_FRONT) 'Reading from the front buffer (=backbuffer on single-buffered display)
Local pix2:Int=0 'Init to black
Local pix3:Int=0 'Init to black
glReadPixels(1,MyHeight-1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix2)) 'Check first pixel
glReadPixels(1,1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix3)) 'Check second pixel

glReadBuffer(GL_BACK)
Local pix4:Int=0
Local pix5:Int=0
glReadPixels(1,MyHeight-1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix4)) 'Check first pixel
glReadPixels(1,1,1,1,GL_RGB,GL_UNSIGNED_BYTE,Varptr(pix5)) 'Check second pixel

Print Hex$(pix2)+" "+Hex$(pix3)+" "+Hex$(pix4)+" "+Hex$(pix5)
enablepolledinput();WaitKey

Flip;WaitKey



skidracer(Posted 2006) [#7]
Same problem on my NVidia based G5 so looks like an Apple bug with the glReadBuffer command.


Setting it to single buffering causes glGetError() on any use of GL_BACK which I suppose is reassuring...


Russell(Posted 2006) [#8]
This reminds me: Whats the difference between
SetGraphicsDriver(BufferedD3D7Max2DDriver())

and
SetGraphicsDriver(D3D7Max2DDriver())

Don't they both use double buffering?

Russell


ImaginaryHuman(Posted 2006) [#9]
Hmm interesting. Well, the second thing you said Skid is of high interest to me - if I can try selecting the backbuffer and then check the error messages and find it's not allowed/available, that in itself can act as confirmation that there is no backbuffer, which is basically what I'm after. Thanks!

And yah, looks like either an apple bug or just some wierd way that they've got things set up on that older system. Having said that I get the same problem on my much newer iMac.

I'll go with the error message method and dump this graphical test, it's wasting too much time for me.

Thanks.


ImaginaryHuman(Posted 2006) [#10]
I put together some code similar to the above but a variation on the theme, which seemed to successfully report the presence or absence of the backbuffer based on a graphical test. It worked fine in fullscreen and window mode with single or doublebuffering on my iMac.

However, my iBook certainly has some issues. I can't open fullscreen on the iBook so I can't test that, but in window mode the test fails when it should work. glReadBuffer() does seem to be being ignored and it almost seems as though when you do a Flip(), the backbuffer is now the visible buffer, and trying to read from the back actually reads from the front, and this changes back and forth every time you do a Flip().

What this basically means is that there are certain issues based on what computer you're on, which interfere with being able to graphically test for the presence of a backbuffer. So... since I obviously can't detect and adapt to the many many different configurations out there, with all their various specific bugs etc, I figure it is impossible to consistently get good test results for this.

So I'm going to just go with the error test - ie try to use glReadBuffer(GL_BACK) and OpenGL returns an error if there is no backbuffer. This, in addition to using glGetIntegerv() on the backbuffer flag which seems report correctly, is enough surety for me to prove whether or not the backbuffer is present. So I'm gunna dump the graphical test and just trust what OpenGL says.

Now I just need to test for the alpha buffer and the accumulation buffer.

I noticed that my desktop is 32-bit, according to OpenGL, and if I don't ask for an alpha buffer, I still get one. I find that interesting. You'd think it means that your window opens with the same format as the desktop. Not so. On my iBook the desktop is reported as 24-bit, no alpha, and it doesn't by default give you an alpha, but if you *ask* for one, you get one. So although it takes the desktop depth and setup as the default for what you'll get in your window, including any buffers that the desktop has (not sure if that applies to depth etc but the desktop typically only has alpha), you can *try* to override having only those buffers that the desktop has by asking for other ones.

I'll come up with a tidy function soon that I'll post, that requests a given screen mode/window with certain buffers and returns what buffers were actually given and whether the display opened properly.

I also had an idea for possible current issues or slowdown from using OpenGL in a MaxGUI window. .... Get the desktop width and height, open a MaxGUI window, find out what the client area size is, close the window, then open the old kind of desktop window using Graphics x,y,0, using the canvas size that was found.

That said, I have yet to experiment with what extra features I can add to the window with MaxGUI.