root/OpenSceneGraph/trunk/src/osg/Texture.cpp @ 10601

Revision 10601, 89.9 kB (checked in by robert, 5 years ago)

Introduced new GLBufferObject pool for managing the memory footprint taken up by VertexBufferObejct?, ElementBufferObject? and PixelBufferObject?.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
RevLine 
[10594]1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
[1529]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*/
[1073]13#include <osg/GLExtensions>
[1099]14#include <osg/Image>
[1073]15#include <osg/Texture>
[8]16#include <osg/State>
17#include <osg/Notify>
[45]18#include <osg/GLU>
[2037]19#include <osg/Timer>
[4674]20#include <osg/ApplicationUsage>
[7385]21#include <osg/FrameBufferObject>
[10092]22#include <osg/TextureRectangle>
[8]23
[3423]24#include <OpenThreads/ScopedLock>
25#include <OpenThreads/Mutex>
26
[1462]27#ifndef GL_TEXTURE_WRAP_R
[1461]28#define GL_TEXTURE_WRAP_R                 0x8072
29#endif
[1099]30
[10370]31#ifndef GL_TEXTURE_MAX_LEVEL
32#define GL_TEXTURE_MAX_LEVEL              0x813D
33#endif
34
35
[2791]36#ifndef GL_UNPACK_CLIENT_STORAGE_APPLE
37#define GL_UNPACK_CLIENT_STORAGE_APPLE    0x85B2
38#endif
[1541]39
[2791]40#ifndef GL_APPLE_vertex_array_range
41#define GL_VERTEX_ARRAY_RANGE_APPLE       0x851D
42#define GL_VERTEX_ARRAY_RANGE_LENGTH_APPLE 0x851E
43#define GL_VERTEX_ARRAY_STORAGE_HINT_APPLE 0x851F
44#define GL_VERTEX_ARRAY_RANGE_POINTER_APPLE 0x8521
45#define GL_STORAGE_CACHED_APPLE           0x85BE
46#define GL_STORAGE_SHARED_APPLE           0x85BF
47#endif
48
[10600]49// #define DO_TIMING
[3852]50
[10409]51namespace osg {
52
[4674]53ApplicationUsageProxy Texture_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_MAX_TEXTURE_SIZE","Set the maximum size of textures.");
54
[10588]55typedef buffered_value< ref_ptr<Texture::Extensions> > BufferedExtensions;
56static BufferedExtensions s_extensions;
57
58unsigned int s_minimumNumberOfTextureObjectsToRetainInCache = 0;
59
60void Texture::setMinimumNumberOfTextureObjectsToRetainInCache(unsigned int minimum)
[3423]61{
[10588]62    s_minimumNumberOfTextureObjectsToRetainInCache = minimum;
63}
64
65unsigned int Texture::getMinimumNumberOfTextureObjectsToRetainInCache()
66{
67    return s_minimumNumberOfTextureObjectsToRetainInCache;
68}
69
70
[10589]71#define USE_NEW_TEXTURE_POOL 1
[10588]72
73void Texture::TextureObject::bind()
74{
75    glBindTexture( _profile._target, _id);
76    if (_set) _set->moveToBack(this);
77}
78
[10597]79void Texture::TextureObject::setAllocated(GLint     numMipmapLevels,
80                                          GLenum    internalFormat,
81                                          GLsizei   width,
82                                          GLsizei   height,
83                                          GLsizei   depth,
84                                          GLint     border)
85{
86    _allocated=true;
87    if (!match(_profile._target,numMipmapLevels,internalFormat,width,height,depth,border))
88    {
89        _profile.set(numMipmapLevels,internalFormat,width,height,depth,border);
90
91        if (_set)
92        {
93            // remove self from original set
94            _set->remove(this);
95
96            // get the new set for the new profile
97            _set = _set->getParent()->getTextureObjectSet(_profile);
98
99            // register self with new set.
100            _set->addToBack(this);
101        }
102    }
103}
104
[10589]105void Texture::TextureProfile::computeSize()
106{
107    unsigned int numBitsPerTexel = 32;
[10595]108
109    switch(_internalFormat)
110    {
111        case(1): numBitsPerTexel = 8; break;
112        case(GL_ALPHA): numBitsPerTexel = 8; break;
113        case(GL_LUMINANCE): numBitsPerTexel = 8; break;
114        case(GL_INTENSITY): numBitsPerTexel = 8; break;
115
116        case(GL_LUMINANCE_ALPHA): numBitsPerTexel = 16; break;
117        case(2): numBitsPerTexel = 16; break;
118
119        case(GL_RGB): numBitsPerTexel = 24; break;
120        case(GL_BGR): numBitsPerTexel = 24; break;
121        case(3): numBitsPerTexel = 24; break;
122
123        case(GL_RGBA): numBitsPerTexel = 32; break;
124        case(4): numBitsPerTexel = 32; break;
125
126        case(GL_COMPRESSED_ALPHA_ARB):           numBitsPerTexel = 4; break;
127        case(GL_COMPRESSED_INTENSITY_ARB):       numBitsPerTexel = 4; break;
128        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB): numBitsPerTexel = 4; break;
129        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):   numBitsPerTexel = 4; break;
130        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):  numBitsPerTexel = 4; break;
131
132        case(GL_COMPRESSED_RGB_ARB):             numBitsPerTexel = 8; break;
133        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):  numBitsPerTexel = 8; break;
134        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):  numBitsPerTexel = 8; break;
135    }
136
137    _size = (unsigned int)(ceil(double(_width * _height * _depth * numBitsPerTexel)/8.0));
138
139    if (_numMipmapLevels>1)
140    {
141        unsigned int mipmapSize = _size / 4;
142        for(GLint i=0; i<_numMipmapLevels && mipmapSize!=0; ++i)
143        {
144            _size += mipmapSize;
145            mipmapSize /= 4;
146        }
147    }
148
149    // osg::notify(osg::NOTICE)<<"TO ("<<_width<<", "<<_height<<", "<<_depth<<") size="<<_size<<" numBitsPerTexel="<<numBitsPerTexel<<std::endl;
[10589]150}
[10588]151
152///////////////////////////////////////////////////////////////////////////////////////////////////////////
153//
154//  New texture object manager
155//
156Texture::TextureObjectSet::TextureObjectSet(TextureObjectManager* parent, const TextureProfile& profile):
157    _parent(parent),
158    _contextID(parent->getContextID()),
159    _profile(profile),
160    _numOfTextureObjects(0),
161    _head(0),
162    _tail(0)
163{
164}
165
166Texture::TextureObjectSet::~TextureObjectSet()
167{
168#if 0
169    osg::notify(osg::NOTICE)<<"TextureObjectSet::~TextureObjectSet(), _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
170    osg::notify(osg::NOTICE)<<"     _orphanedTextureObjects = "<<_orphanedTextureObjects.size()<<std::endl;
171    osg::notify(osg::NOTICE)<<"     _head = "<<_head<<std::endl;
172    osg::notify(osg::NOTICE)<<"     _tail = "<<_tail<<std::endl;
173#endif
174}
175
176bool Texture::TextureObjectSet::checkConsistency() const
177{
[10601]178//    return true;
[10588]179
180    // osg::notify(osg::NOTICE)<<"TextureObjectSet::checkConsistency()"<<std::endl;
181    // check consistency of linked list.
182    unsigned int numInList = 0;
183    Texture::TextureObject* to = _head;
184    while(to!=0)
185    {
186        ++numInList;
187
188        if (to->_next)
189        {
190            if ((to->_next)->_previous != to)
191            {
192                osg::notify(osg::NOTICE)<<"Error (to->_next)->_previous != to "<<std::endl;
193                throw "Error (to->_next)->_previous != to ";
194            }
195        }
196        else
197        {
198            if (_tail != to)
199            {
200                osg::notify(osg::NOTICE)<<"Error _trail != to"<<std::endl;
201                throw "Error _trail != to";
202            }
203        }
204
205        to = to->_next;
206    }
207
208    unsigned int totalNumber = numInList + _orphanedTextureObjects.size();
209    if (totalNumber != _numOfTextureObjects)
210    {
211        osg::notify(osg::NOTICE)<<"Error numInList + _orphanedTextureObjects.size() != _numOfTextureObjects"<<std::endl;
212        osg::notify(osg::NOTICE)<<"    numInList = "<<numInList<<std::endl;
213        osg::notify(osg::NOTICE)<<"    _orphanedTextureObjects.size() = "<<_orphanedTextureObjects.size()<<std::endl;
214        osg::notify(osg::NOTICE)<<"    _pendingOrphanedTextureObjects.size() = "<<_pendingOrphanedTextureObjects.size()<<std::endl;
215        osg::notify(osg::NOTICE)<<"    _numOfTextureObjects = "<<_numOfTextureObjects<<std::endl;
216        throw "Error numInList + _orphanedTextureObjects.size() != _numOfTextureObjects";
217    }
218
219    return true;
220}
221
222void Texture::TextureObjectSet::handlePendingOrphandedTextureObjects()
223{
224    // osg::notify(osg::NOTICE)<<"handlePendingOrphandedTextureObjects()"<<_pendingOrphanedTextureObjects.size()<<std::endl;
225
226    if (_pendingOrphanedTextureObjects.empty()) return;
227
[10594]228    unsigned int numOrphaned = _pendingOrphanedTextureObjects.size();
229
[10588]230    for(TextureObjectList::iterator itr = _pendingOrphanedTextureObjects.begin();
231        itr != _pendingOrphanedTextureObjects.end();
232        ++itr)
233    {
234        TextureObject* to = itr->get();
235
236        _orphanedTextureObjects.push_back(to);
237
[10597]238        remove(to);
[10588]239
240#if 0
241        osg::notify(osg::NOTICE)<<"  HPOTO  after  _head = "<<_head<<std::endl;
242        osg::notify(osg::NOTICE)<<"  HPOTO  after _tail = "<<_tail<<std::endl;
243        osg::notify(osg::NOTICE)<<"  HPOTO  after to->_previous = "<<to->_previous<<std::endl;
244        osg::notify(osg::NOTICE)<<"  HPOTO  after to->_next = "<<to->_next<<std::endl;
245#endif
246
247    }
248
[10594]249
250    // update the TextureObjectManager's running total of active + orphaned TextureObjects
251    _parent->getNumberOrphanedTextureObjects() += numOrphaned;
252    _parent->getNumberActiveTextureObjects() -= numOrphaned;
253
[10588]254    _pendingOrphanedTextureObjects.clear();
255
256    checkConsistency();
257}
258
259void Texture::TextureObjectSet::flushAllDeletedTextureObjects()
260{
261    for(TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
262        itr != _orphanedTextureObjects.end();
263        ++itr)
264    {
265
266        GLuint id = (*itr)->id();
267
[10601]268        osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<id<<std::endl;
[10588]269
270        glDeleteTextures( 1L, &id);
271    }
[10589]272
[10594]273    unsigned int numDeleted = _orphanedTextureObjects.size();
274    _numOfTextureObjects -= numDeleted;
275
[10589]276    // update the TextureObjectManager's running total of current pool size
[10594]277    _parent->getCurrTexturePoolSize() -= numDeleted*_profile._size;
278    _parent->getNumberOrphanedTextureObjects() -= numDeleted;
279    _parent->getNumberDeleted() += numDeleted;
[10589]280
[10594]281    _orphanedTextureObjects.clear();
[10588]282}
283
284void Texture::TextureObjectSet::discardAllDeletedTextureObjects()
285{
[10594]286    unsigned int numDiscarded = _orphanedTextureObjects.size();
[10588]287
[10594]288    _numOfTextureObjects -= numDiscarded;
289
[10589]290    // update the TextureObjectManager's running total of current pool size
[10594]291    _parent->setCurrTexturePoolSize( _parent->getCurrTexturePoolSize() - numDiscarded*_profile._size );
[10589]292
[10594]293    // update the number of active and orphaned TextureOjects
294    _parent->getNumberOrphanedTextureObjects() -= 1;
295    _parent->getNumberActiveTextureObjects() += 1;
296    _parent->getNumberDeleted() += 1;
297
298
[10588]299    // just clear the list as there is nothing else we can do with them when discarding them
300    _orphanedTextureObjects.clear();
301}
302
303void Texture::TextureObjectSet::flushDeletedTextureObjects(double currentTime, double& availableTime)
304{
305    // osg::notify(osg::NOTICE)<<"Texture::TextureObjectSet::flushDeletedTextureObjects(..) Not properly implemented yet"<<std::endl;
306
[10594]307    // if nothing to delete return
308    if (_orphanedTextureObjects.empty()) return;
309
310    // if no time available don't try to flush objects.
311    if (availableTime<=0.0) return;
312
313    // if we don't have too many orphaned texture objects then don't bother deleting them, as we can potentially reuse them later.
314    if (_parent->getNumberOrphanedTextureObjects()<=s_minimumNumberOfTextureObjectsToRetainInCache) return;
315
316    unsigned int numDeleted = 0;
317    unsigned int maxNumObjectsToDelete = _parent->getNumberOrphanedTextureObjects()-s_minimumNumberOfTextureObjectsToRetainInCache;
318    if (maxNumObjectsToDelete>4) maxNumObjectsToDelete = 4;
319
320    ElapsedTime timer;
321
322    TextureObjectList::iterator itr = _orphanedTextureObjects.begin();
323    for(;
324        itr != _orphanedTextureObjects.end() && timer.elapsedTime()<availableTime && numDeleted<maxNumObjectsToDelete;
325        ++itr)
326    {
327
328        GLuint id = (*itr)->id();
329
[10601]330        osg::notify(osg::NOTICE)<<"Deleting textureobject id="<<id<<std::endl;
[10594]331
332        glDeleteTextures( 1L, &id);
333
334        ++numDeleted;
335    }
336
[10595]337    // osg::notify(osg::NOTICE)<<"Size before = "<<_orphanedTextureObjects.size();
[10594]338    _orphanedTextureObjects.erase(_orphanedTextureObjects.begin(), itr);
[10595]339    // osg::notify(osg::NOTICE)<<", after = "<<_orphanedTextureObjects.size()<<" numDeleted = "<<numDeleted<<std::endl;
[10594]340
341    // update the number of TO's in this TextureObjectSet
342    _numOfTextureObjects -= numDeleted;
343
344    _parent->setCurrTexturePoolSize( _parent->getCurrTexturePoolSize() - numDeleted*_profile._size );
345
346    // update the number of active and orphaned TextureOjects
347    _parent->getNumberOrphanedTextureObjects() -= numDeleted;
348    _parent->getNumberActiveTextureObjects() += numDeleted;
349    _parent->getNumberDeleted() += numDeleted;
350
351    availableTime -= timer.elapsedTime();
[10588]352}
353
[10589]354bool Texture::TextureObjectSet::makeSpace(unsigned int& size)
355{
356    if (!_orphanedTextureObjects.empty())
357    {
358        unsigned int sizeAvailable = _orphanedTextureObjects.size() * _profile._size;
359        if (size>sizeAvailable) size -= sizeAvailable;
360        else size = 0;
361
362        flushAllDeletedTextureObjects();
363    }
364
365    return size==0;
366}
367
[10594]368Texture::TextureObject* Texture::TextureObjectSet::takeFromOrphans(Texture* texture)
[10588]369{
[10594]370    // take front of orphaned list.
371    ref_ptr<TextureObject> to = _orphanedTextureObjects.front();
[10588]372
[10594]373    // remove from orphan list.
374    _orphanedTextureObjects.pop_front();
[10588]375
[10594]376    // assign to new texture
377    to->setTexture(texture);
[10588]378
[10594]379    // update the number of active and orphaned TextureOjects
380    _parent->getNumberOrphanedTextureObjects() -= 1;
381    _parent->getNumberActiveTextureObjects() += 1;
[10588]382
[10594]383    // place at back of active list
384    addToBack(to.get());
[10588]385
[10594]386    // osg::notify(osg::NOTICE)<<"Reusing orhpahned TextureObject, _numOfTextureObjects="<<_numOfTextureObjects<<std::endl;
[10588]387
[10594]388    return to.release();
389}
[10588]390
[10594]391
392Texture::TextureObject* Texture::TextureObjectSet::takeOrGenerate(Texture* texture)
393{
394    // see if we can recyle TextureObject from the orphane list
395    if (!_pendingOrphanedTextureObjects.empty())
396    {
397        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
398        handlePendingOrphandedTextureObjects();
399        return takeFromOrphans(texture);
[10588]400    }
[10594]401    else if (!_orphanedTextureObjects.empty())
402    {
403        return takeFromOrphans(texture);
404    }
[10588]405
[10594]406    unsigned int minFrameNumber = _parent->getFrameNumber();
407
[10588]408    // see if we can reuse TextureObject by taking the least recently used active TextureObject
[10589]409    if ((_parent->getMaxTexturePoolSize()!=0) &&
410        (!_parent->hasSpace(_profile._size)) &&
[10588]411        (_numOfTextureObjects>1) &&
[10594]412        (_head != 0) &&
413        (_head->_frameLastUsed<minFrameNumber))
[10588]414    {
[10594]415
416        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
417
[10588]418        ref_ptr<TextureObject> to = _head;
419
420        ref_ptr<Texture> original_texture = to->getTexture();
421
422        if (original_texture.valid())
423        {
424            original_texture->setTextureObject(_contextID,0);
[10594]425            // osg::notify(osg::NOTICE)<<"TextureObjectSet="<<this<<": Reusing an active TextureObject "<<to.get()<<" _numOfTextureObjects="<<_numOfTextureObjects<<" width="<<_profile._width<<" height="<<_profile._height<<std::endl;
[10588]426        }
427        else
428        {
[10594]429            // osg::notify(osg::NOTICE)<<"Reusing a recently orphaned active TextureObject "<<to.get()<<std::endl;
[10588]430        }
431
432        moveToBack(to.get());
433
434        // assign to new texture
435        to->setTexture(texture);
436
437        return to.release();
438    }
439
440    //
441    // no TextureObjects available to recyle so have to create one from scratch
442    //
443    GLuint id;
444    glGenTextures( 1L, &id );
445
446    TextureObject* to = new Texture::TextureObject(const_cast<Texture*>(texture),id,_profile);
447    to->_set = this;
448    ++_numOfTextureObjects;
449
[10589]450    // update the current texture pool size
[10594]451    _parent->getCurrTexturePoolSize() += _profile._size;
452    _parent->getNumberActiveTextureObjects() += 1;
[10589]453
[10588]454    addToBack(to);
455
[10594]456    // osg::notify(osg::NOTICE)<<"Created new TextureObject, _numOfTextureObjects "<<_numOfTextureObjects<<std::endl;
[10588]457
458    return to;
459}
460
461void Texture::TextureObjectSet::moveToBack(Texture::TextureObject* to)
462{
463#if 0
464    osg::notify(osg::NOTICE)<<"TextureObjectSet::moveToBack("<<to<<")"<<std::endl;
465    osg::notify(osg::NOTICE)<<"    before _head = "<<_head<<std::endl;
466    osg::notify(osg::NOTICE)<<"    before _tail = "<<_tail<<std::endl;
467    osg::notify(osg::NOTICE)<<"    before to->_previous = "<<to->_previous<<std::endl;
468    osg::notify(osg::NOTICE)<<"    before to->_next = "<<to->_next<<std::endl;
469#endif
470
[10594]471    to->_frameLastUsed = _parent->getFrameNumber();
472
[10588]473    // nothing to do if we are already tail
474    if (to==_tail) return;
475
476    // if no tail exists then assign 'to' as tail and head
477    if (_tail==0)
478    {
479        osg::notify(osg::NOTICE)<<"Error ***************** Should not get here !!!!!!!!!"<<std::endl;
480        _head = to;
481        _tail = to;
482        return;
483    }
484
485    if (to->_next==0)
486    {
487        osg::notify(osg::NOTICE)<<"Error ***************** Should not get here either !!!!!!!!!"<<std::endl;
488        return;
489    }
490
491
492    if (to->_previous)
493    {
494        (to->_previous)->_next = to->_next;
495    }
496    else
497    {
498        // 'to' is the head, so moving it to the back will mean we need a new head
499        if (to->_next)
500        {
501            _head = to->_next;
502        }
503    }
504
505    (to->_next)->_previous = to->_previous;
506
507    _tail->_next = to;
508
509    to->_previous = _tail;
510    to->_next = 0;
511
512    _tail = to;
513
514#if 0
515    osg::notify(osg::NOTICE)<<"  m2B   after  _head = "<<_head<<std::endl;
516    osg::notify(osg::NOTICE)<<"  m2B   after _tail = "<<_tail<<std::endl;
517    osg::notify(osg::NOTICE)<<"  m2B   after to->_previous = "<<to->_previous<<std::endl;
518    osg::notify(osg::NOTICE)<<"  m2B   after to->_next = "<<to->_next<<std::endl;
519#endif
520    checkConsistency();
521}
522
523void Texture::TextureObjectSet::addToBack(Texture::TextureObject* to)
524{
525#if 0
526    osg::notify(osg::NOTICE)<<"TextureObjectSet::addToBack("<<to<<")"<<std::endl;
527    osg::notify(osg::NOTICE)<<"    before _head = "<<_head<<std::endl;
528    osg::notify(osg::NOTICE)<<"    before _tail = "<<_tail<<std::endl;
529    osg::notify(osg::NOTICE)<<"    before to->_previous = "<<to->_previous<<std::endl;
530    osg::notify(osg::NOTICE)<<"    before to->_next = "<<to->_next<<std::endl;
531#endif
532
533    if (to->_previous !=0 || to->_next !=0)
534    {
535        moveToBack(to);
536    }
537    else
538    {
[10594]539        to->_frameLastUsed = _parent->getFrameNumber();
540
[10588]541        if (_tail) _tail->_next = to;
542        to->_previous = _tail;
543
544        if (!_head) _head = to;
545        _tail = to;
546    }
547#if 0
548    osg::notify(osg::NOTICE)<<"  a2B  after  _head = "<<_head<<std::endl;
549    osg::notify(osg::NOTICE)<<"  a2B   after _tail = "<<_tail<<std::endl;
550    osg::notify(osg::NOTICE)<<"  a2B   after to->_previous = "<<to->_previous<<std::endl;
551    osg::notify(osg::NOTICE)<<"  a2B   after to->_next = "<<to->_next<<std::endl;
552#endif
553    checkConsistency();
554}
555
556void Texture::TextureObjectSet::orphan(Texture::TextureObject* to)
557{
558    // osg::notify(osg::NOTICE)<<"TextureObjectSet::orphan("<<to<<")"<<std::endl;
559
560    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
561
562    // disconnect from original texture
563    to->setTexture(0);
564
565    // add orphan 'to' to the pending list of orphans, these will then be
566    // handled in the handlePendingOrphandedTextureObjects() where the TO's
567    // will be removed from the active list, and then placed in the orhpanTextureObject
568    // list.  This double buffered approach to handling orphaned TO's is used
569    // to avoid having to mutex the process of appling active TO's.
570    _pendingOrphanedTextureObjects.push_back(to);
571
572#if 0
573    osg::notify(osg::NOTICE)<<"TextureObjectSet::orphan("<<to<<")  _pendingOrphanedTextureObjects.size()="<<_pendingOrphanedTextureObjects.size()<<std::endl;
574    osg::notify(osg::NOTICE)<<"                                    _orphanedTextureObjects.size()="<<_orphanedTextureObjects.size()<<std::endl;
575#endif
576}
577
[10597]578void Texture::TextureObjectSet::remove(Texture::TextureObject* to)
579{
580    if (to->_previous!=0)
581    {
582        (to->_previous)->_next = to->_next;
583    }
584    else
585    {
586        // 'to' was head so assign _head to the next in list
587        _head = to->_next;
588    }
589
590    if (to->_next!=0)
591    {
592        (to->_next)->_previous = to->_previous;
593    }
594    else
595    {
596        // 'to' was tail so assing tail to the previous in list
597        _tail = to->_previous;
598    }
599
600    // reset the 'to' list pointers as it's no longer in the active list.
601    to->_next = 0;
602    to->_previous = 0;
603}
604
605
[10589]606Texture::TextureObjectManager::TextureObjectManager(unsigned int contextID):
607    _contextID(contextID),
[10594]608    _numActiveTextureObjects(0),
609    _numOrphanedTextureObjects(0),
[10589]610    _currTexturePoolSize(0),
[10594]611    _maxTexturePoolSize(0),
612    _frameNumber(0),
613    _numFrames(0),
614    _numDeleted(0),
615    _deleteTime(0.0),
616    _numGenerated(0),
617    _generateTime(0.0),
618    _numApplied(0),
619    _applyTime(0.0)
[10588]620{
621}
622
[10589]623void Texture::TextureObjectManager::setMaxTexturePoolSize(unsigned int size)
624{
625    if (_maxTexturePoolSize == size) return;
[10588]626
[10598]627    if (size<_currTexturePoolSize)
[10589]628    {
[10598]629        osg::notify(osg::NOTICE)<<"Warning: new MaxTexturePoolSize="<<size<<" is smaller than current TexturePoolSize="<<_currTexturePoolSize<<std::endl;
[10589]630    }
631
632    _maxTexturePoolSize = size;
[10588]633}
634
[10589]635bool Texture::TextureObjectManager::makeSpace(unsigned int size)
[10588]636{
[10589]637    for(TextureSetMap::iterator itr = _textureSetMap.begin();
638        itr != _textureSetMap.end() && size>0;
639        ++itr)
640    {
641        if ((*itr).second->makeSpace(size)) return true;
642    }
643
644    return size==0;
[10588]645}
646
647
648Texture::TextureObject* Texture::TextureObjectManager::generateTextureObject(const Texture* texture, GLenum target)
649{
650    return generateTextureObject(texture, target, 0, 0, 0, 0, 0, 0);
651}
652
653Texture::TextureObject* Texture::TextureObjectManager::generateTextureObject(const Texture* texture,
654                                             GLenum    target,
655                                             GLint     numMipmapLevels,
656                                             GLenum    internalFormat,
657                                             GLsizei   width,
658                                             GLsizei   height,
659                                             GLsizei   depth,
660                                             GLint     border)
661{
[10594]662    ElapsedTime elapsedTime(&(getGenerateTime()));
663    ++getNumberGenerated();
664
[10588]665    Texture::TextureProfile profile(target,numMipmapLevels,internalFormat,width,height,depth,border);
[10597]666    TextureObjectSet* tos = getTextureObjectSet(profile);
667    return tos->takeOrGenerate(const_cast<Texture*>(texture));
668}
669
670Texture::TextureObjectSet* Texture::TextureObjectManager::getTextureObjectSet(const TextureProfile& profile)
671{
[10588]672    osg::ref_ptr<Texture::TextureObjectSet>& tos = _textureSetMap[profile];
673    if (!tos) tos = new Texture::TextureObjectSet(this, profile);
[10597]674    return tos.get();
[10588]675}
676
677void Texture::TextureObjectManager::handlePendingOrphandedTextureObjects()
678{
679    for(TextureSetMap::iterator itr = _textureSetMap.begin();
680        itr != _textureSetMap.end();
681        ++itr)
682    {
683        (*itr).second->handlePendingOrphandedTextureObjects();
684    }
685}
686
687void Texture::TextureObjectManager::flushAllDeletedTextureObjects()
688{
[10594]689    ElapsedTime elapsedTime(&(getDeleteTime()));
[10589]690
[10588]691    for(TextureSetMap::iterator itr = _textureSetMap.begin();
692        itr != _textureSetMap.end();
693        ++itr)
694    {
695        (*itr).second->flushAllDeletedTextureObjects();
696    }
697}
698
699void Texture::TextureObjectManager::discardAllDeletedTextureObjects()
700{
701    for(TextureSetMap::iterator itr = _textureSetMap.begin();
702        itr != _textureSetMap.end();
703        ++itr)
704    {
705        (*itr).second->discardAllDeletedTextureObjects();
706    }
707}
708
709void Texture::TextureObjectManager::flushDeletedTextureObjects(double currentTime, double& availableTime)
710{
[10594]711    ElapsedTime elapsedTime(&(getDeleteTime()));
712
[10588]713    for(TextureSetMap::iterator itr = _textureSetMap.begin();
714        (itr != _textureSetMap.end()) && (availableTime > 0.0);
715        ++itr)
716    {
717        (*itr).second->flushDeletedTextureObjects(currentTime, availableTime);
718    }
719}
720
721void Texture::TextureObjectManager::releaseTextureObject(Texture::TextureObject* to)
722{
723    if (to->_set) to->_set->orphan(to);
724    else osg::notify(osg::NOTICE)<<"TextureObjectManager::releaseTextureObject(Texture::TextureObject* to) Not implemented yet"<<std::endl;
725}
726
727
[10594]728void Texture::TextureObjectManager::newFrame(osg::FrameStamp* fs)
729{
730    if (fs) _frameNumber = fs->getFrameNumber();
731    else ++_frameNumber;
732
733    ++_numFrames;
734}
735
736void Texture::TextureObjectManager::reportStats()
737{
738    double numFrames(_numFrames==0 ? 1.0 : _numFrames);
739    osg::notify(osg::NOTICE)<<"TextureObjectMananger::reportStats()"<<std::endl;
740    osg::notify(osg::NOTICE)<<"   total _numOfTextureObjects="<<_numActiveTextureObjects<<", _numOrphanedTextureObjects="<<_numOrphanedTextureObjects<<" _currTexturePoolSize="<<_currTexturePoolSize<<std::endl;
741    osg::notify(osg::NOTICE)<<"   total _numGenerated="<<_numGenerated<<", _generateTime="<<_generateTime<<", averagePerFrame="<<_generateTime/numFrames*1000.0<<"ms"<<std::endl;
742    osg::notify(osg::NOTICE)<<"   total _numDeleted="<<_numDeleted<<", _deleteTime="<<_deleteTime<<", averagePerFrame="<<_deleteTime/numFrames*1000.0<<"ms"<<std::endl;
743    osg::notify(osg::NOTICE)<<"   total _numApplied="<<_numApplied<<", _applyTime="<<_applyTime<<", averagePerFrame="<<_applyTime/numFrames*1000.0<<"ms"<<std::endl;
744}
745
746void Texture::TextureObjectManager::resetStats()
747{
748    _numFrames = 0;
749    _numDeleted = 0;
750    _deleteTime = 0;
751
752    _numGenerated = 0;
753    _generateTime = 0;
754
755    _numApplied = 0;
756    _applyTime = 0;
757}
758
759
760
[10588]761osg::ref_ptr<Texture::TextureObjectManager>& Texture::getTextureObjectManager(unsigned int contextID)
762{
763    typedef osg::buffered_object< ref_ptr<Texture::TextureObjectManager> > TextureObjectManagerBuffer;
764    static TextureObjectManagerBuffer s_TextureObjectManager;
765    if (!s_TextureObjectManager[contextID]) s_TextureObjectManager[contextID] = new Texture::TextureObjectManager(contextID);
766    return s_TextureObjectManager[contextID];
767}
768
769
770#if USE_NEW_TEXTURE_POOL
771
772Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID, GLenum target)
773{
774    return getTextureObjectManager(contextID)->generateTextureObject(texture, target);
775}
776
777Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,
778                                             GLenum    target,
779                                             GLint     numMipmapLevels,
780                                             GLenum    internalFormat,
781                                             GLsizei   width,
782                                             GLsizei   height,
783                                             GLsizei   depth,
784                                             GLint     border)
785{
786    return getTextureObjectManager(contextID)->generateTextureObject(texture,target,numMipmapLevels,internalFormat,width,height,depth,border);
787}
788
789void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
790{
791    getTextureObjectManager(contextID)->flushAllDeletedTextureObjects();
792}
793
794void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
795{
796    getTextureObjectManager(contextID)->discardAllDeletedTextureObjects();
797}
798
799void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
800{
801    getTextureObjectManager(contextID)->flushDeletedTextureObjects(currentTime, availbleTime);
802}
803
804void Texture::releaseTextureObject(unsigned int contextID, Texture::TextureObject* to)
805{
806    getTextureObjectManager(contextID)->releaseTextureObject(to);
807}
808
809#else
810
811///////////////////////////////////////////////////////////////////////////////////////////////////////////
812//
813//  Original texture object manager
814//
815class OriginalTextureObjectManager : public osg::Referenced
816{
[3423]817public:
818
[10588]819    OriginalTextureObjectManager():
[5378]820        _expiryDelay(0.0)
821    {
[10588]822        // printf("Constructing OriginalTextureObjectManager\n");
[5378]823    }
[3423]824
[10588]825    ~OriginalTextureObjectManager()
[5378]826    {
[10588]827        // printf("Destructing OriginalTextureObjectManager\n");
[5378]828    }
829
[10588]830    virtual Texture::TextureObject* generateTextureObject(Texture* texture, unsigned int contextID,GLenum target);
[3423]831
[10588]832    virtual Texture::TextureObject* generateTextureObject(Texture* texture, unsigned int contextID,
[3423]833                                                 GLenum    target,
834                                                 GLint     numMipmapLevels,
835                                                 GLenum    internalFormat,
836                                                 GLsizei   width,
837                                                 GLsizei   height,
838                                                 GLsizei   depth,
839                                                 GLint     border);
840
[10588]841    virtual Texture::TextureObject* reuseTextureObject(Texture* texture, unsigned int contextID,
[3423]842                                              GLenum    target,
843                                              GLint     numMipmapLevels,
844                                              GLenum    internalFormat,
845                                              GLsizei   width,
846                                              GLsizei   height,
847                                              GLsizei   depth,
848                                              GLint     border);
849
[10588]850    inline Texture::TextureObject* reuseOrGenerateTextureObject(Texture* texture, unsigned int contextID,
[3423]851                                              GLenum    target,
852                                              GLint     numMipmapLevels,
853                                              GLenum    internalFormat,
854                                              GLsizei   width,
855                                              GLsizei   height,
856                                              GLsizei   depth,
857                                              GLint     border)
858    {
[10588]859        Texture::TextureObject* to = reuseTextureObject(texture, contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
[3423]860        if (to) return to;
[10588]861        else return generateTextureObject(texture, contextID,target,numMipmapLevels,internalFormat,width,height,depth,border);
[3423]862    }                                                     
863
864    void flushAllTextureObjects(unsigned int contextID);
865
[7773]866    void discardAllTextureObjects(unsigned int contextID);
867
[3423]868    void flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime);
869
870    void setExpiryDelay(double expiryDelay) { _expiryDelay = expiryDelay; }
871
872    double getExpiryDelay() const { return _expiryDelay; }
873
874    /** How long to keep unused texture objects before deletion. */
875    double                  _expiryDelay;
876
[10588]877    typedef osg::buffered_object<Texture::TextureObjectList> TextureObjectListMap;
878    TextureObjectListMap    _textureObjectListMap;
[3423]879
880    // mutex to keep access serialized.
881    OpenThreads::Mutex      _mutex;
882};
883
[6004]884unsigned int Texture::s_numberTextureReusedLastInLastFrame = 0;
885unsigned int Texture::s_numberNewTextureInLastFrame = 0;
886unsigned int Texture::s_numberDeletedTextureInLastFrame = 0;
887
888
[10588]889static ref_ptr<OriginalTextureObjectManager> s_textureObjectManager = new OriginalTextureObjectManager;
[6004]890
891
[10594]892Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID,GLenum target)
[6004]893{
[10594]894    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
895    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
896    tom->getNumberGenerated()++;
897
[2022]898    GLuint id;
899    glGenTextures( 1L, &id );
[1541]900
[10588]901    return new Texture::TextureObject(texture, id,target);
[2022]902}
903
[3422]904static int s_number = 0;
905
[10594]906Texture::TextureObject* OriginalTextureObjectManager::generateTextureObject(Texture* texture, unsigned int contextID,
[2022]907                                                                             GLenum    target,
908                                                                             GLint     numMipmapLevels,
909                                                                             GLenum    internalFormat,
910                                                                             GLsizei   width,
911                                                                             GLsizei   height,
912                                                                             GLsizei   depth,
913                                                                             GLint     border)
[1541]914{
[10594]915    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
916    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
917    tom->getNumberGenerated()++;
918
[3422]919    ++s_number;
[3423]920    ++Texture::s_numberNewTextureInLastFrame;
[3422]921    // notify(NOTICE)<<"creating new texture object "<<s_number<<std::endl;
922
[2022]923    // no useable texture object found so return 0
924    GLuint id;
925    glGenTextures( 1L, &id );
926
[10588]927    return new Texture::TextureObject(texture, id,target,numMipmapLevels,internalFormat,width,height,depth,border);
[2022]928}
929
[10588]930Texture::TextureObject* OriginalTextureObjectManager::reuseTextureObject(Texture* texture, unsigned int contextID,
[2022]931                                                                             GLenum    target,
932                                                                             GLint     numMipmapLevels,
933                                                                             GLenum    internalFormat,
934                                                                             GLsizei   width,
935                                                                             GLsizei   height,
936                                                                             GLsizei   depth,
937                                                                             GLint     border)
938{
[10594]939    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
940    ElapsedTime elapsedTime(&(tom->getGenerateTime()));
941    tom->getNumberGenerated()++;
942
[3171]943    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
944
[3423]945    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
946    for(Texture::TextureObjectList::iterator itr = tol.begin();
[2022]947        itr != tol.end();
948        ++itr)
[1541]949    {
[2022]950        if ((*itr)->match(target,numMipmapLevels,internalFormat,width,height,depth,border))
951        {
952            // found usable texture object.
953            Texture::TextureObject* textureObject = (*itr).release();
954            tol.erase(itr);
955           
[3422]956            // notify(NOTICE)<<"reusing texture object "<<std::endl;
[2022]957           
[3423]958            ++Texture::s_numberTextureReusedLastInLastFrame;
[3422]959
[10588]960            textureObject->setTexture(texture);
961
[2022]962            return textureObject;
963        }
[1541]964    }
[2022]965   
966    return 0;
[1541]967}
968
[10588]969void OriginalTextureObjectManager::flushAllTextureObjects(unsigned int contextID)
[1541]970{
[10594]971    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
972    ElapsedTime elapsedTime(&(tom->getDeleteTime()));
973
[3171]974    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
975
[5358]976    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
[3423]977
[5934]978    // osg::notify(osg::INFO)<<"Flushing texture objects num="<<tol.size()<<" contextID="<<contextID<<std::endl;
979
[5358]980    for(Texture::TextureObjectList::iterator itr=tol.begin();
981        itr!=tol.end();
982        ++itr)
983    {
[5934]984        // osg::notify(osg::NOTICE)<<"  deleting texture object "<<(*itr)->_id<<std::endl;
[10588]985        GLuint id = (*itr)->id();
986        glDeleteTextures( 1L, &id);
[10594]987
988        tom->getNumberDeleted()++;
[3423]989    }
[5358]990    tol.clear();
[3423]991}
992
[10588]993void OriginalTextureObjectManager::discardAllTextureObjects(unsigned int contextID)
[7773]994{
995    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
996
997    Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
998    tol.clear();
999}
1000
[10588]1001void OriginalTextureObjectManager::flushTextureObjects(unsigned int contextID,double currentTime, double& availableTime)
[3423]1002{
[10594]1003
[2037]1004    // if no time available don't try to flush objects.
1005    if (availableTime<=0.0) return;
[2022]1006
[10594]1007    Texture::TextureObjectManager* tom = Texture::getTextureObjectManager(contextID);
1008    ElapsedTime timer(&(tom->getDeleteTime()));
1009
[3422]1010    unsigned int numObjectsDeleted = 0;
1011    unsigned int maxNumObjectsToDelete = 4;
[3171]1012
[10594]1013    {
[3171]1014        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
1015
[5358]1016        Texture::TextureObjectList& tol = _textureObjectListMap[contextID];
1017
1018        // reset the time of any uninitialized objects.
1019        Texture::TextureObjectList::iterator itr;
1020        for(itr=tol.begin();
1021            itr!=tol.end();
1022            ++itr)
[1541]1023        {
[10588]1024            if ((*itr)->getTimeStamp()==0.0) (*itr)->setTimeStamp(currentTime);
[5358]1025        }
[2037]1026
[5358]1027        double expiryTime = currentTime-_expiryDelay;
1028
1029        for(itr=tol.begin();
[10594]1030            itr!=tol.end() && timer.elapsedTime()<availableTime && tol.size()>s_minimumNumberOfTextureObjectsToRetainInCache && numObjectsDeleted<maxNumObjectsToDelete;
[5358]1031            )
1032        {
[10588]1033            if ((*itr)->getTimeStamp()<=expiryTime)
[2037]1034            {
[5358]1035                --s_number;
1036                ++Texture::s_numberDeletedTextureInLastFrame;
[3171]1037
[10588]1038                GLuint id = (*itr)->id();
1039                glDeleteTextures( 1L, &id);
[5358]1040                itr = tol.erase(itr);
1041                ++numObjectsDeleted;
1042            }
1043            else
[2037]1044            {
[5358]1045                ++itr;
[2037]1046            }
[2022]1047        }
[1541]1048    }
[10594]1049
1050    tom->getNumberDeleted()+=numObjectsDeleted;
[3171]1051       
[10594]1052    availableTime -= timer.elapsedTime();
[1541]1053}
1054
1055
[10588]1056static OriginalTextureObjectManager* getOriginalTextureObjectManager()
[2022]1057{
[3423]1058    return s_textureObjectManager.get();
[2022]1059}
1060
[3423]1061
[10588]1062Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,GLenum target)
[2022]1063{
[10588]1064    if (getOriginalTextureObjectManager()) return getOriginalTextureObjectManager()->generateTextureObject(const_cast<osg::Texture*>(texture),contextID,target);
[5378]1065    else return 0;
[2022]1066}
1067
[10588]1068Texture::TextureObject* Texture::generateTextureObject(const Texture* texture, unsigned int contextID,
[3423]1069                                             GLenum    target,
1070                                             GLint     numMipmapLevels,
1071                                             GLenum    internalFormat,
1072                                             GLsizei   width,
1073                                             GLsizei   height,
1074                                             GLsizei   depth,
1075                                             GLint     border)
[2036]1076{
[10588]1077    if (getOriginalTextureObjectManager())
1078        return getOriginalTextureObjectManager()->reuseOrGenerateTextureObject(const_cast<osg::Texture*>(texture),
1079                                             contextID,
[3423]1080                                             target,
1081                                             numMipmapLevels,
1082                                             internalFormat,
1083                                             width,
1084                                             height,
1085                                             depth,
1086                                             border);
[5378]1087    else
1088        return 0;
[3423]1089}                                             
1090
1091void Texture::flushAllDeletedTextureObjects(unsigned int contextID)
1092{
[10588]1093    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->flushAllTextureObjects(contextID);
[3423]1094}
1095
[7773]1096void Texture::discardAllDeletedTextureObjects(unsigned int contextID)
1097{
[10588]1098    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->discardAllTextureObjects(contextID);
[7773]1099}
1100
[3423]1101void Texture::flushDeletedTextureObjects(unsigned int contextID,double currentTime, double& availbleTime)
1102{
[10588]1103    if (getOriginalTextureObjectManager()) getOriginalTextureObjectManager()->flushTextureObjects(contextID, currentTime, availbleTime);
[2036]1104}
[2022]1105
[10588]1106void Texture::releaseTextureObject(unsigned int contextID, Texture::TextureObject* to)
1107{
1108    if (getOriginalTextureObjectManager())
1109    {
1110        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getOriginalTextureObjectManager()->_mutex);
1111        getOriginalTextureObjectManager()->_textureObjectListMap[contextID].push_back(to);
1112    }
1113}
1114
1115#endif
1116
1117
1118
[952]1119Texture::Texture():
[2541]1120            _wrap_s(CLAMP),
1121            _wrap_t(CLAMP),
1122            _wrap_r(CLAMP),
[1099]1123            _min_filter(LINEAR_MIPMAP_LINEAR), // trilinear
1124            _mag_filter(LINEAR),
1125            _maxAnisotropy(1.0f),
[1819]1126            _useHardwareMipMapGeneration(true),
1127            _unrefImageDataAfterApply(false),
[2791]1128            _clientStorageHint(false),
[4837]1129            _resizeNonPowerOfTwoHint(true),
[1099]1130            _borderColor(0.0, 0.0, 0.0, 0.0),
[2678]1131            _borderWidth(0),
[1099]1132            _internalFormatMode(USE_IMAGE_DATA_FORMAT),
[9062]1133            _internalFormatType(NORMALIZED),
[2551]1134            _internalFormat(0),
[4700]1135            _sourceFormat(0),
[4706]1136            _sourceType(0),
[2551]1137            _use_shadow_comparison(false),
1138            _shadow_compare_func(LEQUAL),
[2686]1139            _shadow_texture_mode(LUMINANCE),
[9062]1140            _shadow_ambient(0)
[2]1141{
1142}
1143
[992]1144Texture::Texture(const Texture& text,const CopyOp& copyop):
[1099]1145            StateAttribute(text,copyop),
1146            _wrap_s(text._wrap_s),
1147            _wrap_t(text._wrap_t),
1148            _wrap_r(text._wrap_r),
1149            _min_filter(text._min_filter),
1150            _mag_filter(text._mag_filter),
1151            _maxAnisotropy(text._maxAnisotropy),
[1773]1152            _useHardwareMipMapGeneration(text._useHardwareMipMapGeneration),
[1819]1153            _unrefImageDataAfterApply(text._unrefImageDataAfterApply),
[2791]1154            _clientStorageHint(text._clientStorageHint),
[4162]1155            _resizeNonPowerOfTwoHint(text._resizeNonPowerOfTwoHint),
[1099]1156            _borderColor(text._borderColor),
[2678]1157            _borderWidth(text._borderWidth),
[1099]1158            _internalFormatMode(text._internalFormatMode),
[9062]1159            _internalFormatType(text._internalFormatType),
[2551]1160            _internalFormat(text._internalFormat),
[4700]1161            _sourceFormat(text._sourceFormat),
1162            _sourceType(text._sourceType),
[2551]1163            _use_shadow_comparison(text._use_shadow_comparison),
1164            _shadow_compare_func(text._shadow_compare_func),
[2686]1165            _shadow_texture_mode(text._shadow_texture_mode),
[9062]1166            _shadow_ambient(text._shadow_ambient)
[1099]1167{
1168}
[2]1169
[8]1170Texture::~Texture()
[2]1171{
[1099]1172    // delete old texture objects.
1173    dirtyTextureObject();
[2]1174}
1175
[1099]1176int Texture::compareTexture(const Texture& rhs) const
[26]1177{
[1099]1178    COMPARE_StateAttribute_Parameter(_wrap_s)
1179    COMPARE_StateAttribute_Parameter(_wrap_t)
1180    COMPARE_StateAttribute_Parameter(_wrap_r)
1181    COMPARE_StateAttribute_Parameter(_min_filter)
1182    COMPARE_StateAttribute_Parameter(_mag_filter)
1183    COMPARE_StateAttribute_Parameter(_maxAnisotropy)
[1773]1184    COMPARE_StateAttribute_Parameter(_useHardwareMipMapGeneration)
[1099]1185    COMPARE_StateAttribute_Parameter(_internalFormatMode)
[3582]1186
1187    // only compare _internalFomat is it has alrady been set in both lhs, and rhs
1188    if (_internalFormat!=0 && rhs._internalFormat!=0)
1189    {
1190        COMPARE_StateAttribute_Parameter(_internalFormat)
1191    }
1192
[4700]1193    COMPARE_StateAttribute_Parameter(_sourceFormat)
1194    COMPARE_StateAttribute_Parameter(_sourceType)
1195
[2551]1196    COMPARE_StateAttribute_Parameter(_use_shadow_comparison)
1197    COMPARE_StateAttribute_Parameter(_shadow_compare_func)
1198    COMPARE_StateAttribute_Parameter(_shadow_texture_mode)
[2686]1199    COMPARE_StateAttribute_Parameter(_shadow_ambient)
[2791]1200
1201    COMPARE_StateAttribute_Parameter(_unrefImageDataAfterApply)
1202    COMPARE_StateAttribute_Parameter(_clientStorageHint)
[4162]1203    COMPARE_StateAttribute_Parameter(_resizeNonPowerOfTwoHint)
1204
[7385]1205    COMPARE_StateAttribute_Parameter(_internalFormatType);
1206   
[1099]1207    return 0;
1208}
[26]1209
[5452]1210int Texture::compareTextureObjects(const Texture& rhs) const
1211{
1212    if (_textureObjectBuffer.size()<rhs._textureObjectBuffer.size()) return -1;
1213    if (rhs._textureObjectBuffer.size()<_textureObjectBuffer.size()) return 1;
1214    for(unsigned int i=0; i<_textureObjectBuffer.size(); ++i)
1215    {
1216        if (_textureObjectBuffer[i] < rhs._textureObjectBuffer[i]) return -1;
1217        else if (rhs._textureObjectBuffer[i] < _textureObjectBuffer[i]) return 1;
1218    }
1219    return 0;
1220}
[1099]1221
[1133]1222void Texture::setWrap(WrapParameter which, WrapMode wrap)
[1099]1223{
1224    switch( which )
[26]1225    {
[1140]1226        case WRAP_S : _wrap_s = wrap; dirtyTextureParameters(); break;
1227        case WRAP_T : _wrap_t = wrap; dirtyTextureParameters(); break;
1228        case WRAP_R : _wrap_r = wrap; dirtyTextureParameters(); break;
[1099]1229        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setWrap("<<(unsigned int)which<<","<<(unsigned int)wrap<<")"<<std::endl; break;
[26]1230    }
[1099]1231   
1232}
[26]1233
[1073]1234
[1133]1235Texture::WrapMode Texture::getWrap(WrapParameter which) const
[1099]1236{
1237    switch( which )
1238    {
1239        case WRAP_S : return _wrap_s;
1240        case WRAP_T : return _wrap_t;
1241        case WRAP_R : return _wrap_r;
1242        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getWrap(which)"<<std::endl; return _wrap_s;
1243    }
1244}
[1073]1245
1246
[1133]1247void Texture::setFilter(FilterParameter which, FilterMode filter)
[1099]1248{
1249    switch( which )
1250    {
[1140]1251        case MIN_FILTER : _min_filter = filter; dirtyTextureParameters(); break;
1252        case MAG_FILTER : _mag_filter = filter; dirtyTextureParameters(); break;
[1099]1253        default : notify(WARN)<<"Error: invalid 'which' passed Texture::setFilter("<<(unsigned int)which<<","<<(unsigned int)filter<<")"<<std::endl; break;
1254    }
1255}
[26]1256
[1099]1257
[1133]1258Texture::FilterMode Texture::getFilter(FilterParameter which) const
[1099]1259{
1260    switch( which )
1261    {
1262        case MIN_FILTER : return _min_filter;
1263        case MAG_FILTER : return _mag_filter;
1264        default : notify(WARN)<<"Error: invalid 'which' passed Texture::getFilter(which)"<< std::endl; return _min_filter;
1265    }
[26]1266}
1267
[1099]1268void Texture::setMaxAnisotropy(float anis)
[2]1269{
[1099]1270    if (_maxAnisotropy!=anis)
[2]1271    {
[1099]1272        _maxAnisotropy = anis;
[1140]1273        dirtyTextureParameters();
[1099]1274    }
1275}
1276
[7385]1277
[1099]1278/** Force a recompile on next apply() of associated OpenGL texture objects.*/
1279void Texture::dirtyTextureObject()
1280{
[10588]1281    for(unsigned int i=0; i<_textureObjectBuffer.size();++i)
[1099]1282    {
[10588]1283        if (_textureObjectBuffer[i].valid())
[8]1284        {
[10588]1285            Texture::releaseTextureObject(i, _textureObjectBuffer[i].get());
1286            _textureObjectBuffer[i] = 0;
[8]1287        }
[2]1288    }
1289}
1290
[1140]1291void Texture::dirtyTextureParameters()
1292{
[7385]1293    _texParametersDirtyList.setAllElementsTo(1);
[1140]1294}
1295
[7385]1296void Texture::allocateMipmapLevels()
1297{
1298    _texMipmapGenerationDirtyList.setAllElementsTo(1);
1299}
1300
[1776]1301void Texture::computeInternalFormatWithImage(const osg::Image& image) const
[2]1302{
[3089]1303    GLint internalFormat = image.getInternalTextureFormat();
[2]1304
[3089]1305    if (_internalFormatMode==USE_IMAGE_DATA_FORMAT)
[2]1306    {
[3089]1307        internalFormat = image.getInternalTextureFormat();
1308    }
1309    else if (_internalFormatMode==USE_USER_DEFINED_FORMAT)
1310    {
1311        internalFormat = _internalFormat;
1312    }
1313    else
1314    {
[945]1315
[7648]1316        const unsigned int contextID = 0; // state.getContextID();  // set to 0 right now, assume same parameters for each graphics context...
[3089]1317        const Extensions* extensions = getExtensions(contextID,true);
1318
1319        switch(_internalFormatMode)
1320        {
[1099]1321        case(USE_ARB_COMPRESSION):
[1155]1322            if (extensions->isTextureCompressionARBSupported())
[8]1323            {
[1099]1324                switch(image.getPixelFormat())
1325                {
1326                    case(1): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1327                    case(2): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1328                    case(3): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1329                    case(4): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1330                    case(GL_RGB): internalFormat = GL_COMPRESSED_RGB_ARB; break;
1331                    case(GL_RGBA): internalFormat = GL_COMPRESSED_RGBA_ARB; break;
1332                    case(GL_ALPHA): internalFormat = GL_COMPRESSED_ALPHA_ARB; break;
1333                    case(GL_LUMINANCE): internalFormat = GL_COMPRESSED_LUMINANCE_ARB; break;
1334                    case(GL_LUMINANCE_ALPHA): internalFormat = GL_COMPRESSED_LUMINANCE_ALPHA_ARB; break;
1335                    case(GL_INTENSITY): internalFormat = GL_COMPRESSED_INTENSITY_ARB; break;
1336                }
1337            }
1338            else internalFormat = image.getInternalTextureFormat();
1339            break;
[990]1340
[1099]1341        case(USE_S3TC_DXT1_COMPRESSION):
[1155]1342            if (extensions->isTextureCompressionS3TCSupported())
[1099]1343            {
1344                switch(image.getPixelFormat())
1345                {
1346                    case(3):        internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1347                    case(4):        internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1348                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1349                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; break;
1350                    default:        internalFormat = image.getInternalTextureFormat(); break;
1351                }
1352            }
1353            else internalFormat = image.getInternalTextureFormat();
1354            break;
[990]1355
[1099]1356        case(USE_S3TC_DXT3_COMPRESSION):
[1155]1357            if (extensions->isTextureCompressionS3TCSupported())
[1099]1358            {
1359                switch(image.getPixelFormat())
1360                {
1361                    case(3):
1362                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1363                    case(4):
1364                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; break;
1365                    default:        internalFormat = image.getInternalTextureFormat(); break;
1366                }
1367            }
1368            else internalFormat = image.getInternalTextureFormat();
1369            break;
[990]1370
[1099]1371        case(USE_S3TC_DXT5_COMPRESSION):
[1155]1372            if (extensions->isTextureCompressionS3TCSupported())
[1047]1373            {
[1099]1374                switch(image.getPixelFormat())
1375                {
1376                    case(3):
1377                    case(GL_RGB):   internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT; break;
1378                    case(4):
1379                    case(GL_RGBA):  internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; break;
1380                    default:        internalFormat = image.getInternalTextureFormat(); break;
1381                }
[1047]1382            }
[1099]1383            else internalFormat = image.getInternalTextureFormat();
1384            break;
[3115]1385        default:
1386            break;
[3089]1387        }
[2]1388    }
[1099]1389   
1390    _internalFormat = internalFormat;
[7385]1391    computeInternalFormatType();
[3144]1392   
1393    //osg::notify(osg::NOTICE)<<"Internal format="<<std::hex<<internalFormat<<std::dec<<std::endl;
[1099]1394}
1395
[7385]1396void Texture::computeInternalFormatType() const
1397{
1398    // Here we could also precompute the _sourceFormat if it is not set,
1399    // since it is different for different internal formats
1400    // (i.e. rgba integer texture --> _sourceFormat = GL_RGBA_INTEGER_EXT)
1401    // Should we do this?  ( Art, 09. Sept. 2007)
1402   
1403    // compute internal format type based on the internal format
1404    switch(_internalFormat)
1405    {
1406        case GL_RGBA32UI_EXT:
1407        case GL_RGBA16UI_EXT:
1408        case GL_RGBA8UI_EXT:
1409
1410        case GL_RGB32UI_EXT:
1411        case GL_RGB16UI_EXT:
1412        case GL_RGB8UI_EXT:
1413
1414        case GL_LUMINANCE32UI_EXT
1415        case GL_LUMINANCE16UI_EXT:   
1416        case GL_LUMINANCE8UI_EXT:   
1417
1418        case GL_INTENSITY32UI_EXT:   
1419        case GL_INTENSITY16UI_EXT:   
1420        case GL_INTENSITY8UI_EXT:   
1421
1422        case GL_LUMINANCE_ALPHA32UI_EXT:   
1423        case GL_LUMINANCE_ALPHA16UI_EXT:   
1424        case GL_LUMINANCE_ALPHA8UI_EXT :   
1425            _internalFormatType = UNSIGNED_INTEGER;
1426            break;
1427
1428        case GL_RGBA32I_EXT:
1429        case GL_RGBA16I_EXT:
1430        case GL_RGBA8I_EXT:
1431
1432        case GL_RGB32I_EXT:
1433        case GL_RGB16I_EXT:
1434        case GL_RGB8I_EXT:
1435
1436        case GL_LUMINANCE32I_EXT:   
1437        case GL_LUMINANCE16I_EXT:   
1438        case GL_LUMINANCE8I_EXT:   
1439
1440        case GL_INTENSITY32I_EXT:   
1441        case GL_INTENSITY16I_EXT:   
1442        case GL_INTENSITY8I_EXT:   
1443
1444        case GL_LUMINANCE_ALPHA32I_EXT:   
1445        case GL_LUMINANCE_ALPHA16I_EXT:   
1446        case GL_LUMINANCE_ALPHA8I_EXT:   
1447            _internalFormatType = SIGNED_INTEGER;
1448            break;
1449       
1450        case GL_RGBA32F_ARB:
1451        case GL_RGBA16F_ARB:
1452
1453        case GL_RGB32F_ARB:
1454        case GL_RGB16F_ARB:
1455
1456        case GL_LUMINANCE32F_ARB:
1457        case GL_LUMINANCE16F_ARB:   
1458
1459        case GL_INTENSITY32F_ARB:
1460        case GL_INTENSITY16F_ARB:   
1461
1462        case GL_LUMINANCE_ALPHA32F_ARB:
1463        case GL_LUMINANCE_ALPHA16F_ARB:   
1464            _internalFormatType = FLOAT;
1465            break;
1466           
1467        default:
1468            _internalFormatType = NORMALIZED;
1469            break;
1470    };
1471}
1472
[1160]1473bool Texture::isCompressedInternalFormat() const
1474{
1475    return isCompressedInternalFormat(getInternalFormat());
1476}
1477
[5213]1478bool Texture::isCompressedInternalFormat(GLint internalFormat)
[1099]1479{
1480    switch(internalFormat)
[2]1481    {
[1099]1482        case(GL_COMPRESSED_ALPHA_ARB):
1483        case(GL_COMPRESSED_INTENSITY_ARB):
1484        case(GL_COMPRESSED_LUMINANCE_ALPHA_ARB):
1485        case(GL_COMPRESSED_LUMINANCE_ARB):
1486        case(GL_COMPRESSED_RGBA_ARB):
1487        case(GL_COMPRESSED_RGB_ARB):
[3448]1488        case(GL_COMPRESSED_RGB_S3TC_DXT1_EXT):
[1099]1489        case(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT):
1490        case(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT):
1491        case(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT):
1492            return true;
1493        default:
1494            return false;
1495    }
1496}
[2]1497
[5213]1498void Texture::getCompressedSize(GLenum internalFormat, GLint width, GLint height, GLint depth, GLint& blockSize, GLint& size)
[3447]1499{
[3620]1500    if (internalFormat == GL_COMPRESSED_RGB_S3TC_DXT1_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
[3447]1501        blockSize = 8;
[5250]1502    else if (internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT3_EXT || internalFormat == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
1503        blockSize = 16;
[3447]1504    else
[5250]1505    {
1506        notify(WARN)<<"Texture::getCompressedSize(...) : cannot compute correct size of compressed format ("<<internalFormat<<") returning 0."<<std::endl;
1507        blockSize = 0;
1508    }
[3447]1509         
1510    size = ((width+3)/4)*((height+3)/4)*depth*blockSize;       
1511}
1512
[1140]1513void Texture::applyTexParameters(GLenum target, State& state) const
[1099]1514{
[1155]1515    // get the contextID (user defined ID of 0 upwards) for the
1516    // current OpenGL context.
[1600]1517    const unsigned int contextID = state.getContextID();
[1155]1518    const Extensions* extensions = getExtensions(contextID,true);
1519
[1459]1520    WrapMode ws = _wrap_s, wt = _wrap_t, wr = _wrap_r;
[8]1521
[1099]1522    // GL_IBM_texture_mirrored_repeat, fall-back REPEAT
[1155]1523    if (!extensions->isTextureMirroredRepeatSupported())
[1099]1524    {
1525        if (ws == MIRROR)
1526            ws = REPEAT;
1527        if (wt == MIRROR)
1528            wt = REPEAT;
[1459]1529        if (wr == MIRROR)
1530            wr = REPEAT;
[1099]1531    }
[8]1532
[1099]1533    // GL_EXT_texture_edge_clamp, fall-back CLAMP
[1155]1534    if (!extensions->isTextureEdgeClampSupported())
[1099]1535    {
1536        if (ws == CLAMP_TO_EDGE)
1537            ws = CLAMP;
1538        if (wt == CLAMP_TO_EDGE)
1539            wt = CLAMP;
[1459]1540        if (wr == CLAMP_TO_EDGE)
1541            wr = CLAMP;
[1099]1542    }
[8]1543
[1155]1544    if(!extensions->isTextureBorderClampSupported())
[1099]1545    {
1546        if(ws == CLAMP_TO_BORDER)
1547            ws = CLAMP;
1548        if(wt == CLAMP_TO_BORDER)
1549            wt = CLAMP;
[1459]1550        if(wr == CLAMP_TO_BORDER)
1551            wr = CLAMP;
[8]1552    }
[10370]1553   
1554    const Image * image = getImage(0);
1555    if( image &&
1556        image->isMipmap() &&
1557        extensions->isTextureMaxLevelSupported() &&
1558        int( image->getNumMipmapLevels() ) <
1559            Image::computeNumberOfMipmapLevels( image->s(), image->t(), image->r() ) )
1560            glTexParameteri( target, GL_TEXTURE_MAX_LEVEL, image->getNumMipmapLevels() - 1 );   
[1099]1561
[10370]1562
[1099]1563    glTexParameteri( target, GL_TEXTURE_WRAP_S, ws );
[2153]1564   
1565    if (target!=GL_TEXTURE_1D) glTexParameteri( target, GL_TEXTURE_WRAP_T, wt );
1566   
1567    if (target==GL_TEXTURE_3D) glTexParameteri( target, GL_TEXTURE_WRAP_R, wr );
[1099]1568
[10370]1569   
[1099]1570    glTexParameteri( target, GL_TEXTURE_MIN_FILTER, _min_filter);
1571    glTexParameteri( target, GL_TEXTURE_MAG_FILTER, _mag_filter);
1572
[7385]1573    // Art: I think anisotropic filtering is not supported by the integer textures
1574    if (extensions->isTextureFilterAnisotropicSupported() &&
1575        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
[8]1576    {
[1155]1577        // note, GL_TEXTURE_MAX_ANISOTROPY_EXT will either be defined
1578        // by gl.h (or via glext.h) or by include/osg/Texture.
1579        glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, _maxAnisotropy);
[2]1580    }
[1099]1581
[1155]1582    if (extensions->isTextureBorderClampSupported())
[1099]1583    {
[7385]1584        if (_internalFormatType == SIGNED_INTEGER)
1585        {
1586            GLint color[4] = {(GLint)_borderColor.r(), (GLint)_borderColor.g(), (GLint)_borderColor.b(), (GLint)_borderColor.a()};
1587            extensions->glTexParameterIiv(target, GL_TEXTURE_BORDER_COLOR, color);
1588        }else if (_internalFormatType == UNSIGNED_INTEGER)
1589        {
1590            GLuint color[4] = {(GLuint)_borderColor.r(), (GLuint)_borderColor.g(), (GLuint)_borderColor.b(), (GLuint)_borderColor.a()};
1591            extensions->glTexParameterIuiv(target, GL_TEXTURE_BORDER_COLOR, color);
1592        }else{
1593            GLfloat color[4] = {(GLfloat)_borderColor.r(), (GLfloat)_borderColor.g(), (GLfloat)_borderColor.b(), (GLfloat)_borderColor.a()};
1594            glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, color);
1595        }
[1099]1596    }
1597
[7385]1598    // integer texture are not supported by the shadow
[10092]1599    if (extensions->isShadowSupported() && (target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE) &&
[7385]1600        _internalFormatType != SIGNED_INTEGER && _internalFormatType != UNSIGNED_INTEGER)
[4430]1601    {
[2551]1602        if (_use_shadow_comparison)
[4430]1603        {
[2558]1604            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
[2551]1605            glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, _shadow_compare_func);
1606            glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, _shadow_texture_mode);
[2686]1607
1608            // if ambient value is 0 - it is default behaviour of GL_ARB_shadow
1609            // no need for GL_ARB_shadow_ambient in this case
1610            if (extensions->isShadowAmbientSupported() && _shadow_ambient > 0)
[4430]1611            {
[2686]1612                glTexParameterf(target, TEXTURE_COMPARE_FAIL_VALUE_ARB, _shadow_ambient);
[4430]1613            }
1614        }
[2551]1615        else 
[4430]1616        {
[2551]1617            glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
[4430]1618        }
1619    }
[2551]1620
[1305]1621    getTextureParameterDirty(state.getContextID()) = false;
[1099]1622
[2]1623}
[8]1624
[2022]1625void Texture::computeRequiredTextureDimensions(State& state, const osg::Image& image,GLsizei& inwidth, GLsizei& inheight,GLsizei& numMipmapLevels) const
[8]1626{
[2022]1627    const unsigned int contextID = state.getContextID();
1628    const Extensions* extensions = getExtensions(contextID,true);
1629
[4162]1630    int width,height;
[2022]1631
[4248]1632    if( !_resizeNonPowerOfTwoHint && extensions->isNonPowerOfTwoTextureSupported(_min_filter) )
[4162]1633    {
1634        width = image.s();
1635        height = image.t();
1636    }
1637    else
1638    {
1639        width = Image::computeNearestPowerOfTwo(image.s()-2*_borderWidth)+2*_borderWidth;
1640        height = Image::computeNearestPowerOfTwo(image.t()-2*_borderWidth)+2*_borderWidth;
1641    }
1642
[2022]1643    // cap the size to what the graphics hardware can handle.
1644    if (width>extensions->maxTextureSize()) width = extensions->maxTextureSize();
1645    if (height>extensions->maxTextureSize()) height = extensions->maxTextureSize();
[4162]1646
[2022]1647    inwidth = width;
1648    inheight = height;
1649   
[10595]1650    if( _min_filter == LINEAR || _min_filter == NEAREST)
[2022]1651    {
[2586]1652        numMipmapLevels = 1;
1653    }
1654    else if( image.isMipmap() )
1655    {
1656        numMipmapLevels = image.getNumMipmapLevels();
1657    }
1658    else
1659    {
[10595]1660        numMipmapLevels = 1;
1661        for(int s=1; s<width || s<height; s <<= 1, ++numMipmapLevels) {}
1662    }
[2022]1663
[9037]1664    // osg::notify(osg::NOTICE)<<"Texture::computeRequiredTextureDimensions() image.s() "<<image.s()<<" image.t()="<<image.t()<<" width="<<width<<" height="<<height<<" numMipmapLevels="<<numMipmapLevels<<std::endl;
1665    // osg::notify(osg::NOTICE)<<"  _resizeNonPowerOfTwoHint="<<_resizeNonPowerOfTwoHint<<" extensions->isNonPowerOfTwoTextureSupported(_min_filter)="<<extensions->isNonPowerOfTwoTextureSupported(_min_filter) <<std::endl;
[2022]1666}
1667
1668bool Texture::areAllTextureObjectsLoaded() const
1669{
1670    for(unsigned int i=0;i<DisplaySettings::instance()->getMaxNumberOfGraphicsContexts();++i)
1671    {
[2647]1672        if (_textureObjectBuffer[i]==0) return false;
[2022]1673    }
[2647]1674    return true;
[2022]1675}
1676
[3447]1677
[2022]1678void Texture::applyTexImage2D_load(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight,GLsizei numMipmapLevels) const
1679{
[1099]1680    // if we don't have a valid image we can't create a texture!
1681    if (!image || !image->data())
1682        return;
[8]1683
[3852]1684#ifdef DO_TIMING
1685    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1686    osg::notify(osg::NOTICE)<<"glTexImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
1687#endif
1688
[1099]1689    // get the contextID (user defined ID of 0 upwards) for the
1690    // current OpenGL context.
[1600]1691    const unsigned int contextID = state.getContextID();
[1155]1692    const Extensions* extensions = getExtensions(contextID,true);
[8]1693
[1099]1694    // select the internalFormat required for the texture.
[2022]1695    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
[5267]1696
1697    // If the texture's internal format is a compressed type, then the
1698    // user is requesting that the graphics card compress the image if it's
1699    // not already compressed. However, if the image is not a multiple of
1700    // four in each dimension the subsequent calls to glTexSubImage* will
1701    // fail. Revert to uncompressed format in this case.
1702    if (isCompressedInternalFormat(_internalFormat) &&
1703        (((inwidth >> 2) << 2) != inwidth ||
1704         ((inheight >> 2) << 2) != inheight))
1705    {
1706        osg::notify(osg::NOTICE)<<"Received a request to compress an image, but image size is not a multiple of four ("<<inwidth<<"x"<<inheight<<"). Reverting to uncompressed.\n";
1707        switch(_internalFormat)
1708        {
1709            case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
1710            case GL_COMPRESSED_RGB: _internalFormat = GL_RGB; break;
1711            case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
1712            case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
1713            case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
1714            case GL_COMPRESSED_RGBA: _internalFormat = GL_RGBA; break;
1715            case GL_COMPRESSED_ALPHA: _internalFormat = GL_ALPHA; break;
1716            case GL_COMPRESSED_LUMINANCE: _internalFormat = GL_LUMINANCE; break;
1717            case GL_COMPRESSED_LUMINANCE_ALPHA: _internalFormat = GL_LUMINANCE_ALPHA; break;
1718            case GL_COMPRESSED_INTENSITY: _internalFormat = GL_INTENSITY; break;
1719        }
1720    }
[1099]1721   
1722    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
[1776]1723   
[2791]1724    bool useClientStorage = extensions->isClientStorageSupported() && getClientStorageHint();
1725    if (useClientStorage)
1726    {
1727        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_TRUE);
1728        glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_PRIORITY,0.0f);
1729       
1730        #ifdef GL_TEXTURE_STORAGE_HINT_APPLE   
1731            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_CACHED_APPLE);
1732        #endif
1733    }
1734   
[1776]1735    unsigned char* data = (unsigned char*)image->data();
1736 
[9037]1737    // osg::notify(osg::NOTICE)<<"inwidth="<<inwidth<<" inheight="<<inheight<<" image->getFileName()"<<image->getFileName()<<std::endl;
[1099]1738
[2022]1739    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
[1776]1740    if (needImageRescale)
[8]1741    {
[1776]1742
1743        // resize the image to power of two.
1744       
1745        if (image->isMipmap())
1746        {
1747            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1748            return;
1749        }
1750        else if (compressed_image)
1751        {
1752            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1753            return;
1754        }
1755       
[2022]1756        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
[1776]1757        data = new unsigned char [newTotalSize];
1758       
1759        if (!data)
1760        {
1761            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
1762            return;
1763        }
1764
[2022]1765        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
1766        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
[1776]1767
1768        // rescale the image to the correct size.
1769        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
1770        gluScaleImage(image->getPixelFormat(),
1771                      image->s(),image->t(),image->getDataType(),image->data(),
[2022]1772                      inwidth,inheight,image->getDataType(),data);
[1776]1773       
1774    }   
1775
[8657]1776    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
1777    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
1778    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
1779
[10600]1780    const unsigned char* dataPtr = image->data();
1781    GLBufferObject* pbo = image->getOrCreateGLBufferObject(contextID);
1782    if (pbo && !needImageRescale && !useGluBuildMipMaps)
[3852]1783    {
[6582]1784        state.bindPixelBufferObject(pbo);
[10600]1785        dataPtr = reinterpret_cast<const unsigned char*>(pbo->getOffset(image->getBufferIndex()));
[3852]1786#ifdef DO_TIMING
1787        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
1788#endif
1789    }
1790    else
1791    {
1792        pbo = 0;
1793    }
1794
[8657]1795    if( !mipmappingRequired || useHardwareMipMapGeneration)
[1776]1796    {
[8373]1797
1798        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
1799
[1773]1800        if ( !compressed_image)
[8]1801        {
[2022]1802            numMipmapLevels = 1;
[1773]1803
[1099]1804            glTexImage2D( target, 0, _internalFormat,
[2678]1805                inwidth, inheight, _borderWidth,
[1099]1806                (GLenum)image->getPixelFormat(),
1807                (GLenum)image->getDataType(),
[10600]1808                dataPtr);
[1099]1809
[8]1810        }
[1155]1811        else if (extensions->isCompressedTexImage2DSupported())
[1099]1812        {
[2022]1813            numMipmapLevels = 1;
[1773]1814
[3447]1815            GLint blockSize, size;
1816            getCompressedSize(_internalFormat, inwidth, inheight, 1, blockSize,size);
[1773]1817
1818            extensions->glCompressedTexImage2D(target, 0, _internalFormat,
[2022]1819                inwidth, inheight,0,
[1773]1820                size,
[10600]1821                dataPtr);
[1773]1822        }
1823
[8373]1824        mipmapAfterTexImage(state, mipmapResult);
[1773]1825    }
1826    else
1827    {
[1776]1828        // we require mip mapping.
1829        if(image->isMipmap())
[1773]1830        {
[3115]1831
[1776]1832            // image is mip mapped so we take the mip map levels from the image.
1833       
[2022]1834            numMipmapLevels = image->getNumMipmapLevels();
[8]1835
[2022]1836            int width  = inwidth;
1837            int height = inheight;
[8]1838
[1773]1839            if( !compressed_image )
[1099]1840            {
[2022]1841                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
[1099]1842                {
[8]1843
[1099]1844                    if (width == 0)
1845                        width = 1;
1846                    if (height == 0)
1847                        height = 1;
1848
1849                    glTexImage2D( target, k, _internalFormat,
[2678]1850                         width, height, _borderWidth,
[1099]1851                        (GLenum)image->getPixelFormat(),
1852                        (GLenum)image->getDataType(),
[10600]1853                        dataPtr + image->getMipmapOffset(k));
[1099]1854
1855                    width >>= 1;
1856                    height >>= 1;
1857                }
1858            }
[1155]1859            else if (extensions->isCompressedTexImage2DSupported())
[1099]1860            {
[3447]1861                GLint blockSize, size;
1862
[2022]1863                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
[1099]1864                {
[1773]1865                    if (width == 0)
1866                        width = 1;
1867                    if (height == 0)
1868                        height = 1;
[1099]1869
[3447]1870                    getCompressedSize(_internalFormat, width, height, 1, blockSize,size);
[3448]1871                   
[1773]1872                    extensions->glCompressedTexImage2D(target, k, _internalFormat,
[2678]1873                                                       width, height, _borderWidth,
[10600]1874                                                       size, dataPtr + image->getMipmapOffset(k));
[1773]1875
1876                    width >>= 1;
1877                    height >>= 1;
1878                }
1879            }
1880        }
[1776]1881        else
1882        {
1883       
1884            if ( !compressed_image)
1885            {
[2022]1886                numMipmapLevels = 0;
[1773]1887
[1776]1888                gluBuild2DMipmaps( target, _internalFormat,
[2022]1889                    inwidth,inheight,
[1776]1890                    (GLenum)image->getPixelFormat(), (GLenum)image->getDataType(),
[8657]1891                    data);
[1776]1892
1893                int width  = image->s();
1894                int height = image->t();
[2022]1895                for( numMipmapLevels = 0 ; (width || height) ; ++numMipmapLevels)
[1776]1896                {
1897                    width >>= 1;
1898                    height >>= 1;
1899                }
1900            }
1901            else 
1902            {
1903                notify(WARN)<<"Warning:: Compressed image cannot be mip mapped"<<std::endl;
1904            }
1905
1906        }
1907
[1773]1908    }
1909
[3852]1910    if (pbo)
1911    {
[6582]1912        state.unbindPixelBufferObject();
[3852]1913    }
[6582]1914   
[3852]1915#ifdef DO_TIMING
1916    static double s_total_time = 0.0;
1917    double delta_time = osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick());
1918    s_total_time += delta_time;
1919    osg::notify(osg::NOTICE)<<"glTexImage2D "<<delta_time<<"ms  total "<<s_total_time<<"ms"<<std::endl;
1920#endif
1921
[1776]1922    if (needImageRescale)
1923    {
1924        // clean up the resized image.
1925        delete [] data;
1926    }
[1773]1927   
[2791]1928    if (useClientStorage)
1929    {
1930        glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE,GL_FALSE);
1931    }
[1773]1932}
1933
[2022]1934
1935
[2662]1936void Texture::applyTexImage2D_subload(State& state, GLenum target, const Image* image, GLsizei inwidth, GLsizei inheight, GLint inInternalFormat, GLint numMipmapLevels) const
[1773]1937{
1938    // if we don't have a valid image we can't create a texture!
1939    if (!image || !image->data())
1940        return;
1941
1942    // image size has changed so we have to re-load the image from scratch.
[2662]1943    if (image->s()!=inwidth || image->t()!=inheight || image->getInternalTextureFormat()!=inInternalFormat )
[1773]1944    {
[2022]1945        applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
[1773]1946        return;
1947    }
1948    // else image size the same as when loaded so we can go ahead and subload
1949   
[5267]1950    // If the texture's internal format is a compressed type, then the
1951    // user is requesting that the graphics card compress the image if it's
1952    // not already compressed. However, if the image is not a multiple of
1953    // four in each dimension the subsequent calls to glTexSubImage* will
1954    // fail. Revert to uncompressed format in this case.
1955    if (isCompressedInternalFormat(_internalFormat) &&
1956        (((inwidth >> 2) << 2) != inwidth ||
1957         ((inheight >> 2) << 2) != inheight))
1958    {
1959        applyTexImage2D_load(state, target, image, inwidth, inheight, numMipmapLevels);
1960        return;
1961    }
1962
[3852]1963#ifdef DO_TIMING
1964    osg::Timer_t start_tick = osg::Timer::instance()->tick();
1965    osg::notify(osg::NOTICE)<<"glTexSubImage2D pixelFormat = "<<std::hex<<image->getPixelFormat()<<std::dec<<std::endl;
1966#endif
[1788]1967   
[1773]1968
1969    // get the contextID (user defined ID of 0 upwards) for the
1970    // current OpenGL context.
1971    const unsigned int contextID = state.getContextID();
1972    const Extensions* extensions = getExtensions(contextID,true);
1973
1974    // select the internalFormat required for the texture.
1975    bool compressed_image = isCompressedInternalFormat((GLenum)image->getPixelFormat());
1976   
1977    glPixelStorei(GL_UNPACK_ALIGNMENT,image->getPacking());
[1776]1978   
1979    unsigned char* data = (unsigned char*)image->data();
1980 
[1773]1981
[2022]1982    bool needImageRescale = inwidth!=image->s() || inheight!=image->t();
[1776]1983    if (needImageRescale)
[1773]1984    {
[1776]1985
1986        // resize the image to power of two.
1987       
1988        if (image->isMipmap())
1989        {
1990            notify(WARN)<<"Warning:: Mipmapped osg::Image not a power of two, cannot apply to texture."<<std::endl;
1991            return;
1992        }
1993        else if (compressed_image)
1994        {
1995            notify(WARN)<<"Warning:: Compressed osg::Image not a power of two, cannot apply to texture."<<std::endl;
1996            return;
1997        }
1998       
[2022]1999        unsigned int newTotalSize = osg::Image::computeRowWidthInBytes(inwidth,image->getPixelFormat(),image->getDataType(),image->getPacking())*inheight;
[1776]2000        data = new unsigned char [newTotalSize];
2001       
2002        if (!data)
2003        {
2004            notify(WARN)<<"Warning:: Not enough memory to resize image, cannot apply to texture."<<std::endl;
2005            return;
2006        }
2007
[2022]2008        if (!image->getFileName().empty()) notify(NOTICE) << "Scaling image '"<<image->getFileName()<<"' from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
2009        else notify(NOTICE) << "Scaling image from ("<<image->s()<<","<<image->t()<<") to ("<<inwidth<<","<<inheight<<")"<<std::endl;
[1776]2010
2011        // rescale the image to the correct size.
2012        glPixelStorei(GL_PACK_ALIGNMENT,image->getPacking());
2013        gluScaleImage(image->getPixelFormat(),
2014                      image->s(),image->t(),image->getDataType(),image->data(),
[2022]2015                      inwidth,inheight,image->getDataType(),data);
[1776]2016       
2017    }   
2018
2019
[8657]2020    bool mipmappingRequired = _min_filter != LINEAR && _min_filter != NEAREST;
2021    bool useHardwareMipMapGeneration = mipmappingRequired && (!image->isMipmap() && isHardwareMipmapGenerationEnabled(state));
2022    bool useGluBuildMipMaps = mipmappingRequired && (!useHardwareMipMapGeneration && !image->isMipmap());
2023
2024    unsigned char* dataMinusOffset = 0;
2025    unsigned char* dataPlusOffset = 0;
2026   
[10600]2027    const unsigned char* dataPtr = image->data();
2028    GLBufferObject* pbo = image->getOrCreateGLBufferObject(contextID);
2029    if (pbo && !needImageRescale && !useGluBuildMipMaps)
[3819]2030    {
[6582]2031        state.bindPixelBufferObject(pbo);
[10600]2032        dataPtr = reinterpret_cast<unsigned char*>(pbo->getOffset(image->getBufferIndex()));
[3852]2033#ifdef DO_TIMING
2034        osg::notify(osg::NOTICE)<<"after PBO "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2035#endif
[3819]2036    }
2037    else
2038    {
2039        pbo = 0;
2040    }
2041
[8657]2042    if( !mipmappingRequired || useHardwareMipMapGeneration)
[1776]2043    {
2044
[8657]2045        GenerateMipmapMode mipmapResult = mipmapBeforeTexImage(state, useHardwareMipMapGeneration);
[8373]2046
[1773]2047        if (!compressed_image)
2048        {
[10589]2049#if 0
2050            glTexImage2D( target, 0, _internalFormat,
2051                inwidth, inheight, _borderWidth,
2052                (GLenum)image->getPixelFormat(),
2053                (GLenum)image->getDataType(),
2054                data -dataMinusOffset+dataPlusOffset);
2055#else
[1773]2056            glTexSubImage2D( target, 0,
2057                0, 0,
[2022]2058                inwidth, inheight,
[1773]2059                (GLenum)image->getPixelFormat(),
2060                (GLenum)image->getDataType(),
[3852]2061                data - dataMinusOffset + dataPlusOffset);
[10589]2062#endif
[1773]2063        }
2064        else if (extensions->isCompressedTexImage2DSupported())
2065        {       
[3447]2066            GLint blockSize,size;
[5254]2067            getCompressedSize(image->getInternalTextureFormat(), inwidth, inheight, 1, blockSize,size);
[2022]2068
[1773]2069            extensions->glCompressedTexSubImage2D(target, 0,
2070                0,0,
[2022]2071                inwidth, inheight,
[1773]2072                (GLenum)image->getPixelFormat(),
[2022]2073                size,
[3852]2074                data - dataMinusOffset + dataPlusOffset );               
[1773]2075        }
2076
[8373]2077        mipmapAfterTexImage(state, mipmapResult);
[1773]2078    }
2079    else
2080    {
[1776]2081        if (image->isMipmap())
[1773]2082        {
[2022]2083            numMipmapLevels = image->getNumMipmapLevels();
[1773]2084
[2022]2085            int width  = inwidth;
2086            int height = inheight;
[1776]2087
2088            if( !compressed_image )
[1773]2089            {
[2022]2090                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
[1776]2091                {
[1773]2092
[1776]2093                    if (width == 0)
2094                        width = 1;
2095                    if (height == 0)
2096                        height = 1;
[1773]2097
[1776]2098                    glTexSubImage2D( target, k,
2099                        0, 0,
2100                        width, height,
2101                        (GLenum)image->getPixelFormat(),
2102                        (GLenum)image->getDataType(),
[3852]2103                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);
[1773]2104
[1776]2105                    width >>= 1;
2106                    height >>= 1;
2107                }
[1773]2108            }
[1776]2109            else if (extensions->isCompressedTexImage2DSupported())
[1773]2110            {
[3447]2111                GLint blockSize,size;
[2022]2112                for( GLsizei k = 0 ; k < numMipmapLevels  && (width || height) ;k++)
[1776]2113                {
2114                    if (width == 0)
2115                        width = 1;
2116                    if (height == 0)
2117                        height = 1;
2118
[5254]2119                    getCompressedSize(image->getInternalTextureFormat(), width, height, 1, blockSize,size);
[1776]2120
[2036]2121                    //state.checkGLErrors("before extensions->glCompressedTexSubImage2D(");
[2022]2122
[1776]2123                    extensions->glCompressedTexSubImage2D(target, k, 
2124                                                       0, 0,
2125                                                       width, height,
2126                                                       (GLenum)image->getPixelFormat(),
[2022]2127                                                       size,
[3852]2128                                                        image->getMipmapData(k) - dataMinusOffset + dataPlusOffset);               
[1776]2129
[2036]2130                    //state.checkGLErrors("after extensions->glCompressedTexSubImage2D(");
[2022]2131
[1776]2132                    width >>= 1;
2133                    height >>= 1;
2134                }
[2022]2135
[1776]2136            }
2137        }
2138        else
2139        {
[4554]2140            //notify(WARN)<<"Warning:: cannot subload mip mapped texture from non mipmapped image."<<std::endl;
2141            applyTexImage2D_load(state, target, image, inwidth, inheight,numMipmapLevels);
2142            return;
[1099]2143        }
2144    }
2145   
[3819]2146    if (pbo)
2147    {
[6582]2148        state.unbindPixelBufferObject();
[3819]2149    }
[3852]2150#ifdef DO_TIMING
2151    osg::notify(osg::NOTICE)<<"glTexSubImage2D "<<osg::Timer::instance()->delta_m(start_tick,osg::Timer::instance()->tick())<<"ms"<<std::endl;
2152#endif
[3819]2153
[1776]2154    if (needImageRescale)
2155    {
2156        // clean up the resized image.
2157        delete [] data;
2158    }
[8]2159}
2160
[8373]2161bool Texture::isHardwareMipmapGenerationEnabled(const State& state) const
2162{
2163    if (_useHardwareMipMapGeneration)
2164    {
2165        unsigned int contextID = state.getContextID();
2166        const Extensions* extensions = getExtensions(contextID,true);
[1143]2167
[8373]2168        if (extensions->isGenerateMipMapSupported())
2169        {
2170            return true;
2171        }
2172
2173        const FBOExtensions* fbo_ext = FBOExtensions::instance(contextID,true);
2174
2175        if (fbo_ext->glGenerateMipmapEXT)
2176        {
2177            return true;
2178        }
2179    }
2180
2181    return false;
2182}
2183
2184Texture::GenerateMipmapMode Texture::mipmapBeforeTexImage(const State& state, bool hardwareMipmapOn) const
2185{
2186    if (hardwareMipmapOn)
2187    {
[8376]2188        int width = getTextureWidth();
2189        int height = getTextureHeight();
2190
2191        //quick bithack to determine whether width or height are non-power-of-two
2192        if ((width & (width - 1)) || (height & (height - 1)))
[8373]2193        {
[8376]2194            //GL_GENERATE_MIPMAP_SGIS with non-power-of-two textures on NVIDIA hardware
2195            //is extremely slow. Use glGenerateMipmapEXT() instead if supported.
2196            if (_internalFormatType != SIGNED_INTEGER &&
2197                _internalFormatType != UNSIGNED_INTEGER)
2198            {
2199                if (FBOExtensions::instance(state.getContextID(), true)->glGenerateMipmapEXT)
2200                {
2201                    return GENERATE_MIPMAP;
2202                }
2203            }
[8373]2204        }
[8376]2205
2206        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
2207        return GENERATE_MIPMAP_TEX_PARAMETER;
[8373]2208    }
2209    return GENERATE_MIPMAP_NONE;
2210}
2211
2212void Texture::mipmapAfterTexImage(State& state, GenerateMipmapMode beforeResult) const
2213{
2214    switch (beforeResult)
2215    {
2216    case GENERATE_MIPMAP:
[8376]2217        {
2218            unsigned int contextID = state.getContextID();
2219            TextureObject* textureObject = getTextureObject(contextID);
2220            if (textureObject)
2221            {
2222                osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(contextID, true);
[10588]2223                fbo_ext->glGenerateMipmapEXT(textureObject->target());
[8376]2224            }
2225        }
[8373]2226        break;
2227    case GENERATE_MIPMAP_TEX_PARAMETER:
2228        glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_FALSE);
2229        break;
[9062]2230    case GENERATE_MIPMAP_NONE:
2231        break;
[8373]2232    }
2233}
2234
[7385]2235void Texture::generateMipmap(State& state) const
2236{
2237    const unsigned int contextID = state.getContextID();
2238
2239    // get the texture object for the current contextID.
2240    TextureObject* textureObject = getTextureObject(contextID);
2241
2242    // if not initialized before, then do nothing
2243    if (textureObject == NULL) return;
2244
2245    _texMipmapGenerationDirtyList[contextID] = 0;
2246   
2247    // if internal format does not provide automatic mipmap generation, then do manual allocation
2248    if (_internalFormatType == SIGNED_INTEGER || _internalFormatType == UNSIGNED_INTEGER)
2249    {
2250        allocateMipmap(state);
2251        return;
2252    }
2253   
2254    // get fbo extension which provides us with the glGenerateMipmapEXT function
2255    osg::FBOExtensions* fbo_ext = osg::FBOExtensions::instance(state.getContextID(), true);
2256
2257    // check if the function is supported
2258    if (fbo_ext->glGenerateMipmapEXT)
2259    {
2260        textureObject->bind();
[10588]2261        fbo_ext->glGenerateMipmapEXT(textureObject->target());
[7385]2262       
2263        // inform state that this texture is the current one bound.
2264        state.haveAppliedTextureAttribute(state.getActiveTextureUnit(), this);
2265   
2266    // if the function is not supported, then do manual allocation
2267    }else
2268    {
2269        allocateMipmap(state);
2270    }
2271   
2272}
2273
[3159]2274void Texture::compileGLObjects(State& state) const
[1155]2275{
2276    apply(state);
2277}
[8]2278
[5882]2279void Texture::resizeGLObjectBuffers(unsigned int maxSize)
2280{
2281    _textureObjectBuffer.resize(maxSize);
2282}
2283
[3159]2284void Texture::releaseGLObjects(State* state) const
2285{
[5934]2286//    if (state) osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects contextID="<<state->getContextID()<<std::endl;
2287//    else osg::notify(osg::NOTICE)<<"Texture::releaseGLObjects no State "<<std::endl;
[5933]2288
[3215]2289    if (!state) const_cast<Texture*>(this)->dirtyTextureObject();
2290    else
2291    {
2292        unsigned int contextID = state->getContextID();
[10588]2293        if (_textureObjectBuffer[contextID].valid())
[3215]2294        {
[10588]2295            Texture::releaseTextureObject(contextID, _textureObjectBuffer[contextID].get());
2296
[3215]2297            _textureObjectBuffer[contextID] = 0;
2298        }
2299    }
[3159]2300}
[1155]2301
[1854]2302Texture::Extensions* Texture::getExtensions(unsigned int contextID,bool createIfNotInitalized)
[1099]2303{
[4102]2304    if (!s_extensions[contextID] && createIfNotInitalized) s_extensions[contextID] = new Extensions(contextID);
[1155]2305    return s_extensions[contextID].get();
2306}
2307
[1600]2308void Texture::setExtensions(unsigned int contextID,Extensions* extensions)
[1155]2309{
2310    s_extensions[contextID] = extensions;
2311}
2312
[4102]2313Texture::Extensions::Extensions(unsigned int contextID)
[1155]2314{
[4102]2315    setupGLExtensions(contextID);
[1155]2316}
2317
2318Texture::Extensions::Extensions(const Extensions& rhs):
2319    Referenced()
2320{
[1856]2321    _isMultiTexturingSupported = rhs._isMultiTexturingSupported;
[1155]2322    _isTextureFilterAnisotropicSupported = rhs._isTextureFilterAnisotropicSupported;
[1646]2323    _isTextureCompressionARBSupported = rhs._isTextureCompressionARBSupported;
2324    _isTextureCompressionS3TCSupported = rhs._isTextureCompressionS3TCSupported;
[1155]2325    _isTextureMirroredRepeatSupported = rhs._isTextureMirroredRepeatSupported;
2326    _isTextureEdgeClampSupported = rhs._isTextureEdgeClampSupported;
2327    _isTextureBorderClampSupported = rhs._isTextureBorderClampSupported;
[1646]2328    _isGenerateMipMapSupported = rhs._isGenerateMipMapSupported;
[1155]2329
2330    _maxTextureSize = rhs._maxTextureSize;
2331
2332    _glCompressedTexImage2D = rhs._glCompressedTexImage2D;
[2686]2333
2334    _isShadowSupported = rhs._isShadowSupported;
2335    _isShadowAmbientSupported = rhs._isShadowAmbientSupported;
[2791]2336
2337    _isClientStorageSupported = rhs._isClientStorageSupported;
[4156]2338
[4248]2339    _isNonPowerOfTwoTextureMipMappedSupported = rhs._isNonPowerOfTwoTextureMipMappedSupported;
2340    _isNonPowerOfTwoTextureNonMipMappedSupported = rhs._isNonPowerOfTwoTextureNonMipMappedSupported;
[7385]2341
2342    _isTextureIntegerEXTSupported = rhs._isTextureIntegerEXTSupported;
[10370]2343    _isTextureMaxLevelSupported = rhs._isTextureMaxLevelSupported;
[1155]2344}
2345
2346void Texture::Extensions::lowestCommonDenominator(const Extensions& rhs)
2347{
[1856]2348    if (!rhs._isMultiTexturingSupported) _isMultiTexturingSupported = false;
2349   
[1155]2350    if (!rhs._isTextureFilterAnisotropicSupported) _isTextureFilterAnisotropicSupported = false;
2351    if (!rhs._isTextureMirroredRepeatSupported) _isTextureMirroredRepeatSupported = false;
2352    if (!rhs._isTextureEdgeClampSupported) _isTextureEdgeClampSupported = false;
2353    if (!rhs._isTextureBorderClampSupported) _isTextureBorderClampSupported = false;
2354   
2355    if (!rhs._isTextureCompressionARBSupported) _isTextureCompressionARBSupported = false;
2356    if (!rhs._isTextureCompressionS3TCSupported) _isTextureCompressionS3TCSupported = false;
[1646]2357   
2358    if (!rhs._isGenerateMipMapSupported) _isGenerateMipMapSupported = false;
[1155]2359
2360    if (rhs._maxTextureSize<_maxTextureSize) _maxTextureSize = rhs._maxTextureSize;
[2959]2361    if (rhs._numTextureUnits<_numTextureUnits) _numTextureUnits = rhs._numTextureUnits;
[1155]2362
2363    if (!rhs._glCompressedTexImage2D) _glCompressedTexImage2D = 0;
[1856]2364    if (!rhs._glCompressedTexSubImage2D) _glCompressedTexSubImage2D = 0;
2365    if (!rhs._glGetCompressedTexImage) _glGetCompressedTexImage = 0;
[2686]2366
[2791]2367    if (!rhs._isShadowSupported) _isShadowSupported = false;
2368    if (!rhs._isShadowAmbientSupported) _isShadowAmbientSupported = false;
2369   
2370    if (!rhs._isClientStorageSupported) _isClientStorageSupported = false;
[4156]2371
[4248]2372    if (!rhs._isNonPowerOfTwoTextureMipMappedSupported) _isNonPowerOfTwoTextureMipMappedSupported = false;
2373    if (!rhs._isNonPowerOfTwoTextureNonMipMappedSupported) _isNonPowerOfTwoTextureNonMipMappedSupported = false;
[7385]2374
2375    if (!rhs._isTextureIntegerEXTSupported) _isTextureIntegerEXTSupported = false;
[10370]2376    if (!rhs._isTextureMaxLevelSupported) _isTextureMaxLevelSupported = false;
[1155]2377}
2378
[4102]2379void Texture::Extensions::setupGLExtensions(unsigned int contextID)
[1155]2380{
[4637]2381    const char* version = (const char*) glGetString( GL_VERSION );
2382    if (!version)
2383    {
2384        osg::notify(osg::FATAL)<<"Error: In Texture::Extensions::setupGLExtensions(..) OpenGL version test failed, requires valid graphics context."<<std::endl;
2385        return;
2386    }
2387   
[4248]2388    const char* renderer = (const char*) glGetString(GL_RENDERER);
2389    std::string rendererString(renderer ? renderer : "");
[2889]2390   
[9539]2391    _isMultiTexturingSupported = isGLExtensionOrVersionSupported( contextID,"GL_ARB_multitexture", 1.3f) ||
2392                                 isGLExtensionOrVersionSupported(contextID,"GL_EXT_multitexture", 1.3f);
[9355]2393                                 
[4102]2394    _isTextureFilterAnisotropicSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_filter_anisotropic");
[9355]2395   
[9539]2396    _isTextureCompressionARBSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_compression", 1.3f);
[9355]2397   
[4102]2398    _isTextureCompressionS3TCSupported = isGLExtensionSupported(contextID,"GL_EXT_texture_compression_s3tc");
[9355]2399   
[9539]2400    _isTextureMirroredRepeatSupported = isGLExtensionOrVersionSupported(contextID,"GL_IBM_texture_mirrored_repeat", 1.4f) ||
2401                                        isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_mirrored_repeat", 1.4f);
[9355]2402                                       
[9539]2403    _isTextureEdgeClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_EXT_texture_edge_clamp", 1.2f) ||
2404                                   isGLExtensionOrVersionSupported(contextID,"GL_SGIS_texture_edge_clamp", 1.2f);
[9355]2405                                   
[9539]2406    _isTextureBorderClampSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_border_clamp", 1.3f);
[9355]2407   
[9539]2408    _isGenerateMipMapSupported = isGLExtensionOrVersionSupported(contextID,"GL_SGIS_generate_mipmap", 1.4f);
[9355]2409                                 
[4102]2410    _isShadowSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow");
[9355]2411   
[4102]2412    _isShadowAmbientSupported = isGLExtensionSupported(contextID,"GL_ARB_shadow_ambient");
[1155]2413
[4102]2414    _isClientStorageSupported = isGLExtensionSupported(contextID,"GL_APPLE_client_storage");
[2791]2415
[9355]2416    _isNonPowerOfTwoTextureNonMipMappedSupported = isGLExtensionOrVersionSupported(contextID,"GL_ARB_texture_non_power_of_two", 2.0);
[4156]2417
[4248]2418    _isNonPowerOfTwoTextureMipMappedSupported = _isNonPowerOfTwoTextureNonMipMappedSupported;
2419   
[7385]2420    _isTextureIntegerEXTSupported = isGLExtensionSupported(contextID, "GL_EXT_texture_integer");
2421
[4257]2422    if (rendererString.find("Radeon")!=std::string::npos || rendererString.find("RADEON")!=std::string::npos)
[4248]2423    {
2424        _isNonPowerOfTwoTextureMipMappedSupported = false;
2425        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for ATI hardware."<<std::endl;
2426    }
2427
[4351]2428    if (rendererString.find("GeForce FX")!=std::string::npos)
2429    {
2430        _isNonPowerOfTwoTextureMipMappedSupported = false;
2431        osg::notify(osg::INFO)<<"Disabling _isNonPowerOfTwoTextureMipMappedSupported for GeForce FX hardware."<<std::endl;
2432    }
2433
[1155]2434    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&_maxTextureSize);
2435
2436    char *ptr;
2437    if( (ptr = getenv("OSG_MAX_TEXTURE_SIZE")) != 0)
[8]2438    {
[1155]2439        GLint osg_max_size = atoi(ptr);
2440
2441        if (osg_max_size<_maxTextureSize)
[1099]2442        {
[1155]2443
2444            _maxTextureSize = osg_max_size;
2445        }
[2959]2446    }
[1155]2447
[3364]2448    if( _isMultiTexturingSupported )
2449    {
2450       glGetIntegerv(GL_MAX_TEXTURE_UNITS,&_numTextureUnits);
2451    }
2452    else
2453    {
2454       _numTextureUnits = 1;
2455    }
[1155]2456
[7385]2457    setGLExtensionFuncPtr(_glCompressedTexImage2D,"glCompressedTexImage2D","glCompressedTexImage2DARB");
2458    setGLExtensionFuncPtr(_glCompressedTexSubImage2D,"glCompressedTexSubImage2D","glCompressedTexSubImage2DARB");
2459    setGLExtensionFuncPtr(_glGetCompressedTexImage,"glGetCompressedTexImage","glGetCompressedTexImageARB");;
2460
2461    setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIiv", "glTexParameterIivARB");
2462    setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuiv", "glTexParameterIuivARB");
2463   
2464    if (_glTexParameterIiv == NULL) setGLExtensionFuncPtr(_glTexParameterIiv, "glTexParameterIivEXT");
2465    if (_glTexParameterIuiv == NULL) setGLExtensionFuncPtr(_glTexParameterIuiv, "glTexParameterIuivEXT");
[10370]2466
2467    _isTextureMaxLevelSupported = ( getGLVersionNumber() >= 1.2f );
[8]2468}
[1047]2469
[7385]2470
2471void Texture::Extensions::glTexParameterIiv(GLenum target, GLenum pname, const GLint* data) const
2472{
2473    if (_glTexParameterIiv)
2474    {
2475        _glTexParameterIiv(target, pname, data);
2476    }
2477    else
2478    {
2479        notify(WARN)<<"Error: glTexParameterIiv not supported by OpenGL driver"<<std::endl;
2480    }
2481}
2482
2483void Texture::Extensions::glTexParameterIuiv(GLenum target, GLenum pname, const GLuint* data) const
2484{
2485    if (_glTexParameterIuiv)
2486    {
2487        _glTexParameterIuiv(target, pname, data);
2488    }
2489    else
2490    {
2491        notify(WARN)<<"Error: glTexParameterIuiv not supported by OpenGL driver"<<std::endl;
2492    }
2493}
2494
[1155]2495void Texture::Extensions::glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data) const
[1099]2496{
[1155]2497    if (_glCompressedTexImage2D)
2498    {
[7379]2499        _glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
[1155]2500    }
2501    else
2502    {
2503        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
2504    }
2505   
[1099]2506}
[1773]2507
[2022]2508void Texture::Extensions::glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) const
[1773]2509{
[3443]2510    if (_glCompressedTexSubImage2D)
[1773]2511    {
[7379]2512        _glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
[1773]2513    }
2514    else
2515    {
2516        notify(WARN)<<"Error: glCompressedTexImage2D not supported by OpenGL driver"<<std::endl;
2517    }
2518   
2519}
[1794]2520void Texture::Extensions::glGetCompressedTexImage(GLenum target, GLint level, GLvoid *data) const
2521{
2522    if (_glGetCompressedTexImage)
2523    {
[7379]2524        _glGetCompressedTexImage(target, level, data);
[1794]2525    }
2526    else
2527    {
2528        notify(WARN)<<"Error: glGetCompressedTexImage not supported by OpenGL driver"<<std::endl;
2529    }
2530}
[4554]2531
[10589]2532}
Note: See TracBrowser for help on using the browser.