root/OpenSceneGraph/trunk/src/osg/GraphicsContext.cpp @ 7074

Revision 7074, 20.6 kB (checked in by robert, 7 years ago)

Added include/osg/GLObjects + .cpp which provide osg::flush*DeletedGLObjects() methods.

Added and cleaned up DeleteHandler? calls in osgViewer to help avoid crashes on exit.

Changed DatabasePager? across to dynamically checcking osg::getCompileContext(..)

Updated wrappers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14
15#include <osg/GraphicsContext>
16#include <osg/Camera>
17#include <osg/View>
18
19#include <osg/FrameBufferObject>
20#include <osg/Program>
21#include <osg/Drawable>
22#include <osg/FragmentProgram>
23#include <osg/VertexProgram>
24
25#include <OpenThreads/ReentrantMutex>
26
27#include <osg/Notify>
28
29#include <map>
30#include <sstream>
31#include <algorithm>
32
33using namespace osg;
34
35/////////////////////////////////////////////////////////////////////////////
36//
37//  GraphicsContext static method implementations
38//
39
40static ref_ptr<GraphicsContext::WindowingSystemInterface> s_WindowingSystemInterface;
41
42void GraphicsContext::setWindowingSystemInterface(WindowingSystemInterface* callback)
43{
44    s_WindowingSystemInterface = callback;
45    osg::notify(osg::INFO)<<"GraphicsContext::setWindowingSystemInterface() "<<s_WindowingSystemInterface.get()<<"\t"<<&s_WindowingSystemInterface<<std::endl;
46}
47
48GraphicsContext::WindowingSystemInterface* GraphicsContext::getWindowingSystemInterface()
49{
50    osg::notify(osg::INFO)<<"GraphicsContext::getWindowingSystemInterface() "<<s_WindowingSystemInterface.get()<<"\t"<<&s_WindowingSystemInterface<<std::endl;
51    return s_WindowingSystemInterface.get();
52}
53
54GraphicsContext* GraphicsContext::createGraphicsContext(Traits* traits)
55{
56    if (s_WindowingSystemInterface.valid())
57        return s_WindowingSystemInterface->createGraphicsContext(traits);
58    else
59        return 0;   
60}
61
62
63std::string GraphicsContext::ScreenIdentifier::displayName() const
64{
65    std::stringstream ostr;
66    ostr<<hostName<<":"<<displayNum<<"."<<screenNum;
67    return ostr.str();
68}
69
70
71class ContextData
72{
73public:
74
75    ContextData():
76        _numContexts(0) {}
77
78    unsigned int _numContexts;
79   
80    void incrementUsageCount() {  ++_numContexts; }
81
82    void decrementUsageCount()
83    {
84        --_numContexts;
85
86        osg::notify(osg::INFO)<<"decrementUsageCount()"<<_numContexts<<std::endl;
87
88        if (_numContexts <= 1 && _compileContext.valid())
89        {
90            osg::notify(osg::INFO)<<"resetting compileContext "<<_compileContext.get()<<" refCount "<<_compileContext->referenceCount()<<std::endl;
91           
92            GraphicsContext* gc = _compileContext.get();
93            _compileContext = 0;
94        }
95    }
96   
97    osg::ref_ptr<osg::GraphicsContext> _compileContext;
98
99};
100
101
102typedef std::map<unsigned int, ContextData>  ContextIDMap;
103static ContextIDMap s_contextIDMap;
104static OpenThreads::ReentrantMutex s_contextIDMapMutex;
105static GraphicsContext::GraphicsContexts s_registeredContexts;
106
107unsigned int GraphicsContext::createNewContextID()
108{
109    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
110   
111    // first check to see if we can reuse contextID;
112    for(ContextIDMap::iterator itr = s_contextIDMap.begin();
113        itr != s_contextIDMap.end();
114        ++itr)
115    {
116        if (itr->second._numContexts == 0)
117        {
118
119            // reuse contextID;
120            itr->second._numContexts = 1;
121
122            osg::notify(osg::INFO)<<"GraphicsContext::createNewContextID() reusing contextID="<<itr->first<<std::endl;
123
124            return itr->first;
125        }
126    }
127
128    unsigned int contextID = s_contextIDMap.size();
129    s_contextIDMap[contextID]._numContexts = 1;
130   
131    osg::notify(osg::INFO)<<"GraphicsContext::createNewContextID() creating contextID="<<contextID<<std::endl;
132   
133
134    if ( (contextID+1) > osg::DisplaySettings::instance()->getMaxNumberOfGraphicsContexts() )
135    {
136        osg::notify(osg::INFO)<<"Updating the MaxNumberOfGraphicsContexts to "<<contextID+1<<std::endl;
137
138        // update the the maximum number of graphics contexts,
139        // to ensure that texture objects and display buffers are configured to the correct size.
140        osg::DisplaySettings::instance()->setMaxNumberOfGraphicsContexts( contextID + 1 );
141    }
142   
143
144    return contextID;   
145}
146
147unsigned int GraphicsContext::getMaxContextID()
148{
149    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
150
151    return s_contextIDMap.size();
152}
153
154
155void GraphicsContext::incrementContextIDUsageCount(unsigned int contextID)
156{
157    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
158   
159    osg::notify(osg::INFO)<<"GraphicsContext::incrementContextIDUsageCount("<<contextID<<") to "<<s_contextIDMap[contextID]._numContexts<<std::endl;
160
161    s_contextIDMap[contextID].incrementUsageCount();
162}
163
164void GraphicsContext::decrementContextIDUsageCount(unsigned int contextID)
165{
166
167    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
168
169    if (s_contextIDMap[contextID]._numContexts!=0)
170    {
171        s_contextIDMap[contextID].decrementUsageCount();
172    }
173    else
174    {
175        osg::notify(osg::NOTICE)<<"Warning: decrementContextIDUsageCount("<<contextID<<") called on expired contextID."<<std::endl;
176    }
177
178    osg::notify(osg::INFO)<<"GraphicsContext::decrementContextIDUsageCount("<<contextID<<") to "<<s_contextIDMap[contextID]._numContexts<<std::endl;
179
180}
181
182
183void GraphicsContext::registerGraphicsContext(GraphicsContext* gc)
184{
185    osg::notify(osg::INFO)<<"GraphicsContext::registerGraphicsContext "<<gc<<std::endl;
186
187    if (!gc) return;
188
189    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
190
191    GraphicsContexts::iterator itr = std::find(s_registeredContexts.begin(), s_registeredContexts.end(), gc);
192    if (itr != s_registeredContexts.end()) s_registeredContexts.erase(itr);
193
194    s_registeredContexts.push_back(gc);
195}
196
197void GraphicsContext::unregisterGraphicsContext(GraphicsContext* gc)
198{
199    osg::notify(osg::INFO)<<"GraphicsContext::unregisterGraphicsContext "<<gc<<std::endl;
200
201    if (!gc) return;
202
203    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
204
205    GraphicsContexts::iterator itr = std::find(s_registeredContexts.begin(), s_registeredContexts.end(), gc);
206    if (itr != s_registeredContexts.end()) s_registeredContexts.erase(itr);
207}
208
209GraphicsContext::GraphicsContexts GraphicsContext::getAllRegisteredGraphicsContexts()
210{
211    osg::notify(osg::INFO)<<"GraphicsContext::getAllRegisteredGraphicsContexts s_registeredContexts.size()="<<s_registeredContexts.size()<<std::endl;
212    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
213    return s_registeredContexts;
214}
215
216GraphicsContext::GraphicsContexts GraphicsContext::getRegisteredGraphicsContexts(unsigned int contextID)
217{
218    GraphicsContexts contexts;
219
220    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
221    for(GraphicsContexts::iterator itr = s_registeredContexts.begin();
222        itr != s_registeredContexts.end();
223        ++itr)
224    {
225        GraphicsContext* gc = *itr;
226        if (gc->getState() && gc->getState()->getContextID()==contextID) contexts.push_back(gc);
227    }
228
229    osg::notify(osg::INFO)<<"GraphicsContext::getRegisteredGraphicsContexts "<<contextID<<" contexts.size()="<<contexts.size()<<std::endl;
230   
231    return contexts;
232}
233
234GraphicsContext* GraphicsContext::getOrCreateCompileContext(unsigned int contextID)
235{
236    osg::notify(osg::INFO)<<"GraphicsContext::createCompileContext."<<std::endl;
237
238    {   
239        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
240        if (s_contextIDMap[contextID]._compileContext.valid()) return s_contextIDMap[contextID]._compileContext.get();
241    }
242   
243    GraphicsContext::GraphicsContexts contexts = GraphicsContext::getRegisteredGraphicsContexts(contextID);
244    if (contexts.empty()) return 0;
245   
246    GraphicsContext* src_gc = contexts.front();
247    const osg::GraphicsContext::Traits* src_traits = src_gc->getTraits();
248
249    osg::GraphicsContext::Traits* traits = new osg::GraphicsContext::Traits;
250    traits->screenNum = src_traits->screenNum;
251    traits->displayNum = src_traits->displayNum;
252    traits->hostName = src_traits->hostName;
253    traits->width = 100;
254    traits->height = 100;
255    traits->red = src_traits->red;
256    traits->green = src_traits->green;
257    traits->blue = src_traits->blue;
258    traits->alpha = src_traits->alpha;
259    traits->depth = src_traits->depth;
260    traits->sharedContext = src_gc;
261    traits->pbuffer = true;
262
263    osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits);
264    gc->realize();
265
266    {   
267        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
268        s_contextIDMap[contextID]._compileContext = gc;
269    }
270   
271    osg::notify(osg::INFO)<<"   succeded GraphicsContext::createCompileContext."<<std::endl;
272    return gc;
273}
274
275void GraphicsContext::setCompileContext(unsigned int contextID, GraphicsContext* gc)
276{
277    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
278    s_contextIDMap[contextID]._compileContext = gc;
279}
280
281GraphicsContext* GraphicsContext::getCompileContext(unsigned int contextID)
282{
283    //osg::notify(osg::NOTICE)<<"GraphicsContext::getCompileContext "<<contextID<<std::endl;
284    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
285    return s_contextIDMap[contextID]._compileContext.get();
286}
287
288
289/////////////////////////////////////////////////////////////////////////////
290//
291//  GraphicsContext standard method implementations
292//
293GraphicsContext::GraphicsContext():
294    _clearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
295    _clearMask(0),
296    _threadOfLastMakeCurrent(0)
297{
298    setThreadSafeRefUnref(true);
299    _operationsBlock = new RefBlock;
300
301    registerGraphicsContext(this);
302}
303
304GraphicsContext::GraphicsContext(const GraphicsContext&, const osg::CopyOp&):
305    _clearColor(osg::Vec4(0.0f,0.0f,0.0f,1.0f)),
306    _clearMask(0),
307    _threadOfLastMakeCurrent(0)
308{
309    setThreadSafeRefUnref(true);
310    _operationsBlock = new RefBlock;
311
312    registerGraphicsContext(this);
313}
314
315GraphicsContext::~GraphicsContext()
316{
317    close(false);
318
319    unregisterGraphicsContext(this);
320}
321
322void GraphicsContext::clear()
323{
324    if (_clearMask==0 || !_traits) return;
325
326    glViewport(0, 0, _traits->width, _traits->height);
327    glScissor(0, 0, _traits->width, _traits->height);
328
329    glClearColor( _clearColor[0], _clearColor[1], _clearColor[2], _clearColor[3]);
330
331    glClear( _clearMask );
332}
333
334bool GraphicsContext::realize()
335{
336    if (realizeImplementation())
337    {
338        return true;
339    }
340    else
341    {   
342        return false;
343    }
344}
345
346void GraphicsContext::close(bool callCloseImplementation)
347{
348    osg::notify(osg::INFO)<<"close("<<callCloseImplementation<<")"<<this<<std::endl;
349
350    // switch off the graphics thread...
351    setGraphicsThread(0);
352   
353   
354    bool sharedContextExists = false;
355   
356    if (_state.valid())
357    {
358        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(s_contextIDMapMutex);
359        if (s_contextIDMap[_state->getContextID()]._numContexts>1) sharedContextExists = true;
360    }
361
362    // release all the OpenGL objects in the scene graphs associted with this
363    for(Cameras::iterator itr = _cameras.begin();
364        itr != _cameras.end();
365        ++itr)
366    {
367        Camera* camera = (*itr);
368        if (camera)
369        {
370            osg::notify(osg::INFO)<<"Releasing GL objects for Camera="<<camera<<" _state="<<_state.get()<<std::endl;
371            camera->releaseGLObjects(_state.get());
372        }
373    }
374
375
376    if (callCloseImplementation && _state.valid() && isRealized())
377    {
378        osg::notify(osg::INFO)<<"Closing still viable window "<<sharedContextExists<<" _state->getContextID()="<<_state->getContextID()<<std::endl;
379
380        makeCurrent();
381       
382        osg::notify(osg::INFO)<<"Doing Flush"<<std::endl;
383
384        // flush all the OpenGL object buffer for this context.
385        double availableTime = 100.0f;
386        double currentTime = _state->getFrameStamp()?_state->getFrameStamp()->getReferenceTime():0.0;
387
388        osg::FrameBufferObject::flushDeletedFrameBufferObjects(_state->getContextID(),currentTime,availableTime);
389        osg::RenderBuffer::flushDeletedRenderBuffers(_state->getContextID(),currentTime,availableTime);
390        osg::Texture::flushAllDeletedTextureObjects(_state->getContextID());
391        osg::Drawable::flushAllDeletedDisplayLists(_state->getContextID());
392        osg::Drawable::flushDeletedVertexBufferObjects(_state->getContextID(),currentTime,availableTime);
393        osg::VertexProgram::flushDeletedVertexProgramObjects(_state->getContextID(),currentTime,availableTime);
394        osg::FragmentProgram::flushDeletedFragmentProgramObjects(_state->getContextID(),currentTime,availableTime);
395        osg::Program::flushDeletedGlPrograms(_state->getContextID(),currentTime,availableTime);
396        osg::Shader::flushDeletedGlShaders(_state->getContextID(),currentTime,availableTime);
397
398        osg::notify(osg::INFO)<<"Done Flush "<<availableTime<<std::endl;
399
400        _state->reset();
401       
402        releaseContext();
403    }
404   
405    if (callCloseImplementation) closeImplementation();
406
407    if (_state.valid())
408    {
409        decrementContextIDUsageCount(_state->getContextID());
410       
411        _state = 0;
412    }
413}
414
415
416bool GraphicsContext::makeCurrent()
417{
418    bool result = makeCurrentImplementation();
419   
420    if (result)
421    {
422        _threadOfLastMakeCurrent = OpenThreads::Thread::CurrentThread();
423    }
424   
425    return result;
426}
427
428bool GraphicsContext::makeContextCurrent(GraphicsContext* readContext)
429{
430    bool result = makeContextCurrentImplementation(readContext);
431
432    if (result)
433    {
434        _threadOfLastMakeCurrent = OpenThreads::Thread::CurrentThread();
435    }
436   
437    return result;
438}
439
440bool GraphicsContext::releaseContext()
441{
442    bool result = releaseContextImplementation();
443   
444    _threadOfLastMakeCurrent = (OpenThreads::Thread*)(-1);
445   
446    return result;
447}
448
449void GraphicsContext::swapBuffers()
450{
451    if (isCurrent())
452    {
453        swapBuffersImplementation();
454        clear();
455    }
456    else if (_graphicsThread.valid() &&
457             _threadOfLastMakeCurrent == _graphicsThread.get())
458    {
459        _graphicsThread->add(new SwapBuffersOperation);
460    }
461    else
462    {
463        makeCurrent();
464        swapBuffersImplementation();
465        clear();
466    }
467}
468
469
470
471void GraphicsContext::createGraphicsThread()
472{
473    if (!_graphicsThread)
474    {
475        setGraphicsThread(new OperationsThread);
476    }
477}
478
479void GraphicsContext::setGraphicsThread(OperationsThread* gt)
480{
481    if (_graphicsThread==gt) return;
482
483    if (_graphicsThread.valid())
484    {
485        // need to kill the thread in some way...
486        _graphicsThread->cancel();
487        _graphicsThread->setParent(0);
488    }
489
490    _graphicsThread = gt;
491   
492    if (_graphicsThread.valid())
493    {
494        _graphicsThread->setParent(this);
495    }
496}
497
498void GraphicsContext::add(Operation* operation)
499{
500    osg::notify(osg::INFO)<<"Doing add"<<std::endl;
501
502    // aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
503    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
504
505    // add the operation to the end of the list
506    _operations.push_back(operation);
507
508    _operationsBlock->set(true);
509}
510
511void GraphicsContext::remove(Operation* operation)
512{
513    osg::notify(osg::INFO)<<"Doing remove operation"<<std::endl;
514
515    // aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
516    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
517
518    for(OperationQueue::iterator itr = _operations.begin();
519        itr!=_operations.end();)
520    {
521        if ((*itr)==operation) itr = _operations.erase(itr);
522        else ++itr;
523    }
524
525    if (_operations.empty())
526    {
527        _operationsBlock->set(false);
528    }
529}
530
531void GraphicsContext::remove(const std::string& name)
532{
533    osg::notify(osg::INFO)<<"Doing remove named operation"<<std::endl;
534   
535    // aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
536    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
537
538    // find the remove all operations with specificed name
539    for(OperationQueue::iterator itr = _operations.begin();
540        itr!=_operations.end();)
541    {
542        if ((*itr)->getName()==name) itr = _operations.erase(itr);
543        else ++itr;
544    }
545
546    if (_operations.empty())
547    {
548        _operationsBlock->set(false);
549    }
550}
551
552void GraphicsContext::removeAllOperations()
553{
554    osg::notify(osg::INFO)<<"Doing remove all operations"<<std::endl;
555
556    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
557    _operations.clear();
558    _operationsBlock->set(false);
559}
560
561void GraphicsContext::runOperations()
562{
563    for(OperationQueue::iterator itr = _operations.begin();
564        itr != _operations.end();
565        )
566    {
567        {
568            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
569            _currentOperation = *itr;
570
571            if (!_currentOperation->getKeep())
572            {
573                itr = _operations.erase(itr);
574
575                if (_operations.empty())
576                {
577                    _operationsBlock->set(false);
578                }
579            }
580            else
581            {
582                ++itr;
583            }
584        }
585               
586        if (_currentOperation.valid())
587        {
588            // osg::notify(osg::INFO)<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
589
590            // call the graphics operation.
591            (*_currentOperation)(this);
592
593            {           
594                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
595                _currentOperation = 0;
596            }
597        }
598    }
599}
600
601void GraphicsContext::addCamera(osg::Camera* camera)
602{
603    _cameras.push_back(camera);
604}
605
606void GraphicsContext::removeCamera(osg::Camera* camera)
607{
608    for(Cameras::iterator itr = _cameras.begin();
609        itr != _cameras.end();
610        ++itr)
611    {
612        if (*itr == camera)
613        {
614            _cameras.erase(itr);
615            return;
616        }
617    }
618}
619
620void GraphicsContext::resizedImplementation(int x, int y, int width, int height)
621{
622    if (!_traits) return;
623   
624    double widthChangeRatio = double(width) / double(_traits->width);
625    double heigtChangeRatio = double(height) / double(_traits->height);
626    double aspectRatioChange = widthChangeRatio / heigtChangeRatio;
627   
628    for(Cameras::iterator itr = _cameras.begin();
629        itr != _cameras.end();
630        ++itr)
631    {
632        Camera* camera = (*itr);
633        Viewport* viewport = camera->getViewport();
634        if (viewport)
635        {
636            if (viewport->x()==0 && viewport->y()==0 &&
637                viewport->width()>=_traits->width && viewport->height()>=_traits->height)
638            {
639                viewport->setViewport(0,0,width,height);
640            }
641            else
642            {
643                viewport->x() = static_cast<osg::Viewport::value_type>(double(viewport->x())*widthChangeRatio);
644                viewport->y() = static_cast<osg::Viewport::value_type>(double(viewport->y())*heigtChangeRatio);
645                viewport->width() = static_cast<osg::Viewport::value_type>(double(viewport->width())*widthChangeRatio);
646                viewport->height() = static_cast<osg::Viewport::value_type>(double(viewport->height())*heigtChangeRatio);
647            }
648        }
649
650        // if aspect ratio adjusted change the project matrix to suit.
651        if (aspectRatioChange != 1.0)
652        {
653            osg::View* view = camera->getView();
654            osg::View::Slave* slave = view ? view->findSlaveForCamera(camera) : 0;
655           
656            if (slave && camera->getReferenceFrame()==osg::Transform::RELATIVE_RF)
657            {
658                switch(view->getCamera()->getProjectionResizePolicy())
659                {
660                    case(osg::Camera::HORIZONTAL): slave->_projectionOffset *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
661                    case(osg::Camera::VERTICAL): slave->_projectionOffset *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
662                    default: break;
663                }
664            }
665            else
666            {
667                Camera::ProjectionResizePolicy policy = view ? view->getCamera()->getProjectionResizePolicy() : camera->getProjectionResizePolicy();
668                switch(policy)
669                {
670                    case(osg::Camera::HORIZONTAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0); break;
671                    case(osg::Camera::VERTICAL): camera->getProjectionMatrix() *= osg::Matrix::scale(1.0, aspectRatioChange,1.0); break;
672                    default: break;
673                }
674            }
675
676        }   
677
678    }
679   
680    _traits->x = x;
681    _traits->y = y;
682    _traits->width = width;
683    _traits->height = height;
684}
Note: See TracBrowser for help on using the browser.