Vote time: RFE - Developer controlled swap buffer

So, just out of curiosity, how far are we away from 1.1 with this feature added into the API?

Gregg

Is anyone working on this? I have got gp’s issue 30 mostly resolved, as in the context shows up again after iconization though I still need to get the context destruction to work cleanly. I will be looking into the kbr’s thread stack mojo next unless someone else already put the work in.

I’m in the process of implementing the per-thread GLContext stack, which is effectively a prerequisite for implementing any swap buffer functionality. I hope to have something checked in within the next week.

Excellent. I will post the fix for issue 30 soon. It appears that when a window is iconized in a jinternalframe a hierarchy event is issued which the canvas isn’t listening for and then when the context is no longer attached to a renderable surface a swapbuffer error is thrown. It can be solved by either attaching a hierarchy event listener to the canvas or I can interrcept the call by overridding processEvents. I went for overridding processEvents since someone could grab all the hierarchy event listeners on the canvas and accidentally remove the fix. I am also reworking the pbuffer gljpanel code I posted before so hopefully it will be a little cleaner. What do you think about making the pbuffer a stand alone context rather than only being created by a glcanvas? Being able to resize itself will make it a lot easier to work with when it is backing a GLJPanel. I was also thinking that the reshape methods in GLCanvas and GLJPanel need to be changed so that they don’t automatically make the viewport take up the full size of the component making the call. It should read in the current viewport size and then preserve the ratio in the resized canvas/panel.

Great; looking forward to seeing your fix for this issue. I am a little worried that the fix will solve the GLJPanel problem but won’t address another basic problem, namely that if a GLCanvas is removed from its parent window and added to another one that the OpenGL context is silently destroyed and is never recreated. With the addition of the per-thread OpenGL context stack the context handling is becoming more complex, and I’m thinking that there must be a simpler solution.

That is one of the changes I made to WindowsOnscreenGLCanvas. A context can be passed to different HDC’s as long as they are on the same device and have the same pixel format. So when the GLCanvas is removed from the internal frame only the device context is new, the rendering context is the same and you don’t run through all the init code again. I assume it will work just the same if it was added to a different parent, but I have not tried. I am still trying the get the pbuffers to resize correctly. I just need to get it to init properly and I will post the code.

I am down to two last issues. The pbuffer gljpanel is still not being destroyed properly. I think I am going to have to make another invisible window/glcanvas to destroy it. The other issue is that if you use a pbuffer you have to flip the image when it is drawn. Currently gljpanel just draws the image upside down using a Graphics object and I am pretty sure it is slower than the MS software renderer. I am trying to use glPixelZoom and glCopyPixels to flip the framebuffer but I just can’t get it to work. Something to do with clipping I think. This might not matter that much if Tiger has hardware accelerated image ops. The other option is to render to a texture rectanlge and just draw a big quad that covers the whole viewport but that won’t be supported on ATI cards until 1.5 drivers show up.

GKW: Have you overridden the add/removeNotify methods? I saw that you had to mess with hierarchy events and such to destroy the context. I still believe these ‘notify’ methods are the cleanest way to solve this problem. When an internal frame is iconified for instance, removeNotify is called on it (and it’s children), to destroy it’s native resources. Also, when it’s deiconfied, addNotify is called, to reconstruct the native resources.
I modified GL4Java some time ago to work using these methods and it worked perfectly back then. I was hoping to be able to integrate this in Jogl as well, but my boss said I couldn’t. I hope you or somebody else can integrate this in my place. If you’re interested I can send you my GL4Java source code.

I thought about using the notify methods and I still may do that. It turns out what I was doing may be jvm specific so I went back to using a hierarchy listener. I am thinking we may have to use a hierarchy listener(ancestor moved) anyway to support moving a surface between multiple monitors. That is a little down the road but it is best to plan ahead. The modifications to the source that I have made do not destroy a context when it is removed from its parent. You have to explicitly call a destroy method on the canvas/jpanel. That way if you iconize a frame the animation stops, if you are using an animator, and you avoid calling init again.

I am down to just a last few intermittent errors when I am disposing of a glcanvas or a gljpanel. Hopefully I will be able to resolve the errors, comment my code, and post the finished code this weekend.

