root/OpenSceneGraph/trunk/src/osgUtil/RenderBin.cpp @ 11202

Revision 11202, 17.2 kB (checked in by robert, 5 years ago)

Clean up of initialization of statics/use of getenv

  • 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#include <stdlib.h>
14#include <string.h>
15
16#include <osgUtil/RenderBin>
17#include <osgUtil/RenderStage>
18#include <osgUtil/Statistics>
19
20#include <osg/Notify>
21#include <osg/ApplicationUsage>
22#include <osg/AlphaFunc>
23
24#include <algorithm>
25
26using namespace osg;
27using namespace osgUtil;
28
29class RenderBinPrototypeList : osg::depends_on<OpenThreads::Mutex*, osg::Referenced::getGlobalReferencedMutex>,
30                               public osg::Referenced, public std::map< std::string, osg::ref_ptr<RenderBin> >
31{
32    public:
33        RenderBinPrototypeList()
34        {
35            add("RenderBin",new RenderBin(RenderBin::getDefaultRenderBinSortMode()));
36            add("StateSortedBin",new RenderBin(RenderBin::SORT_BY_STATE));
37            add("DepthSortedBin",new RenderBin(RenderBin::SORT_BACK_TO_FRONT));
38            add("TraversalOrderBin",new RenderBin(RenderBin::TRAVERSAL_ORDER));
39        }
40
41        void add(const std::string& name, RenderBin* bin)
42        {
43            (*this)[name] = bin;
44        }
45
46        ~RenderBinPrototypeList() {}
47};
48
49static RenderBinPrototypeList* renderBinPrototypeList()
50{
51    static osg::ref_ptr<RenderBinPrototypeList> s_renderBinPrototypeList = new  RenderBinPrototypeList;
52    return s_renderBinPrototypeList.get();
53}
54
55RenderBin* RenderBin::getRenderBinPrototype(const std::string& binName)
56{
57    RenderBinPrototypeList* list = renderBinPrototypeList();
58    if (list)
59    {
60        RenderBinPrototypeList::iterator itr = list->find(binName);
61        if (itr != list->end()) return itr->second.get();
62    }
63    return NULL;
64}
65
66RenderBin* RenderBin::createRenderBin(const std::string& binName)
67{
68    RenderBinPrototypeList* list = renderBinPrototypeList();
69    if (list)
70    {
71        RenderBin* prototype = getRenderBinPrototype(binName);
72        if (prototype) return dynamic_cast<RenderBin*>(prototype->clone(osg::CopyOp::DEEP_COPY_ALL));
73    }
74   
75    osg::notify(osg::WARN) <<"Warning: RenderBin \""<<binName<<"\" implementation not found, using default RenderBin as a fallback."<<std::endl;
76    return new RenderBin;
77}
78
79void RenderBin::addRenderBinPrototype(const std::string& binName,RenderBin* proto)
80{
81    RenderBinPrototypeList* list = renderBinPrototypeList();
82    if (list && proto)
83    {
84        (*list)[binName] = proto;
85    }
86}
87
88void RenderBin::removeRenderBinPrototype(RenderBin* proto)
89{
90    RenderBinPrototypeList* list = renderBinPrototypeList();
91    if (list && proto)
92    {
93        for(RenderBinPrototypeList::iterator itr = list->begin();
94            itr != list->end();
95            ++itr)
96        {
97            if (itr->second == proto)
98            {
99                // osg::notify(osg::NOTICE)<<"Found protype, now erasing "<<itr->first<<std::endl;
100                list->erase(itr);
101                return;
102            }
103        }
104    }
105    // osg::notify(osg::NOTICE)<<"Not found protype"<<std::endl;
106}
107
108static bool s_defaultBinSortModeInitialized = false;
109static RenderBin::SortMode s_defaultBinSortMode = RenderBin::SORT_BY_STATE;
110static osg::ApplicationUsageProxy RenderBin_e0(osg::ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_DEFAULT_BIN_SORT_MODE <type>","SORT_BY_STATE | SORT_BY_STATE_THEN_FRONT_TO_BACK | SORT_FRONT_TO_BACK | SORT_BACK_TO_FRONT");
111
112void RenderBin::setDefaultRenderBinSortMode(RenderBin::SortMode mode)
113{
114    s_defaultBinSortModeInitialized = true;
115    s_defaultBinSortMode = mode;
116}
117
118
119RenderBin::SortMode RenderBin::getDefaultRenderBinSortMode()
120{
121    if (!s_defaultBinSortModeInitialized)
122    {
123        s_defaultBinSortModeInitialized = true;
124       
125        const char* str = getenv("OSG_DEFAULT_BIN_SORT_MODE");
126        if (str)
127        {
128            if (strcmp(str,"SORT_BY_STATE")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE;
129            else if (strcmp(str,"SORT_BY_STATE_THEN_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_BY_STATE_THEN_FRONT_TO_BACK;
130            else if (strcmp(str,"SORT_FRONT_TO_BACK")==0) s_defaultBinSortMode = RenderBin::SORT_FRONT_TO_BACK;
131            else if (strcmp(str,"SORT_BACK_TO_FRONT")==0) s_defaultBinSortMode = RenderBin::SORT_BACK_TO_FRONT;
132            else if (strcmp(str,"TRAVERSAL_ORDER")==0) s_defaultBinSortMode = RenderBin::TRAVERSAL_ORDER;
133        }
134    }
135   
136    return s_defaultBinSortMode;
137}
138
139RenderBin::RenderBin()
140{
141    _binNum = 0;
142    _parent = NULL;
143    _stage = NULL;
144    _sorted = false;
145    _sortMode = getDefaultRenderBinSortMode();
146}
147
148RenderBin::RenderBin(SortMode mode)
149{
150    _binNum = 0;
151    _parent = NULL;
152    _stage = NULL;
153    _sorted = false;
154    _sortMode = mode;
155
156#if 1
157    if (_sortMode==SORT_BACK_TO_FRONT)
158    {
159        _stateset  = new osg::StateSet;
160        _stateset->setThreadSafeRefUnref(true);
161       
162         // set up an alphafunc by default to speed up blending operations.
163        osg::AlphaFunc* alphafunc = new osg::AlphaFunc;
164        alphafunc->setFunction(osg::AlphaFunc::GREATER,0.0f);
165        alphafunc->setThreadSafeRefUnref(true);
166       
167        _stateset->setAttributeAndModes(alphafunc, osg::StateAttribute::ON);
168    }
169#endif   
170}
171
172RenderBin::RenderBin(const RenderBin& rhs,const CopyOp& copyop):
173        Object(rhs,copyop),
174        _binNum(rhs._binNum),
175        _parent(rhs._parent),
176        _stage(rhs._stage),
177        _bins(rhs._bins),
178        _stateGraphList(rhs._stateGraphList),
179        _renderLeafList(rhs._renderLeafList),
180        _sorted(rhs._sorted),
181        _sortMode(rhs._sortMode),
182        _sortCallback(rhs._sortCallback),
183        _drawCallback(rhs._drawCallback),
184        _stateset(rhs._stateset)
185{
186
187}
188
189RenderBin::~RenderBin()
190{
191}
192
193void RenderBin::reset()
194{
195    _stateGraphList.clear();
196    _renderLeafList.clear();
197    _bins.clear();
198    _sorted = false;
199}
200
201void RenderBin::sort()
202{
203    if (_sorted) return;
204
205    for(RenderBinList::iterator itr = _bins.begin();
206        itr!=_bins.end();
207        ++itr)
208    {
209        itr->second->sort();
210    }
211   
212    if (_sortCallback.valid())
213    {
214        _sortCallback->sortImplementation(this);
215    }
216    else sortImplementation();
217   
218    _sorted = true;
219}
220
221void RenderBin::setSortMode(SortMode mode)
222{
223    _sortMode = mode;
224}
225
226void RenderBin::sortImplementation()
227{
228    switch(_sortMode)
229    {
230        case(SORT_BY_STATE):
231            sortByState();
232            break;
233        case(SORT_BY_STATE_THEN_FRONT_TO_BACK):
234            sortByStateThenFrontToBack();
235            break;
236        case(SORT_FRONT_TO_BACK):
237            sortFrontToBack();
238            break;
239        case(SORT_BACK_TO_FRONT):
240            sortBackToFront();
241            break;
242        case(TRAVERSAL_ORDER):
243            sortTraversalOrder();
244            break;
245    }
246}
247
248struct SortByStateFunctor
249{
250    bool operator() (const StateGraph* lhs,const StateGraph* rhs) const
251    {
252        return (*(lhs->_stateset)<*(rhs->_stateset));
253    }
254};
255
256void RenderBin::sortByState()
257{
258    //osg::notify(osg::NOTICE)<<"sortByState()"<<std::endl;
259    // actually we'll do nothing right now, as fine grained sorting by state
260    // appears to cost more to do than it saves in draw.  The contents of
261    // the StateGraph leaves is already coarse grained sorted, this
262    // sorting is as a function of the cull traversal.
263    // cout << "doing sortByState "<<this<<endl;
264}
265
266
267struct StateGraphFrontToBackSortFunctor
268{
269    bool operator() (const StateGraph* lhs,const StateGraph* rhs) const
270    {
271        return (lhs->_minimumDistance<rhs->_minimumDistance);
272    }
273};
274
275void RenderBin::sortByStateThenFrontToBack()
276{
277    for(StateGraphList::iterator itr=_stateGraphList.begin();
278        itr!=_stateGraphList.end();
279        ++itr)
280    {
281        (*itr)->sortFrontToBack();
282        (*itr)->getMinimumDistance();
283    }
284    std::sort(_stateGraphList.begin(),_stateGraphList.end(),StateGraphFrontToBackSortFunctor());
285}
286
287struct FrontToBackSortFunctor
288{
289    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
290    {
291        return (lhs->_depth<rhs->_depth);
292    }
293};
294
295   
296void RenderBin::sortFrontToBack()
297{
298    copyLeavesFromStateGraphListToRenderLeafList();
299
300    // now sort the list into acending depth order.
301    std::sort(_renderLeafList.begin(),_renderLeafList.end(),FrontToBackSortFunctor());
302   
303//    cout << "sort front to back"<<endl;
304}
305
306struct BackToFrontSortFunctor
307{
308    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
309    {
310        return (rhs->_depth<lhs->_depth);
311    }
312};
313
314void RenderBin::sortBackToFront()
315{
316    copyLeavesFromStateGraphListToRenderLeafList();
317
318    // now sort the list into acending depth order.
319    std::sort(_renderLeafList.begin(),_renderLeafList.end(),BackToFrontSortFunctor());
320
321//    cout << "sort back to front"<<endl;
322}
323
324
325struct TraversalOrderFunctor
326{
327    bool operator() (const RenderLeaf* lhs,const RenderLeaf* rhs) const
328    {
329        return (lhs->_traversalNumber<rhs->_traversalNumber);
330    }
331};
332
333void RenderBin::sortTraversalOrder()
334{
335    copyLeavesFromStateGraphListToRenderLeafList();
336
337    // now sort the list into acending depth order.
338    std::sort(_renderLeafList.begin(),_renderLeafList.end(),TraversalOrderFunctor());
339}
340
341void RenderBin::copyLeavesFromStateGraphListToRenderLeafList()
342{
343    _renderLeafList.clear();
344
345    int totalsize=0;
346    StateGraphList::iterator itr;
347    for(itr=_stateGraphList.begin();
348        itr!=_stateGraphList.end();
349        ++itr)
350    {
351        totalsize += (*itr)->_leaves.size();
352    }
353
354    _renderLeafList.reserve(totalsize);
355   
356    bool detectedNaN = false;
357       
358    // first copy all the leaves from the render graphs into the leaf list.
359    for(itr=_stateGraphList.begin();
360        itr!=_stateGraphList.end();
361        ++itr)
362    {
363        for(StateGraph::LeafList::iterator dw_itr = (*itr)->_leaves.begin();
364            dw_itr != (*itr)->_leaves.end();
365            ++dw_itr)
366        {
367            if (!osg::isNaN((*dw_itr)->_depth))
368            {
369                _renderLeafList.push_back(dw_itr->get());
370            }
371            else
372            {
373                detectedNaN = true;
374            }
375        }
376    }
377   
378    if (detectedNaN) osg::notify(osg::NOTICE)<<"Warning: RenderBin::copyLeavesFromStateGraphListToRenderLeafList() detected NaN depth values, database may be corrupted."<<std::endl;
379   
380    // empty the render graph list to prevent it being drawn along side the render leaf list (see drawImplementation.)
381    _stateGraphList.clear();
382}
383
384RenderBin* RenderBin::find_or_insert(int binNum,const std::string& binName)
385{
386    // search for appropriate bin.
387    RenderBinList::iterator itr = _bins.find(binNum);
388    if (itr!=_bins.end()) return itr->second.get();
389
390    // create a rendering bin and insert into bin list.
391    RenderBin* rb = RenderBin::createRenderBin(binName);
392    if (rb)
393    {
394
395        RenderStage* rs = dynamic_cast<RenderStage*>(rb);
396        if (rs)
397        {
398            rs->_binNum = binNum;
399            rs->_parent = NULL;
400            rs->_stage = rs;
401            _stage->addPreRenderStage(rs);
402        }
403        else
404        {
405            rb->_binNum = binNum;
406            rb->_parent = this;
407            rb->_stage = _stage;
408            _bins[binNum] = rb;
409        }
410    }
411    return rb;
412}
413
414void RenderBin::draw(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
415{
416    if (_drawCallback.valid())
417    {
418        _drawCallback->drawImplementation(this,renderInfo,previous);
419    }
420    else drawImplementation(renderInfo,previous);
421}
422
423void RenderBin::drawImplementation(osg::RenderInfo& renderInfo,RenderLeaf*& previous)
424{
425    osg::State& state = *renderInfo.getState();
426
427    // osg::notify(osg::NOTICE)<<"begin RenderBin::drawImplementation "<<className()<<" sortMode "<<getSortMode()<<std::endl;
428
429
430    unsigned int numToPop = (previous ? StateGraph::numToPop(previous->_parent) : 0);
431    if (numToPop>1) --numToPop;
432    unsigned int insertStateSetPosition = state.getStateSetStackSize() - numToPop;
433
434    if (_stateset.valid())
435    {
436        state.insertStateSet(insertStateSetPosition, _stateset.get());
437    }
438
439
440    // draw first set of draw bins.
441    RenderBinList::iterator rbitr;
442    for(rbitr = _bins.begin();
443        rbitr!=_bins.end() && rbitr->first<0;
444        ++rbitr)
445    {
446        rbitr->second->draw(renderInfo,previous);
447    }
448
449    // draw fine grained ordering.
450    for(RenderLeafList::iterator rlitr= _renderLeafList.begin();
451        rlitr!= _renderLeafList.end();
452        ++rlitr)
453    {
454        RenderLeaf* rl = *rlitr;
455        rl->render(renderInfo,previous);
456        previous = rl;
457    }
458
459
460    bool draw_forward = true; //(_sortMode!=SORT_BY_STATE) || (state.getFrameStamp()->getFrameNumber() % 2)==0;
461
462    // draw coarse grained ordering.
463    if (draw_forward)
464    {
465        for(StateGraphList::iterator oitr=_stateGraphList.begin();
466            oitr!=_stateGraphList.end();
467            ++oitr)
468        {
469
470            for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
471                dw_itr != (*oitr)->_leaves.end();
472                ++dw_itr)
473            {
474                RenderLeaf* rl = dw_itr->get();
475                rl->render(renderInfo,previous);
476                previous = rl;
477
478            }
479        }
480    }
481    else
482    {
483        for(StateGraphList::reverse_iterator oitr=_stateGraphList.rbegin();
484            oitr!=_stateGraphList.rend();
485            ++oitr)
486        {
487
488            for(StateGraph::LeafList::iterator dw_itr = (*oitr)->_leaves.begin();
489                dw_itr != (*oitr)->_leaves.end();
490                ++dw_itr)
491            {
492                RenderLeaf* rl = dw_itr->get();
493                rl->render(renderInfo,previous);
494                previous = rl;
495
496            }
497        }
498    }
499
500    // draw post bins.
501    for(;
502        rbitr!=_bins.end();
503        ++rbitr)
504    {
505        rbitr->second->draw(renderInfo,previous);
506    }
507
508    if (_stateset.valid())
509    {
510        state.removeStateSet(insertStateSetPosition);
511        // state.apply();
512    }
513
514
515    // osg::notify(osg::NOTICE)<<"end RenderBin::drawImplementation "<<className()<<std::endl;
516}
517
518// stats
519bool RenderBin::getStats(Statistics& stats) const
520{
521    stats.addBins(1);
522
523    // different by return type - collects the stats in this renderrBin
524    bool statsCollected = false;
525
526    // draw fine grained ordering.
527    for(RenderLeafList::const_iterator dw_itr = _renderLeafList.begin();
528        dw_itr != _renderLeafList.end();
529        ++dw_itr)
530    {
531        const RenderLeaf* rl = *dw_itr;
532        const Drawable* dw= rl->getDrawable();
533        stats.addDrawable(); // number of geosets
534        if (rl->_modelview.get())
535        {
536            stats.addMatrix(); // number of matrices
537        }
538       
539        if (dw)
540        {
541              // then tot up the primitive types and no vertices.
542              dw->accept(stats); // use sub-class to find the stats for each drawable
543        }
544        statsCollected = true;
545    }
546
547    for(StateGraphList::const_iterator oitr=_stateGraphList.begin();
548        oitr!=_stateGraphList.end();
549        ++oitr)
550    {
551       
552        for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin();
553            dw_itr != (*oitr)->_leaves.end();
554            ++dw_itr)
555        {
556            const RenderLeaf* rl = dw_itr->get();
557            const Drawable* dw= rl->getDrawable();
558            stats.addDrawable(); // number of geosets
559            if (rl->_modelview.get()) stats.addMatrix(); // number of matrices
560            if (dw)
561            {
562                // then tot up the primitive types and no vertices.
563                dw->accept(stats); // use sub-class to find the stats for each drawable
564            }
565        }
566        statsCollected = true;
567    }
568
569    // now collects stats for any subbins.
570    for(RenderBinList::const_iterator itr = _bins.begin();
571        itr!=_bins.end();
572        ++itr)
573    {
574        if (itr->second->getStats(stats))
575        {
576            statsCollected = true;
577        }
578    }
579
580    return statsCollected;
581}
582
583unsigned int RenderBin::computeNumberOfDynamicRenderLeaves() const
584{
585    unsigned int count = 0;
586
587    // draw first set of draw bins.
588    RenderBinList::const_iterator rbitr;
589    for(rbitr = _bins.begin();
590        rbitr!=_bins.end() && rbitr->first<0;
591        ++rbitr)
592    {
593        count += rbitr->second->computeNumberOfDynamicRenderLeaves();
594    }
595
596    // draw fine grained ordering.
597    for(RenderLeafList::const_iterator rlitr= _renderLeafList.begin();
598        rlitr!= _renderLeafList.end();
599        ++rlitr)
600    {
601        RenderLeaf* rl = *rlitr;
602        if (rl->_dynamic) ++count;
603    }
604
605
606    // draw coarse grained ordering.
607    for(StateGraphList::const_iterator oitr=_stateGraphList.begin();
608        oitr!=_stateGraphList.end();
609        ++oitr)
610    {
611
612        for(StateGraph::LeafList::const_iterator dw_itr = (*oitr)->_leaves.begin();
613            dw_itr != (*oitr)->_leaves.end();
614            ++dw_itr)
615        {
616            RenderLeaf* rl = dw_itr->get();
617            if (rl->_dynamic) ++count;
618        }
619    }
620
621    // draw post bins.
622    for(;
623        rbitr!=_bins.end();
624        ++rbitr)
625    {
626        count += rbitr->second->computeNumberOfDynamicRenderLeaves();
627    }
628   
629    return count;
630}
Note: See TracBrowser for help on using the browser.