226
edits
(Added note about being able to configure extra view windows using properties.) |
|||
(13 intermediate revisions by one other user not shown) | |||
Line 21: | Line 21: | ||
=== Status updates === | === Status updates === | ||
* 2020-12-12: One can now [https://sourceforge.net/p/flightgear/mailman/message/37174948/ configure extra view windows using properties]. | |||
* 2020-11-21: Merged into next: {{flightgear commit|f62e5b9ce3462758b48f4c711eb7c3bf4bcc7061|CompositeViewer:Support for multiple view windows using osgViewer::CompositeViewer}} <ref>https://sourceforge.net/p/flightgear/mailman/message/37158652/</ref> | * 2020-11-21: Merged into next: {{flightgear commit|f62e5b9ce3462758b48f4c711eb7c3bf4bcc7061|CompositeViewer:Support for multiple view windows using osgViewer::CompositeViewer}} <ref>https://sourceforge.net/p/flightgear/mailman/message/37158652/</ref> | ||
Line 47: | Line 49: | ||
* for the time being, use of reset/re-init and aggressive OSG threading options seems to cause stability problems even without having cloned any views <ref>https://forum.flightgear.org/viewtopic.php?f=6&t=38334</ref> | * for the time being, use of reset/re-init and aggressive OSG threading options seems to cause stability problems even without having cloned any views <ref>https://forum.flightgear.org/viewtopic.php?f=6&t=38334</ref> | ||
* Using OpenSceneGraph-3.6 causes problems elsewhere: [[OSGText Issues]] (under investigation as of 11/2020) <ref>https://sourceforge.net/p/flightgear/mailman/message/37157550/</ref> | * Using OpenSceneGraph-3.6 causes problems elsewhere: [[OSGText Issues]] (under investigation as of 11/2020) <ref>https://sourceforge.net/p/flightgear/mailman/message/37157550/</ref> | ||
* the [[PUI]] based fps/frame spacing counter implemented in $FG_ROOT/Nasal/gui.nas could probably be replaced by a Canvas implementation rendering to the [[Canvas_Snippets#Accessing_the_Canvas_Desktop|Canvas desktop]] using the [[Tooltips]] backend <ref>https://sourceforge.net/p/flightgear/mailman/message/37170351/</ref> | |||
* for some people there seem to be [[Compositor]] related event handling regressions which we should keep track of once we begin supporting events per view <ref>https://sourceforge.net/p/flightgear/mailman/message/37170307/</ref> | |||
=== Current limitations === | === Current limitations === | ||
Line 72: | Line 76: | ||
== Background == | == Background == | ||
<!-- | |||
{{WIP}} | {{WIP}} | ||
--> | |||
The natural way to manage a application that was two views on to two different scenes is to use a osgViewer::View for each separate scene, and then a osgViewer::CompositeViewer to manage these two scenes. These two views can share the same GraphicsWindow, or have their own. They may even be added/removed from the CompositeViewer, or have their rendering toggled on/off via NodeMask's on the master Camera for each View.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg24466.html</ref> | The natural way to manage a application that was two views on to two different scenes is to use a osgViewer::View for each separate scene, and then a osgViewer::CompositeViewer to manage these two scenes. These two views can share the same GraphicsWindow, or have their own. They may even be added/removed from the CompositeViewer, or have their rendering toggled on/off via NodeMask's on the master Camera for each View.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg24466.html</ref> | ||
Line 181: | Line 187: | ||
thread one two, the state for each context should be kept local to | thread one two, the state for each context should be kept local to | ||
each one.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg03788.html</ref> | each one.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg03788.html</ref> | ||
running multiple windows multi-threaded will give you the | |||
best performance, the OSG is designed for this usage model, and most | |||
easily set up using the native windowing support that the OSG | |||
provides.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg16632.html</ref> | |||
As long as your run the viewer multithreaded the OSG will use a | |||
barrier so that each graphics thread waits at the end of draw | |||
dispatch, then once all the threads join this barrier then all move on | |||
together and then call swap buffers. This is done to try and achieve | |||
synchronized swapping, however, it's not a full proof scheme as it | |||
doesn't use any low level driver and hardware synchronization. | |||
Extensions to some OpenGL drivers exist to enable the low level | |||
synchronisation, such as swap groups, swap ready and gen lock.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg54571.html</ref> | |||
* osgViewer::CompositeViewer is designed for applications that have multiple Views. The only thing to be careful of is when you are adding and removing View's from the CompositeViewer you should do is calling stopThreading() on the viewer prior to adding or removing views, then call startThreading() afterwards. If you are running SingleThreaded or CullDrawThreadPerContext you won't need to worry about stop and starting threads.<ref>https://groups.google.com/d/msg/osg-users/7OojxLpBGdw/mzorZe3rKwEJ</ref> | * osgViewer::CompositeViewer is designed for applications that have multiple Views. The only thing to be careful of is when you are adding and removing View's from the CompositeViewer you should do is calling stopThreading() on the viewer prior to adding or removing views, then call startThreading() afterwards. If you are running SingleThreaded or CullDrawThreadPerContext you won't need to worry about stop and starting threads.<ref>https://groups.google.com/d/msg/osg-users/7OojxLpBGdw/mzorZe3rKwEJ</ref> | ||
Line 188: | Line 210: | ||
* as long as you have two GPU's the most efficient way to drive them should be multi-threaded - there is a caveat though, hardware and drivers aren't always up to scratch, and even then they should be able to manage the multi-threads and multi-gpus seemless they fail too.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg18332.html</ref> | * as long as you have two GPU's the most efficient way to drive them should be multi-threaded - there is a caveat though, hardware and drivers aren't always up to scratch, and even then they should be able to manage the multi-threads and multi-gpus seemless they fail too.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg18332.html</ref> | ||
* Cull and draw can only run in a parallel once all the dynamic geometry has been dispatched, otherwise the draw will be dispatching data that is being modified by the next frames update and cull traversals. Perhaps you have some dynamic geometry or StateSet's that are holding back the next frame. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg36238.html</ref> | * Cull and draw can only run in a parallel once all the dynamic geometry has been dispatched, otherwise the draw will be dispatching data that is being modified by the next frames update and cull traversals. Perhaps you have some dynamic geometry or StateSet's that are holding back the next frame. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg36238.html</ref> | ||
* if you are using a single graphics card for best performance one usually tries to use a single graphics window and have two cameras or more share this context.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg54512.html</ref> | |||
The ThreadPerCamera is just shorthand for | The ThreadPerCamera is just shorthand for | ||
Line 204: | Line 226: | ||
=== Sharing scenes === | === Sharing scenes === | ||
The osgViewer has a mechanism for avoid multiple traversals of shared | |||
scene graphs if mutlple View's share the same root node of the scene | |||
graph. If shared component isn't the topmost node then the OSG has no | |||
straight forward way to know whether a subgraph has been traversed or | |||
not that frame. One could implement a mechanism to avoid this | |||
visiting a node multiple times in one frame but it would be really | |||
costly to do, an expense that would only be a benefit for a very small | |||
number of users, but would slow performance for everyone else. | |||
If you have a shared subgraph that you don't want traversed multiple | |||
times per frame then use an UpdateCallback that has a frameNumber | |||
member variable that keep track of the the frameNumber (use | |||
NodeVisitor::getFrameStamp()'s FrameNumber) of the last traversal, | |||
when a traversal calls the update callback you only traverse the | |||
subgraph if the frameNumber is different and then set the frameNumber | |||
to the present frame, if the frameNumber is the same then you just | |||
return immediately. This custom UpdateCallback you'd place as high as | |||
you can in your scene graph to make sure the traversal stops as soon | |||
as possible. | |||
Another approach is to move this frameNumber tracking into your | |||
existing update callbacks, and simple return right away with the | |||
frameNumber is the same. This requires a small tweak to the callbacks | |||
but is such a small change it's generally pretty easy to integrate.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg74476.html</ref> | |||
* Each View has one scene graph, and can share its scene graph between other instances of View. The View can also share the same GraphicsWindow, or have its own GraphicsWindow. The View also has a master Camera, and an optional list of slave Camera so you can scale from simple views up to complete distortion correction or multiple display output setups. Each View has its own event handlers and cameras handlers. Its extremely flexible and configurable. <ref>https://groups.google.com/d/msg/osg-users/kmSNMm6w008/zBBunL-VRJsJ</ref> | * Each View has one scene graph, and can share its scene graph between other instances of View. The View can also share the same GraphicsWindow, or have its own GraphicsWindow. The View also has a master Camera, and an optional list of slave Camera so you can scale from simple views up to complete distortion correction or multiple display output setups. Each View has its own event handlers and cameras handlers. Its extremely flexible and configurable. <ref>https://groups.google.com/d/msg/osg-users/kmSNMm6w008/zBBunL-VRJsJ</ref> | ||
* sharing a scene between View's is OK within one CompositeViewer as they will Views on the same scene will share the same FrameStamp i.e. there will be all at the same point in time. Sharing one scene between multiple Viewers will hit up against the problem that in one set of traversals the scene graph is one time and then the traversals from the other viewer will try to change the time back - and likely to cause a mess. This timing issue isn't likely to cause problems with high level rendering though - it should just mess up things like particle systems and sequences.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg07305.html</ref> | * sharing a scene between View's is OK within one CompositeViewer as they will Views on the same scene will share the same FrameStamp i.e. there will be all at the same point in time. Sharing one scene between multiple Viewers will hit up against the problem that in one set of traversals the scene graph is one time and then the traversals from the other viewer will try to change the time back - and likely to cause a mess. This timing issue isn't likely to cause problems with high level rendering though - it should just mess up things like particle systems and sequences.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg07305.html</ref> | ||
Line 223: | Line 269: | ||
trivial, but with encapsulating all this functionality it has to make | trivial, but with encapsulating all this functionality it has to make | ||
some assumptions about the way it's used<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg36853.html</ref> | some assumptions about the way it's used<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg36853.html</ref> | ||
A sharing OpenGL contexts doesn't mean actually sharing of the | |||
context, its just sharing some data between contexts, so you don't | |||
have a "common OpenGL context", you have two separate OpenGL contexts | |||
that are sharing display lits/texture objects etc. | |||
Each GraphicsWindow "is a" GraphicsContext which maps directly to a | |||
single OpenGL graphics context. Each OpenGL graphics context has its | |||
own state machine which is mapped by a single osg::State object - | |||
which you'll find on the GraphicsContext. | |||
Sharing of display lists/texture objects between contexts on the OSG | |||
just requires you to set the State::ContextID to same value. If the | |||
GraphicsWindow implementation is set up correctly then it'll | |||
automatically assign the same ContextID for each of the seperate | |||
osg::State objects.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg02505.html</ref> | |||
* It's possible to share contexts in the OSG [...] As for general desirability of share GL objects between contexts, yes it can reduce memory usage, but it forces you to use the OSG single threaded otherwise two contexts will be contended for the same resources that deliberately aren't mutex locked for performance reasons. There is also on a limited set of cases where drivers/hardware will actually share OpenGL contexts. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg32676.html</ref> | * It's possible to share contexts in the OSG [...] As for general desirability of share GL objects between contexts, yes it can reduce memory usage, but it forces you to use the OSG single threaded otherwise two contexts will be contended for the same resources that deliberately aren't mutex locked for performance reasons. There is also on a limited set of cases where drivers/hardware will actually share OpenGL contexts. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg32676.html</ref> | ||
Line 230: | Line 292: | ||
* Sharing contexts is also something the forces a few limits on how you use the graphics contexts, such as it's only really safe to use them single threaded. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg16791.html</ref> | * Sharing contexts is also something the forces a few limits on how you use the graphics contexts, such as it's only really safe to use them single threaded. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg16791.html</ref> | ||
* If you are creating new graphics contexts and applying and old scene graph to it then you can't use the Texture::setUnRefImageDataAfterApply(true) feature of osg::Texture as this will discard the imagery once it's applied to all the graphics contexts that it knows about. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg32658.html</ref> The typical problem is that the scene graph has been set up to unref texture images after apply so when it comes to reloading the texture images there aren't the to download. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg34284.html</ref> | * If you are creating new graphics contexts and applying and old scene graph to it then you can't use the Texture::setUnRefImageDataAfterApply(true) feature of osg::Texture as this will discard the imagery once it's applied to all the graphics contexts that it knows about. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg32658.html</ref> The typical problem is that the scene graph has been set up to unref texture images after apply so when it comes to reloading the texture images there aren't the to download. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg34284.html</ref> | ||
=== Swap Buffers === | |||
OpenGL drivers have a FIFO, your app fills the fifo with tokens and | |||
data, at the end of the frame you send in a swap buffers token and | |||
this goes into the FIFO with everything else. Normally the swap | |||
buffers call itself doesn't block (although some implementations do | |||
this), but the FIFO itself can only be cleared at the rate for one | |||
swap buffers call per frame so it'll fill and once filled up it will | |||
effectively block until previous frame was begun dispatching. The | |||
driver may allow several frames worth data in the fifo before block, | |||
this is driver dependent, and also dependent on just how data you have | |||
to pass to OpenGL- if you have massive models the CPU will be block on | |||
the FIFO right on the same frame rather than more than one frame begin | |||
backed in the FIFO. | |||
The end result of this is simpler though - put vsync on, and your | |||
frame loop will block and should iddle while its waiting for the FIFO | |||
to begin accepting new data. <ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg04323.html</ref> | |||
The driver will be queuing up multiple frames in the FIFO, something it | |||
does to help improve the framerate, but increases frame latency. | |||
We aren't powerless in this though, modern drivers and hardware support | |||
putting fences into the pipeline and waiting on these to be completed on | |||
the GPU. In the svn/trunk vesion of the OSG you'll find a swap buffers | |||
SyncSwapBuffersCallback implementation that does this for you. You can | |||
enable this via the env var OSG_SYNC_SWAP_BUFFERS=ON, or --sync on the | |||
command line for examples like osgviewer.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg68525.html</ref> | |||
There is an OpenGL extension that supports syncronizing of swap | |||
buffers across multiple graphics contexts that allows you to assigns | |||
contexts to swap groups<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg32951.html</ref> | |||
some graphics drivers will do swap buffers in sequence if you have | |||
multiple windows being rendered too, with each swap doing a vsync, | |||
which ends up with each window blocking till the end of each screen | |||
refresh. Use of the swap groups extension would be one way around | |||
this issue<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg22273.html</ref> | |||
The GraphicsContext::swapBuffers() is | |||
normally what does the swap buffers and then calls | |||
GraphicsContext::clear(), with GraphicsWindowEmbedded::swapBuffers() | |||
it's a non op, because there is no way it can do a swap buffers as it | |||
doesn't actually know about a real graphics context.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg21395.html</ref> | |||
=== Image Sharing === | === Image Sharing === | ||
Line 238: | Line 344: | ||
=== Multiple Viewers === | === Multiple Viewers === | ||
One possible | |||
solution would be to have two separate viewers, each running their own | |||
frame() when required - you can't mix scene graphs or graphics contexts | |||
in this case though.<ref>https://www.mail-archive.com/osg-users@lists.openscenegraph.org/msg30983.html</ref> | |||
If you don't want the main rendering loop to wait for the rendering of all these extra views then | If you don't want the main rendering loop to wait for the rendering of all these extra views then | ||
you'll need to use a separate viewer(or compositeviewer) with it's own | you'll need to use a separate viewer(or compositeviewer) with it's own |
edits