I have been in an email discussion with Ken on implementing this functionality and there is a disconnect between our philosophies, and seeing that there are other people trying to solve this problem, I thought maybe we can all just post our concept implementations, the actual code isn’t important here, just the methodology and why:

Here it goes for me:
One of the onus’ of OpenGL has not been safety, but always flexibility, if safety was the primary concern than there wouldn’t be the inventive ways that people of bastardized some of the OpenGL calls, resulting in very nice effects or visualizations. The makeCurrent and free are just another necessary part of OpenGL, no safer or less safer than any of the other state changing functions. Granted it has much more far sweeping side effects, but so does going into the wrong matrix mode in the middle of your drawing routine.

My methodology behind doing the implementation in the way that I had sent is because it offered both safety, convenience and the ability to kick you in the butt if you did it wrong. Safety and convenience through the classes that manage the buffer swap automatically, the different SwapBufferPolicy(s), but I also exposed the [make curent and free] calls. Granted the swapBufferPolicy classes could have been written to use package only accessor’s for buffer swapping, but then the user would have to add to this repository if they needed a different behavior. Granted they can be very sneeky and insert a rouge class into the package, basically making a different jogl than everyone else is using, but when updates are available, they once again have to repackage.

-Jason (just my 3 and a half cents)

Finally found some time to get everything done.

Go here to get the files.

I had to rename jogl.dll to jogl.zip to upload it to geocities so rename it back to jogl.dll after download.

  1. GLCanvas and GLJPanel should work a lot better inside JInternalFrames.

  2. GLJPanel has been implemented with pbuffers. This will allow you to use the lastest version of OpenGL that your graphics card supports unlike the previous implementation which used DIB’s and the MS software renderer. Also if you have a nvidia card it will use render to texture rectangle and you will get ok frame rates. As soon as OpenGL 1.5 comes out we can use the ARB render to texture rectangle and everyone will get the love.

This is WINDOWS ONLY!!!

[quote]I had to rename jogl.dll to jogl.zip to upload it to geocities so rename it back to jogl.dll after download.
[/quote]
You mean you didn’t actually ZIP it???

Yeah I was running out the door. It is now an actual zip and 1/8th the original size. I don’t think you really even need it but I figure just in case I forgot to remove some of my own native code.

FYI, a “per-thread GLContext stack” has been checked in to the JOGL repository. This enables calling GLDrawable.display() recursively as well as calling another drawable’s display() method from within a GLEventListener’s display() implementation. It was a prerequisite for exposing swapBuffers() in the public API, which should now be almost trivial to implement correctly and which is on my list of things to do.

Looks cool. That will fix the little hack I did for GLJPanels using render to texture rectangle. I will try to integrate what I did into the new framework.

I merged my code with the code now in the tree. The source is now available in joglsource.zip and the jar is the working jar. The dll from the source tree will work just fine. I also forgot to mention that I added dispose methods to GLCanvas and GLJPanel. It seemed to be a waste of resources not to have a dispose method. Along those lines what would you think about a destroy method in GLEventListener? It would make cleanup a little more automatic.

The files are here.

Thanks for your changes. I want to avoid exposing destroy() at the moment because I think it should be possible to fix the issue of destroying and recreating the OpenGL context by overriding addNotify() and removeNotify() as Pepijn van Eeckhoudt did in GL4Java (and which I haven’t yet ported over). I’ll try to review your changes over the next week.

FYI, my current priority is fixing the visual / pixel format selection problems that have been seen e.g. on lower-end cards. It looks like most of JOGL’s code in this area needs to be restructured and some minor public API changes are necessary (to the GLCapabilitiesChooser interface).

The only problem I see with overridding addnotify is that someone might want to keep the canvas around and reattach it later and not have to have everything reset. Which is exactly what the code I just posted does. When the internal frame iconizes the glcanvas, removeNotify() is called. If you are loading textures in your init you can expect a sizeable wait while they are reloaded.

I forgot to mention that I would like to do a fix for moving the canvases around to different monitors in a multiheaded config but I don’t have a second monitor handy. I am going to see if I can scrounge up a little 15incher. I think all you need to do is keep track of what GraphicsDevice you are on and then when ancestorMoved events are generated all you have to do is check if the component moved to a different GraphicsDevice and then re-init the device context and the rendering context. Shouldn’t be to hard.