| | 440 | // GLBufferObjectSet |
| | 441 | // |
| | 442 | GLBufferObjectSet::GLBufferObjectSet(GLBufferObjectManager* parent, const BufferObjectProfile& profile): |
| | 443 | _parent(parent), |
| | 444 | _contextID(parent->getContextID()), |
| | 445 | _profile(profile), |
| | 446 | _numOfGLBufferObjects(0), |
| | 447 | _head(0), |
| | 448 | _tail(0) |
| | 449 | { |
| | 450 | osg::notify(osg::NOTICE)<<"GLBufferObjectSet::GLBufferObjectSet _profile._size="<<_profile._size<<std::endl; |
| | 451 | } |
| | 452 | |
| | 453 | GLBufferObjectSet::~GLBufferObjectSet() |
| | 454 | { |
| | 455 | #if 0 |
| | 456 | osg::notify(osg::NOTICE)<<"GLBufferObjectSet::~GLBufferObjectSet(), _numOfGLBufferObjects="<<_numOfGLBufferObjects<<std::endl; |
| | 457 | osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects = "<<_orphanedGLBufferObjects.size()<<std::endl; |
| | 458 | osg::notify(osg::NOTICE)<<" _head = "<<_head<<std::endl; |
| | 459 | osg::notify(osg::NOTICE)<<" _tail = "<<_tail<<std::endl; |
| | 460 | #endif |
| | 461 | } |
| | 462 | |
| | 463 | bool GLBufferObjectSet::checkConsistency() const |
| | 464 | { |
| | 465 | return true; |
| | 466 | |
| | 467 | // osg::notify(osg::NOTICE)<<"GLBufferObjectSet::checkConsistency()"<<std::endl; |
| | 468 | // check consistency of linked list. |
| | 469 | unsigned int numInList = 0; |
| | 470 | GLBufferObject* to = _head; |
| | 471 | while(to!=0) |
| | 472 | { |
| | 473 | ++numInList; |
| | 474 | |
| | 475 | if (to->_next) |
| | 476 | { |
| | 477 | if ((to->_next)->_previous != to) |
| | 478 | { |
| | 479 | osg::notify(osg::NOTICE)<<"Error (to->_next)->_previous != to "<<std::endl; |
| | 480 | throw "Error (to->_next)->_previous != to "; |
| | 481 | } |
| | 482 | } |
| | 483 | else |
| | 484 | { |
| | 485 | if (_tail != to) |
| | 486 | { |
| | 487 | osg::notify(osg::NOTICE)<<"Error _trail != to"<<std::endl; |
| | 488 | throw "Error _trail != to"; |
| | 489 | } |
| | 490 | } |
| | 491 | |
| | 492 | to = to->_next; |
| | 493 | } |
| | 494 | |
| | 495 | unsigned int totalNumber = numInList + _orphanedGLBufferObjects.size(); |
| | 496 | if (totalNumber != _numOfGLBufferObjects) |
| | 497 | { |
| | 498 | osg::notify(osg::NOTICE)<<"Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects"<<std::endl; |
| | 499 | osg::notify(osg::NOTICE)<<" numInList = "<<numInList<<std::endl; |
| | 500 | osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects.size() = "<<_orphanedGLBufferObjects.size()<<std::endl; |
| | 501 | osg::notify(osg::NOTICE)<<" _pendingOrphanedGLBufferObjects.size() = "<<_pendingOrphanedGLBufferObjects.size()<<std::endl; |
| | 502 | osg::notify(osg::NOTICE)<<" _numOfGLBufferObjects = "<<_numOfGLBufferObjects<<std::endl; |
| | 503 | throw "Error numInList + _orphanedGLBufferObjects.size() != _numOfGLBufferObjects"; |
| | 504 | } |
| | 505 | |
| | 506 | return true; |
| | 507 | } |
| | 508 | |
| | 509 | void GLBufferObjectSet::handlePendingOrphandedGLBufferObjects() |
| | 510 | { |
| | 511 | // osg::notify(osg::NOTICE)<<"handlePendingOrphandedGLBufferObjects()"<<_pendingOrphanedGLBufferObjects.size()<<std::endl; |
| | 512 | |
| | 513 | if (_pendingOrphanedGLBufferObjects.empty()) return; |
| | 514 | |
| | 515 | unsigned int numOrphaned = _pendingOrphanedGLBufferObjects.size(); |
| | 516 | |
| | 517 | for(GLBufferObjectList::iterator itr = _pendingOrphanedGLBufferObjects.begin(); |
| | 518 | itr != _pendingOrphanedGLBufferObjects.end(); |
| | 519 | ++itr) |
| | 520 | { |
| | 521 | GLBufferObject* to = itr->get(); |
| | 522 | |
| | 523 | _orphanedGLBufferObjects.push_back(to); |
| | 524 | |
| | 525 | remove(to); |
| | 526 | |
| | 527 | #if 0 |
| | 528 | osg::notify(osg::NOTICE)<<" HPOTO after _head = "<<_head<<std::endl; |
| | 529 | osg::notify(osg::NOTICE)<<" HPOTO after _tail = "<<_tail<<std::endl; |
| | 530 | osg::notify(osg::NOTICE)<<" HPOTO after to->_previous = "<<to->_previous<<std::endl; |
| | 531 | osg::notify(osg::NOTICE)<<" HPOTO after to->_next = "<<to->_next<<std::endl; |
| | 532 | #endif |
| | 533 | |
| | 534 | } |
| | 535 | |
| | 536 | |
| | 537 | // update the GLBufferObjectManager's running total of active + orphaned GLBufferObjects |
| | 538 | _parent->getNumberOrphanedGLBufferObjects() += numOrphaned; |
| | 539 | _parent->getNumberActiveGLBufferObjects() -= numOrphaned; |
| | 540 | |
| | 541 | _pendingOrphanedGLBufferObjects.clear(); |
| | 542 | |
| | 543 | checkConsistency(); |
| | 544 | } |
| | 545 | |
| | 546 | void GLBufferObjectSet::flushAllDeletedGLBufferObjects() |
| | 547 | { |
| | 548 | for(GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin(); |
| | 549 | itr != _orphanedGLBufferObjects.end(); |
| | 550 | ++itr) |
| | 551 | { |
| | 552 | |
| | 553 | (*itr)->deleteGLObject(); |
| | 554 | |
| | 555 | osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<(*itr)->getGLObjectID()<<std::endl; |
| | 556 | } |
| | 557 | |
| | 558 | unsigned int numDeleted = _orphanedGLBufferObjects.size(); |
| | 559 | _numOfGLBufferObjects -= numDeleted; |
| | 560 | |
| | 561 | // update the GLBufferObjectManager's running total of current pool size |
| | 562 | _parent->getCurrGLBufferObjectPoolSize() -= numDeleted*_profile._size; |
| | 563 | _parent->getNumberOrphanedGLBufferObjects() -= numDeleted; |
| | 564 | _parent->getNumberDeleted() += numDeleted; |
| | 565 | |
| | 566 | _orphanedGLBufferObjects.clear(); |
| | 567 | } |
| | 568 | |
| | 569 | void GLBufferObjectSet::discardAllDeletedGLBufferObjects() |
| | 570 | { |
| | 571 | unsigned int numDiscarded = _orphanedGLBufferObjects.size(); |
| | 572 | |
| | 573 | _numOfGLBufferObjects -= numDiscarded; |
| | 574 | |
| | 575 | // update the GLBufferObjectManager's running total of current pool size |
| | 576 | _parent->setCurrGLBufferObjectPoolSize( _parent->getCurrGLBufferObjectPoolSize() - numDiscarded*_profile._size ); |
| | 577 | |
| | 578 | // update the number of active and orphaned TextureOjects |
| | 579 | _parent->getNumberOrphanedGLBufferObjects() -= 1; |
| | 580 | _parent->getNumberActiveGLBufferObjects() += 1; |
| | 581 | _parent->getNumberDeleted() += 1; |
| | 582 | |
| | 583 | |
| | 584 | // just clear the list as there is nothing else we can do with them when discarding them |
| | 585 | _orphanedGLBufferObjects.clear(); |
| | 586 | } |
| | 587 | |
| | 588 | void GLBufferObjectSet::flushDeletedGLBufferObjects(double currentTime, double& availableTime) |
| | 589 | { |
| | 590 | // if nothing to delete return |
| | 591 | if (_orphanedGLBufferObjects.empty()) return; |
| | 592 | |
| | 593 | // if no time available don't try to flush objects. |
| | 594 | if (availableTime<=0.0) return; |
| | 595 | |
| | 596 | // if we don't have too many orphaned texture objects then don't bother deleting them, as we can potentially reuse them later. |
| | 597 | if (_parent->getNumberOrphanedGLBufferObjects()<=s_minimumNumberOfGLBufferObjectsToRetainInCache) return; |
| | 598 | |
| | 599 | unsigned int numDeleted = 0; |
| | 600 | unsigned int maxNumObjectsToDelete = _parent->getNumberOrphanedGLBufferObjects()-s_minimumNumberOfGLBufferObjectsToRetainInCache; |
| | 601 | if (maxNumObjectsToDelete>4) maxNumObjectsToDelete = 4; |
| | 602 | |
| | 603 | ElapsedTime timer; |
| | 604 | |
| | 605 | GLBufferObjectList::iterator itr = _orphanedGLBufferObjects.begin(); |
| | 606 | for(; |
| | 607 | itr != _orphanedGLBufferObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete; |
| | 608 | ++itr) |
| | 609 | { |
| | 610 | |
| | 611 | osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<itr->get()<<std::endl; |
| | 612 | |
| | 613 | (*itr)->deleteGLObject(); |
| | 614 | |
| | 615 | ++numDeleted; |
| | 616 | } |
| | 617 | |
| | 618 | // osg::notify(osg::NOTICE)<<"Size before = "<<_orphanedGLBufferObjects.size(); |
| | 619 | _orphanedGLBufferObjects.erase(_orphanedGLBufferObjects.begin(), itr); |
| | 620 | //osg::notify(osg::NOTICE)<<", after = "<<_orphanedGLBufferObjects.size()<<" numDeleted = "<<numDeleted<<std::endl; |
| | 621 | |
| | 622 | // update the number of TO's in this GLBufferObjectSet |
| | 623 | _numOfGLBufferObjects -= numDeleted; |
| | 624 | |
| | 625 | _parent->setCurrGLBufferObjectPoolSize( _parent->getCurrGLBufferObjectPoolSize() - numDeleted*_profile._size ); |
| | 626 | |
| | 627 | // update the number of active and orphaned TextureOjects |
| | 628 | _parent->getNumberOrphanedGLBufferObjects() -= numDeleted; |
| | 629 | _parent->getNumberActiveGLBufferObjects() += numDeleted; |
| | 630 | _parent->getNumberDeleted() += numDeleted; |
| | 631 | |
| | 632 | availableTime -= timer.elapsedTime(); |
| | 633 | } |
| | 634 | |
| | 635 | bool GLBufferObjectSet::makeSpace(unsigned int& size) |
| | 636 | { |
| | 637 | if (!_orphanedGLBufferObjects.empty()) |
| | 638 | { |
| | 639 | unsigned int sizeAvailable = _orphanedGLBufferObjects.size() * _profile._size; |
| | 640 | if (size>sizeAvailable) size -= sizeAvailable; |
| | 641 | else size = 0; |
| | 642 | |
| | 643 | flushAllDeletedGLBufferObjects(); |
| | 644 | } |
| | 645 | |
| | 646 | return size==0; |
| | 647 | } |
| | 648 | |
| | 649 | GLBufferObject* GLBufferObjectSet::takeFromOrphans(BufferObject* bufferObject) |
| | 650 | { |
| | 651 | // take front of orphaned list. |
| | 652 | ref_ptr<GLBufferObject> glbo = _orphanedGLBufferObjects.front(); |
| | 653 | |
| | 654 | // remove from orphan list. |
| | 655 | _orphanedGLBufferObjects.pop_front(); |
| | 656 | |
| | 657 | // assign to new texture |
| | 658 | glbo->assign(bufferObject); |
| | 659 | glbo->setProfile(_profile); |
| | 660 | |
| | 661 | // update the number of active and orphaned TextureOjects |
| | 662 | _parent->getNumberOrphanedGLBufferObjects() -= 1; |
| | 663 | _parent->getNumberActiveGLBufferObjects() += 1; |
| | 664 | |
| | 665 | // place at back of active list |
| | 666 | addToBack(glbo.get()); |
| | 667 | |
| | 668 | // osg::notify(osg::NOTICE)<<"Reusing orhpahned GLBufferObject, _numOfGLBufferObjects="<<_numOfGLBufferObjects<<std::endl; |
| | 669 | |
| | 670 | return glbo.release(); |
| | 671 | } |
| | 672 | |
| | 673 | |
| | 674 | GLBufferObject* GLBufferObjectSet::takeOrGenerate(BufferObject* bufferObject) |
| | 675 | { |
| | 676 | // see if we can recyle GLBufferObject from the orphane list |
| | 677 | if (!_pendingOrphanedGLBufferObjects.empty()) |
| | 678 | { |
| | 679 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 680 | handlePendingOrphandedGLBufferObjects(); |
| | 681 | return takeFromOrphans(bufferObject); |
| | 682 | } |
| | 683 | else if (!_orphanedGLBufferObjects.empty()) |
| | 684 | { |
| | 685 | return takeFromOrphans(bufferObject); |
| | 686 | } |
| | 687 | |
| | 688 | unsigned int minFrameNumber = _parent->getFrameNumber(); |
| | 689 | |
| | 690 | // see if we can reuse GLBufferObject by taking the least recently used active GLBufferObject |
| | 691 | if ((_parent->getMaxGLBufferObjectPoolSize()!=0) && |
| | 692 | (!_parent->hasSpace(_profile._size)) && |
| | 693 | (_numOfGLBufferObjects>1) && |
| | 694 | (_head != 0) && |
| | 695 | (_head->_frameLastUsed<minFrameNumber)) |
| | 696 | { |
| | 697 | |
| | 698 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 699 | |
| | 700 | ref_ptr<GLBufferObject> glbo = _head; |
| | 701 | |
| | 702 | ref_ptr<BufferObject> original_BufferObject = glbo->getBufferObject(); |
| | 703 | |
| | 704 | if (original_BufferObject.valid()) |
| | 705 | { |
| | 706 | original_BufferObject->setGLBufferObject(_contextID,0); |
| | 707 | // osg::notify(osg::NOTICE)<<"GLBufferObjectSet="<<this<<": Reusing an active GLBufferObject "<<glbo.get()<<" _numOfGLBufferObjects="<<_numOfGLBufferObjects<<" size="<<_profile._size<<std::endl; |
| | 708 | } |
| | 709 | else |
| | 710 | { |
| | 711 | // osg::notify(osg::NOTICE)<<"Reusing a recently orphaned active GLBufferObject "<<glbo.get()<<std::endl; |
| | 712 | } |
| | 713 | |
| | 714 | moveToBack(glbo.get()); |
| | 715 | |
| | 716 | // assign to new texture |
| | 717 | glbo->setBufferObject(bufferObject); |
| | 718 | glbo->setProfile(_profile); |
| | 719 | |
| | 720 | return glbo.release(); |
| | 721 | } |
| | 722 | |
| | 723 | // |
| | 724 | GLBufferObject* glbo = new GLBufferObject(_contextID, const_cast<BufferObject*>(bufferObject)); |
| | 725 | glbo->setProfile(_profile); |
| | 726 | glbo->_set = this; |
| | 727 | ++_numOfGLBufferObjects; |
| | 728 | |
| | 729 | // update the current texture pool size |
| | 730 | _parent->getCurrGLBufferObjectPoolSize() += _profile._size; |
| | 731 | _parent->getNumberActiveGLBufferObjects() += 1; |
| | 732 | |
| | 733 | addToBack(glbo); |
| | 734 | |
| | 735 | // osg::notify(osg::NOTICE)<<"Created new GLBufferObject, _numOfGLBufferObjects "<<_numOfGLBufferObjects<<std::endl; |
| | 736 | |
| | 737 | return glbo; |
| | 738 | } |
| | 739 | |
| | 740 | void GLBufferObjectSet::moveToBack(GLBufferObject* to) |
| | 741 | { |
| | 742 | #if 0 |
| | 743 | osg::notify(osg::NOTICE)<<"GLBufferObjectSet::moveToBack("<<to<<")"<<std::endl; |
| | 744 | osg::notify(osg::NOTICE)<<" before _head = "<<_head<<std::endl; |
| | 745 | osg::notify(osg::NOTICE)<<" before _tail = "<<_tail<<std::endl; |
| | 746 | osg::notify(osg::NOTICE)<<" before to->_previous = "<<to->_previous<<std::endl; |
| | 747 | osg::notify(osg::NOTICE)<<" before to->_next = "<<to->_next<<std::endl; |
| | 748 | #endif |
| | 749 | |
| | 750 | to->_frameLastUsed = _parent->getFrameNumber(); |
| | 751 | |
| | 752 | // nothing to do if we are already tail |
| | 753 | if (to==_tail) return; |
| | 754 | |
| | 755 | // if no tail exists then assign 'to' as tail and head |
| | 756 | if (_tail==0) |
| | 757 | { |
| | 758 | osg::notify(osg::NOTICE)<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl; |
| | 759 | _head = to; |
| | 760 | _tail = to; |
| | 761 | return; |
| | 762 | } |
| | 763 | |
| | 764 | if (to->_next==0) |
| | 765 | { |
| | 766 | osg::notify(osg::NOTICE)<<"Error ***************** Should not get here either !!!!!!!!!"<<std::endl; |
| | 767 | return; |
| | 768 | } |
| | 769 | |
| | 770 | |
| | 771 | if (to->_previous) |
| | 772 | { |
| | 773 | (to->_previous)->_next = to->_next; |
| | 774 | } |
| | 775 | else |
| | 776 | { |
| | 777 | // 'to' is the head, so moving it to the back will mean we need a new head |
| | 778 | if (to->_next) |
| | 779 | { |
| | 780 | _head = to->_next; |
| | 781 | } |
| | 782 | } |
| | 783 | |
| | 784 | (to->_next)->_previous = to->_previous; |
| | 785 | |
| | 786 | _tail->_next = to; |
| | 787 | |
| | 788 | to->_previous = _tail; |
| | 789 | to->_next = 0; |
| | 790 | |
| | 791 | _tail = to; |
| | 792 | |
| | 793 | #if 0 |
| | 794 | osg::notify(osg::NOTICE)<<" m2B after _head = "<<_head<<std::endl; |
| | 795 | osg::notify(osg::NOTICE)<<" m2B after _tail = "<<_tail<<std::endl; |
| | 796 | osg::notify(osg::NOTICE)<<" m2B after to->_previous = "<<to->_previous<<std::endl; |
| | 797 | osg::notify(osg::NOTICE)<<" m2B after to->_next = "<<to->_next<<std::endl; |
| | 798 | #endif |
| | 799 | checkConsistency(); |
| | 800 | } |
| | 801 | |
| | 802 | void GLBufferObjectSet::addToBack(GLBufferObject* to) |
| | 803 | { |
| | 804 | #if 0 |
| | 805 | osg::notify(osg::NOTICE)<<"GLBufferObjectSet::addToBack("<<to<<")"<<std::endl; |
| | 806 | osg::notify(osg::NOTICE)<<" before _head = "<<_head<<std::endl; |
| | 807 | osg::notify(osg::NOTICE)<<" before _tail = "<<_tail<<std::endl; |
| | 808 | osg::notify(osg::NOTICE)<<" before to->_previous = "<<to->_previous<<std::endl; |
| | 809 | osg::notify(osg::NOTICE)<<" before to->_next = "<<to->_next<<std::endl; |
| | 810 | #endif |
| | 811 | |
| | 812 | if (to->_previous !=0 || to->_next !=0) |
| | 813 | { |
| | 814 | moveToBack(to); |
| | 815 | } |
| | 816 | else |
| | 817 | { |
| | 818 | to->_frameLastUsed = _parent->getFrameNumber(); |
| | 819 | |
| | 820 | if (_tail) _tail->_next = to; |
| | 821 | to->_previous = _tail; |
| | 822 | |
| | 823 | if (!_head) _head = to; |
| | 824 | _tail = to; |
| | 825 | } |
| | 826 | #if 0 |
| | 827 | osg::notify(osg::NOTICE)<<" a2B after _head = "<<_head<<std::endl; |
| | 828 | osg::notify(osg::NOTICE)<<" a2B after _tail = "<<_tail<<std::endl; |
| | 829 | osg::notify(osg::NOTICE)<<" a2B after to->_previous = "<<to->_previous<<std::endl; |
| | 830 | osg::notify(osg::NOTICE)<<" a2B after to->_next = "<<to->_next<<std::endl; |
| | 831 | #endif |
| | 832 | checkConsistency(); |
| | 833 | } |
| | 834 | |
| | 835 | void GLBufferObjectSet::orphan(GLBufferObject* to) |
| | 836 | { |
| | 837 | // osg::notify(osg::NOTICE)<<"GLBufferObjectSet::orphan("<<to<<")"<<std::endl; |
| | 838 | |
| | 839 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 840 | |
| | 841 | // disconnect from original texture |
| | 842 | to->setBufferObject(0); |
| | 843 | |
| | 844 | // add orphan 'to' to the pending list of orphans, these will then be |
| | 845 | // handled in the handlePendingOrphandedGLBufferObjects() where the TO's |
| | 846 | // will be removed from the active list, and then placed in the orhpanGLBufferObject |
| | 847 | // list. This double buffered approach to handling orphaned TO's is used |
| | 848 | // to avoid having to mutex the process of appling active TO's. |
| | 849 | _pendingOrphanedGLBufferObjects.push_back(to); |
| | 850 | |
| | 851 | #if 0 |
| | 852 | osg::notify(osg::NOTICE)<<"GLBufferObjectSet::orphan("<<to<<") _pendingOrphanedGLBufferObjects.size()="<<_pendingOrphanedGLBufferObjects.size()<<std::endl; |
| | 853 | osg::notify(osg::NOTICE)<<" _orphanedGLBufferObjects.size()="<<_orphanedGLBufferObjects.size()<<std::endl; |
| | 854 | #endif |
| | 855 | } |
| | 856 | |
| | 857 | void GLBufferObjectSet::remove(GLBufferObject* to) |
| | 858 | { |
| | 859 | if (to->_previous!=0) |
| | 860 | { |
| | 861 | (to->_previous)->_next = to->_next; |
| | 862 | } |
| | 863 | else |
| | 864 | { |
| | 865 | // 'to' was head so assign _head to the next in list |
| | 866 | _head = to->_next; |
| | 867 | } |
| | 868 | |
| | 869 | if (to->_next!=0) |
| | 870 | { |
| | 871 | (to->_next)->_previous = to->_previous; |
| | 872 | } |
| | 873 | else |
| | 874 | { |
| | 875 | // 'to' was tail so assing tail to the previous in list |
| | 876 | _tail = to->_previous; |
| | 877 | } |
| | 878 | |
| | 879 | // reset the 'to' list pointers as it's no longer in the active list. |
| | 880 | to->_next = 0; |
| | 881 | to->_previous = 0; |
| | 882 | } |
| | 883 | |
| | 884 | |
| | 885 | GLBufferObjectManager::GLBufferObjectManager(unsigned int contextID): |
| | 886 | _contextID(contextID), |
| | 887 | _numActiveGLBufferObjects(0), |
| | 888 | _numOrphanedGLBufferObjects(0), |
| | 889 | _currGLBufferObjectPoolSize(0), |
| | 890 | _maxGLBufferObjectPoolSize(0), |
| | 891 | _frameNumber(0), |
| | 892 | _numFrames(0), |
| | 893 | _numDeleted(0), |
| | 894 | _deleteTime(0.0), |
| | 895 | _numGenerated(0), |
| | 896 | _generateTime(0.0), |
| | 897 | _numApplied(0), |
| | 898 | _applyTime(0.0) |
| | 899 | { |
| | 900 | } |
| | 901 | |
| | 902 | void GLBufferObjectManager::setMaxGLBufferObjectPoolSize(unsigned int size) |
| | 903 | { |
| | 904 | if (_maxGLBufferObjectPoolSize == size) return; |
| | 905 | |
| | 906 | if (size<_currGLBufferObjectPoolSize) |
| | 907 | { |
| | 908 | osg::notify(osg::NOTICE)<<"Warning: new MaxGLBufferObjectPoolSize="<<size<<" is smaller than current GLBufferObjectPoolSize="<<_currGLBufferObjectPoolSize<<std::endl; |
| | 909 | } |
| | 910 | |
| | 911 | _maxGLBufferObjectPoolSize = size; |
| | 912 | } |
| | 913 | |
| | 914 | bool GLBufferObjectManager::makeSpace(unsigned int size) |
| | 915 | { |
| | 916 | for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin(); |
| | 917 | itr != _glBufferObjectSetMap.end() && size>0; |
| | 918 | ++itr) |
| | 919 | { |
| | 920 | if ((*itr).second->makeSpace(size)) return true; |
| | 921 | } |
| | 922 | |
| | 923 | return size==0; |
| | 924 | } |
| | 925 | |
| | 926 | |
| | 927 | GLBufferObject* GLBufferObjectManager::generateGLBufferObject(const BufferObject* bufferObject) |
| | 928 | { |
| | 929 | ElapsedTime elapsedTime(&(getGenerateTime())); |
| | 930 | ++getNumberGenerated(); |
| | 931 | |
| | 932 | BufferObjectProfile profile(bufferObject->getTarget(), bufferObject->getUsage(), bufferObject->computeRequiredBufferSize()); |
| | 933 | |
| | 934 | // osg::notify(osg::NOTICE)<<"GLBufferObjectManager::generateGLBufferObject size="<<bufferObject->computeRequiredBufferSize()<<std::endl; |
| | 935 | |
| | 936 | GLBufferObjectSet* glbos = getGLBufferObjectSet(profile); |
| | 937 | return glbos->takeOrGenerate(const_cast<BufferObject*>(bufferObject)); |
| | 938 | } |
| | 939 | |
| | 940 | GLBufferObjectSet* GLBufferObjectManager::getGLBufferObjectSet(const BufferObjectProfile& profile) |
| | 941 | { |
| | 942 | osg::ref_ptr<GLBufferObjectSet>& tos = _glBufferObjectSetMap[profile]; |
| | 943 | if (!tos) tos = new GLBufferObjectSet(this, profile); |
| | 944 | return tos.get(); |
| | 945 | } |
| | 946 | |
| | 947 | void GLBufferObjectManager::handlePendingOrphandedGLBufferObjects() |
| | 948 | { |
| | 949 | for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin(); |
| | 950 | itr != _glBufferObjectSetMap.end(); |
| | 951 | ++itr) |
| | 952 | { |
| | 953 | (*itr).second->handlePendingOrphandedGLBufferObjects(); |
| | 954 | } |
| | 955 | } |
| | 956 | |
| | 957 | void GLBufferObjectManager::flushAllDeletedGLBufferObjects() |
| | 958 | { |
| | 959 | ElapsedTime elapsedTime(&(getDeleteTime())); |
| | 960 | |
| | 961 | for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin(); |
| | 962 | itr != _glBufferObjectSetMap.end(); |
| | 963 | ++itr) |
| | 964 | { |
| | 965 | (*itr).second->flushAllDeletedGLBufferObjects(); |
| | 966 | } |
| | 967 | } |
| | 968 | |
| | 969 | void GLBufferObjectManager::discardAllDeletedGLBufferObjects() |
| | 970 | { |
| | 971 | for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin(); |
| | 972 | itr != _glBufferObjectSetMap.end(); |
| | 973 | ++itr) |
| | 974 | { |
| | 975 | (*itr).second->discardAllDeletedGLBufferObjects(); |
| | 976 | } |
| | 977 | } |
| | 978 | |
| | 979 | void GLBufferObjectManager::flushDeletedGLBufferObjects(double currentTime, double& availableTime) |
| | 980 | { |
| | 981 | ElapsedTime elapsedTime(&(getDeleteTime())); |
| | 982 | |
| | 983 | for(GLBufferObjectSetMap::iterator itr = _glBufferObjectSetMap.begin(); |
| | 984 | (itr != _glBufferObjectSetMap.end()) && (availableTime > 0.0); |
| | 985 | ++itr) |
| | 986 | { |
| | 987 | (*itr).second->flushDeletedGLBufferObjects(currentTime, availableTime); |
| | 988 | } |
| | 989 | } |
| | 990 | |
| | 991 | void GLBufferObjectManager::releaseGLBufferObject(GLBufferObject* to) |
| | 992 | { |
| | 993 | if (to->_set) to->_set->orphan(to); |
| | 994 | else osg::notify(osg::NOTICE)<<"GLBufferObjectManager::releaseGLBufferObject(GLBufferObject* to) Not implemented yet"<<std::endl; |
| | 995 | } |
| | 996 | |
| | 997 | |
| | 998 | void GLBufferObjectManager::newFrame(osg::FrameStamp* fs) |
| | 999 | { |
| | 1000 | if (fs) _frameNumber = fs->getFrameNumber(); |
| | 1001 | else ++_frameNumber; |
| | 1002 | |
| | 1003 | ++_numFrames; |
| | 1004 | } |
| | 1005 | |
| | 1006 | void GLBufferObjectManager::reportStats() |
| | 1007 | { |
| | 1008 | double numFrames(_numFrames==0 ? 1.0 : _numFrames); |
| | 1009 | osg::notify(osg::NOTICE)<<"GLBufferObjectMananger::reportStats()"<<std::endl; |
| | 1010 | osg::notify(osg::NOTICE)<<" total _numOfGLBufferObjects="<<_numActiveGLBufferObjects<<", _numOrphanedGLBufferObjects="<<_numOrphanedGLBufferObjects<<" _currGLBufferObjectPoolSize="<<_currGLBufferObjectPoolSize<<std::endl; |
| | 1011 | osg::notify(osg::NOTICE)<<" total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl; |
| | 1012 | osg::notify(osg::NOTICE)<<" total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl; |
| | 1013 | osg::notify(osg::NOTICE)<<" total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl; |
| | 1014 | } |
| | 1015 | |
| | 1016 | void GLBufferObjectManager::resetStats() |
| | 1017 | { |
| | 1018 | _numFrames = 0; |
| | 1019 | _numDeleted = 0; |
| | 1020 | _deleteTime = 0; |
| | 1021 | |
| | 1022 | _numGenerated = 0; |
| | 1023 | _generateTime = 0; |
| | 1024 | |
| | 1025 | _numApplied = 0; |
| | 1026 | _applyTime = 0; |
| | 1027 | } |
| | 1028 | |
| | 1029 | |
| | 1030 | |
| | 1031 | osg::ref_ptr<GLBufferObjectManager>& GLBufferObjectManager::getGLBufferObjectManager(unsigned int contextID) |
| | 1032 | { |
| | 1033 | typedef osg::buffered_object< ref_ptr<GLBufferObjectManager> > GLBufferObjectManagerBuffer; |
| | 1034 | static GLBufferObjectManagerBuffer s_GLBufferObjectManager; |
| | 1035 | if (!s_GLBufferObjectManager[contextID]) s_GLBufferObjectManager[contextID] = new GLBufferObjectManager(contextID); |
| | 1036 | return s_GLBufferObjectManager[contextID]; |
| | 1037 | } |
| | 1038 | |
| | 1039 | GLBufferObject* GLBufferObject::createGLBufferObject(unsigned int contextID, const BufferObject* bufferObject) |
| | 1040 | { |
| | 1041 | return GLBufferObjectManager::getGLBufferObjectManager(contextID)->generateGLBufferObject(bufferObject); |
| | 1042 | } |
| | 1043 | |
| | 1044 | void GLBufferObject::flushAllDeletedBufferObjects(unsigned int contextID) |
| | 1045 | { |
| | 1046 | GLBufferObjectManager::getGLBufferObjectManager(contextID)->flushAllDeletedGLBufferObjects(); |
| | 1047 | } |
| | 1048 | |
| | 1049 | void GLBufferObject::discardAllDeletedBufferObjects(unsigned int contextID) |
| | 1050 | { |
| | 1051 | GLBufferObjectManager::getGLBufferObjectManager(contextID)->discardAllDeletedGLBufferObjects(); |
| | 1052 | } |
| | 1053 | |
| | 1054 | void GLBufferObject::flushDeletedBufferObjects(unsigned int contextID,double currentTime, double& availbleTime) |
| | 1055 | { |
| | 1056 | GLBufferObjectManager::getGLBufferObjectManager(contextID)->flushDeletedGLBufferObjects(currentTime, availbleTime); |
| | 1057 | } |
| | 1058 | |
| | 1059 | void GLBufferObject::releaseGLBufferObject(unsigned int contextID, GLBufferObject* to) |
| | 1060 | { |
| | 1061 | GLBufferObjectManager::getGLBufferObjectManager(contextID)->releaseGLBufferObject(to); |
| | 1062 | } |
| | 1063 | |
| | 1064 | |
| | 1065 | |
| | 1066 | ////////////////////////////////////////////////////////////////////////////////////////////////////// |
| | 1067 | // |
| 598 | | #if 0 |
| 599 | | void VertexBufferObject::compileBuffer(State& state) const |
| 600 | | { |
| 601 | | unsigned int contextID = state.getContextID(); |
| 602 | | |
| 603 | | _compiledList[contextID] = 1; |
| 604 | | |
| 605 | | Extensions* extensions = getExtensions(contextID,true); |
| 606 | | |
| 607 | | // osg::notify(osg::NOTICE)<<"VertexBufferObject::compileBuffer frameNumber="<<state.getFrameStamp()->getFrameNumber()<<std::endl; |
| 608 | | |
| 609 | | unsigned int totalSizeRequired = 0; |
| 610 | | unsigned int numNewArrays = 0; |
| 611 | | for(BufferEntryArrayPairs::const_iterator itr = _bufferEntryArrayPairs.begin(); |
| 612 | | itr != _bufferEntryArrayPairs.end(); |
| 613 | | ++itr) |
| 614 | | { |
| 615 | | const BufferEntryArrayPair& bep = *itr; |
| 616 | | if (bep.second) |
| 617 | | { |
| 618 | | totalSizeRequired += bep.second->getTotalDataSize(); |
| 619 | | if (bep.first.dataSize == 0) ++numNewArrays; |
| 620 | | } |
| 621 | | } |
| 622 | | |
| 623 | | bool copyAll = false; |
| 624 | | GLuint& vbo = buffer(contextID); |
| 625 | | if (vbo==0) |
| 626 | | { |
| 627 | | // building for the first time. |
| 628 | | |
| 629 | | _totalSize = totalSizeRequired; |
| 630 | | |
| 631 | | // don't generate buffer if size is zero. |
| 632 | | if (_totalSize==0) return; |
| 633 | | |
| 634 | | extensions->glGenBuffers(1, &vbo); |
| 635 | | extensions->glBindBuffer(_target, vbo); |
| 636 | | extensions->glBufferData(_target, _totalSize, NULL, _usage); |
| 637 | | |
| 638 | | copyAll = true; |
| 639 | | } |
| 640 | | else |
| 641 | | { |
| 642 | | extensions->glBindBuffer(_target, vbo); |
| 643 | | |
| 644 | | if (_totalSize != totalSizeRequired) |
| 645 | | { |
| 646 | | // resize vbo. |
| 647 | | _totalSize = totalSizeRequired; |
| 648 | | extensions->glBufferData(_target, _totalSize, NULL, _usage); |
| 649 | | |
| 650 | | copyAll = true; |
| 651 | | } |
| 652 | | } |
| 653 | | |
| 654 | | typedef std::map<unsigned int,std::vector<unsigned int> > SizePosMap_t; |
| 655 | | SizePosMap_t freeList; |
| 656 | | if (copyAll == false && numNewArrays > 0) |
| 657 | | { |
| 658 | | std::map<unsigned int,unsigned int> usedList; |
| 659 | | for(BufferEntryArrayPairs::const_iterator itr = _bufferEntryArrayPairs.begin(); |
| 660 | | itr != _bufferEntryArrayPairs.end(); |
| 661 | | ++itr) |
| 662 | | { |
| 663 | | const BufferEntryArrayPair& bep = *itr; |
| 664 | | if (bep.second==NULL) continue; |
| 665 | | if (bep.first.dataSize == 0) continue; |
| 666 | | usedList[bep.first.offset] = bep.first.dataSize; |
| 667 | | } |
| 668 | | unsigned int numFreeBlocks = 0; |
| 669 | | unsigned int pos=0; |
| 670 | | |
| 671 | | for (std::map<unsigned int,unsigned int>::const_iterator it=usedList.begin(); it!=usedList.end(); ++it) |
| 672 | | { |
| 673 | | unsigned int start = it->first; |
| 674 | | unsigned int length = it->second; |
| 675 | | if (pos < start) |
| 676 | | { |
| 677 | | freeList[start-pos].push_back(pos); |
| 678 | | ++numFreeBlocks; |
| 679 | | } |
| 680 | | pos = start+length; |
| 681 | | } |
| 682 | | if (pos < totalSizeRequired) |
| 683 | | { |
| 684 | | freeList[totalSizeRequired-pos].push_back(pos); |
| 685 | | ++numFreeBlocks; |
| 686 | | } |
| 687 | | if (numNewArrays < numFreeBlocks) |
| 688 | | { |
| 689 | | copyAll = true; // too fragmented, fallback to copyAll |
| 690 | | freeList.clear(); |
| 691 | | } |
| 692 | | } |
| 693 | | |
| 694 | | |
| 695 | | // osg::Timer_t start_tick = osg::Timer::instance()->tick(); |
| 696 | | |
| 697 | | |
| 698 | | void* vboMemory = 0; |
| 699 | | |
| 700 | | #if 0 |
| 701 | | vboMemory = extensions->glMapBuffer(_target, GL_WRITE_ONLY_ARB); |
| 702 | | #endif |
| 703 | | |
| 704 | | unsigned int offset = 0; |
| 705 | | for(BufferEntryArrayPairs::const_iterator itr = _bufferEntryArrayPairs.begin(); |
| 706 | | itr != _bufferEntryArrayPairs.end(); |
| 707 | | ++itr) |
| 708 | | { |
| 709 | | const BufferEntryArrayPair& bep = *itr; |
| 710 | | const Array* de = bep.second; |
| 711 | | if (de) |
| 712 | | { |
| 713 | | const unsigned int arraySize = de->getTotalDataSize(); |
| 714 | | if (copyAll || |
| 715 | | bep.first.modifiedCount[contextID] != bep.second->getModifiedCount() || |
| 716 | | bep.first.dataSize != arraySize) |
| 717 | | { |
| 718 | | // copy data across |
| 719 | | unsigned int newOffset = bep.first.offset; |
| 720 | | if (copyAll) |
| 721 | | { |
| 722 | | newOffset = offset; |
| 723 | | offset += arraySize; |
| 724 | | } |
| 725 | | else if (bep.first.dataSize == 0) |
| 726 | | { |
| 727 | | SizePosMap_t::iterator findIt = freeList.lower_bound(arraySize); |
| 728 | | if (findIt==freeList.end()) |
| 729 | | { |
| 730 | | osg::notify(osg::FATAL)<<"No suitable Memory in VBO found!"<<std::endl; |
| 731 | | continue; |
| 732 | | } |
| 733 | | const unsigned int oldOffset = findIt->second.back(); |
| 734 | | newOffset = oldOffset; |
| 735 | | if (findIt->first > arraySize) // using larger block |
| 736 | | { |
| 737 | | freeList[findIt->first-arraySize].push_back(oldOffset+arraySize); |
| 738 | | } |
| 739 | | findIt->second.pop_back(); |
| 740 | | if (findIt->second.empty()) |
| 741 | | { |
| 742 | | freeList.erase(findIt); |
| 743 | | } |
| 744 | | } |
| 745 | | bep.first.dataSize = arraySize; |
| 746 | | bep.first.modifiedCount[contextID] = de->getModifiedCount(); |
| 747 | | bep.first.offset = newOffset; |
| 748 | | de->setVertexBufferObjectOffset((GLvoid*)newOffset); |
| 749 | | |
| 750 | | // osg::notify(osg::NOTICE)<<" copying vertex buffer data "<<bep.first.dataSize<<" bytes"<<std::endl; |
| 751 | | |
| 752 | | if (vboMemory) |
| 753 | | memcpy((char*)vboMemory + bep.first.offset, de->getDataPointer(), bep.first.dataSize); |
| 754 | | else |
| 755 | | extensions->glBufferSubData(_target, bep.first.offset, bep.first.dataSize, de->getDataPointer()); |
| 756 | | |
| 757 | | } |
| 758 | | } |
| 759 | | } |
| 760 | | |
| 761 | | |
| 762 | | // Unmap the texture image buffer |
| 763 | | if (vboMemory) extensions->glUnmapBuffer(_target); |
| 764 | | |
| 765 | | // osg::notify(osg::NOTICE)<<"pbo _totalSize="<<_totalSize<<std::endl; |
| 766 | | // osg::notify(osg::NOTICE)<<"pbo "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl; |
| 767 | | } |
| 768 | | #endif |