root/OpenSceneGraph/trunk/src/osgDB/ImagePager.cpp @ 13191

Revision 13191, 11.8 kB (checked in by robert, 3 hours ago)

From Farshid Lashkari, "I've attached a small fix to the Collada loader which prevents a null pointer access in some cases."

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgDB/ImagePager>
15#include <osgDB/ReadFile>
16
17#include <osg/Notify>
18#include <osg/ImageSequence>
19
20using namespace osgDB;
21
22
23/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
24//
25//  SortFileRequestFunctor
26//
27struct ImagePager::SortFileRequestFunctor
28{
29    bool operator() (const osg::ref_ptr<ImagePager::ImageRequest>& lhs,const osg::ref_ptr<ImagePager::ImageRequest>& rhs) const
30    {
31        return (lhs->_timeToMergeBy < rhs->_timeToMergeBy);
32    }
33};
34
35
36/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
37//
38//  RequestQueue
39//
40void ImagePager::RequestQueue::sort()
41{
42    std::sort(_requestList.begin(),_requestList.end(),SortFileRequestFunctor());
43}
44
45unsigned int ImagePager::RequestQueue::size() const
46{
47    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
48    return _requestList.size();
49}
50
51
52
53/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
54//
55//  ReadQueue
56//
57ImagePager::ReadQueue::ReadQueue(ImagePager* pager, const std::string& name):
58    _pager(pager),
59    _name(name)
60{
61    _block = new osg::RefBlock;
62}
63
64void ImagePager::ReadQueue::clear()
65{
66    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
67
68    for(RequestList::iterator citr = _requestList.begin();
69        citr != _requestList.end();
70        ++citr)
71    {
72        (*citr)->_attachmentPoint = 0;
73        (*citr)->_requestQueue = 0;
74    }
75
76    _requestList.clear();
77
78    updateBlock();
79}
80
81void ImagePager::ReadQueue::add(ImagePager::ImageRequest* databaseRequest)
82{
83    // tempo hack to avoid the ImagePager accumulating requests when it can keep up,
84    // note this will mean that only one ImageSequence can be properly managed at one time,
85    // this hack will be removed once a better system for managing expiry of requests is introduced.
86    // clear();
87
88    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
89   
90    _requestList.push_back(databaseRequest);
91    databaseRequest->_requestQueue = this;
92
93    OSG_INFO<<"ImagePager::ReadQueue::add("<<databaseRequest->_fileName<<"), size()="<<_requestList.size()<<std::endl;
94
95    updateBlock();
96}
97
98void ImagePager::ReadQueue::takeFirst(osg::ref_ptr<ImageRequest>& databaseRequest)
99{
100    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_requestMutex);
101
102    if (!_requestList.empty())
103    {
104        sort();
105
106        OSG_INFO<<"ImagePager::ReadQueue::takeFirst(..), size()="<<_requestList.size()<<std::endl;
107
108        databaseRequest = _requestList.front();
109        databaseRequest->_requestQueue = 0;
110        _requestList.erase(_requestList.begin());
111
112        updateBlock();
113    }
114}
115
116//////////////////////////////////////////////////////////////////////////////////////
117//
118// ImageThread
119//
120ImagePager::ImageThread::ImageThread(ImagePager* pager, Mode mode, const std::string& name):
121    _done(false),
122    _mode(mode),
123    _pager(pager),
124    _name(name)
125{
126}
127
128ImagePager::ImageThread::ImageThread(const ImageThread& dt, ImagePager* pager):
129    _done(false),
130    _mode(dt._mode),
131    _pager(pager),
132    _name(dt._name)
133{
134}
135
136ImagePager::ImageThread::~ImageThread()
137{
138}
139
140int ImagePager::ImageThread::cancel()
141{
142    int result = 0;
143
144    if( isRunning() )
145    {
146
147        _done = true;
148
149        switch(_mode)
150        {
151            case(HANDLE_ALL_REQUESTS):
152                _pager->_readQueue->release();
153                break;
154            case(HANDLE_NON_HTTP):
155                _pager->_readQueue->release();
156                break;
157            case(HANDLE_ONLY_HTTP):
158                _pager->_readQueue->release();
159                break;
160        }
161
162        // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
163        // _databasePagerThreadBlock->release();
164
165        // then wait for the the thread to stop running.
166        while(isRunning())
167        {
168            // commenting out debug info as it was cashing crash on exit, presumable
169            // due to osg::notify or std::cout destructing earlier than this destructor.
170            // OSG_DEBUG<<"Waiting for DatabasePager to cancel"<<std::endl;
171            OpenThreads::Thread::YieldCurrentThread();
172        }
173
174        // _startThreadCalled = false;
175    }
176    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
177    return result;
178}
179
180void ImagePager::ImageThread::run()
181{
182    OSG_INFO<<"ImagePager::ImageThread::run() "<<this<<std::endl;
183    bool firstTime = true;
184
185    osg::ref_ptr<ImagePager::ReadQueue> read_queue;
186
187    switch(_mode)
188    {
189        case(HANDLE_ALL_REQUESTS):
190            read_queue = _pager->_readQueue;
191            break;
192        case(HANDLE_NON_HTTP):
193            read_queue = _pager->_readQueue;
194            break;
195        case(HANDLE_ONLY_HTTP):
196            read_queue = _pager->_readQueue;
197            break;
198    }
199
200    do
201    {
202        read_queue->block();
203
204        osg::ref_ptr<ImageRequest> imageRequest;
205        read_queue->takeFirst(imageRequest);
206
207        if (imageRequest.valid())
208        {
209            // OSG_NOTICE<<"doing readImageFile("<<imageRequest->_fileName<<") index to assign = "<<imageRequest->_attachmentIndex<<std::endl;
210            osg::ref_ptr<osg::Image> image = osgDB::readImageFile(imageRequest->_fileName, imageRequest->_readOptions.get());
211            if (image.valid())
212            {
213                // OSG_NOTICE<<"   successful readImageFile("<<imageRequest->_fileName<<") index to assign = "<<imageRequest->_attachmentIndex<<std::endl;
214               
215                osg::ImageSequence* is = dynamic_cast<osg::ImageSequence*>(imageRequest->_attachmentPoint.get());
216                if (is)
217                {
218                    if (imageRequest->_attachmentIndex >= 0)
219                    {
220                        is->setImage(imageRequest->_attachmentIndex, image.get());
221                    }
222                    else
223                    {
224                        is->addImage(image.get());
225                    }
226                }
227                else
228                {
229                    imageRequest->_loadedImage = image;
230
231                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_completedQueue->_requestMutex);
232                    _pager->_completedQueue->_requestList.push_back(imageRequest);
233                }
234            }
235
236        }
237        else
238        {
239            OpenThreads::Thread::YieldCurrentThread();
240        }
241
242
243        // go to sleep till our the next time our thread gets scheduled.
244
245        if (firstTime)
246        {
247            // do a yield to get round a peculiar thread hang when testCancel() is called
248            // in certain circumstances - of which there is no particular pattern.
249            YieldCurrentThread();
250            firstTime = false;
251        }
252
253    } while (!testCancel() && !_done);
254
255    OSG_INFO<<"ImagePager::ImageThread::done()"<<std::endl;
256
257}
258
259//////////////////////////////////////////////////////////////////////////////////////
260//
261// ImagePager
262//
263ImagePager::ImagePager():
264    _done(false)
265{
266    _startThreadCalled = false;
267    _databasePagerThreadPaused = false;
268
269    _readQueue = new ReadQueue(this,"Image Queue");
270    _completedQueue = new RequestQueue;
271    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 1"));
272#if 1
273    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 2"));
274    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 3"));
275    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 4"));
276    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 5"));
277    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 6"));
278#endif
279    // 1 second
280    _preLoadTime = 1.0;
281}
282
283ImagePager::~ImagePager()
284{
285    cancel();
286}
287
288int ImagePager::cancel()
289{
290    int result = 0;
291
292    for(ImageThreads::iterator itr = _imageThreads.begin();
293        itr != _imageThreads.end();
294        ++itr)
295    {
296        (*itr)->setDone(true);
297    }
298
299    // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
300    _readQueue->release();
301
302    for(ImageThreads::iterator itr = _imageThreads.begin();
303        itr != _imageThreads.end();
304        ++itr)
305    {
306        (*itr)->cancel();
307    }
308
309    _done = true;
310    _startThreadCalled = false;
311
312    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
313    return result;
314}
315
316osg::Image* ImagePager::readImageFile(const std::string& fileName)
317{
318    return osgDB::readImageFile(fileName);
319}
320
321void ImagePager::requestImageFile(const std::string& fileName, osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp* framestamp, osg::ref_ptr<osg::Referenced>& imageRequest, const osg::Referenced* options)
322{
323
324    osgDB::Options* readOptions = dynamic_cast<osgDB::Options*>(const_cast<osg::Referenced*>(options));
325    if (!readOptions)
326    {
327       readOptions = Registry::instance()->getOptions();
328    }
329
330    bool alreadyAssigned = dynamic_cast<ImageRequest*>(imageRequest.get()) && (imageRequest->referenceCount()>1);
331    if (alreadyAssigned)
332    {
333        // OSG_NOTICE<<"ImagePager::requestImageFile("<<fileName<<") alreadyAssigned"<<std::endl;
334        return;
335    }
336
337    osg::ref_ptr<ImageRequest> request = new ImageRequest;
338    request->_timeToMergeBy = timeToMergeBy;
339    request->_fileName = fileName;
340    request->_attachmentPoint = attachmentPoint;
341    request->_attachmentIndex = attachmentIndex;
342    request->_requestQueue = _readQueue.get();
343    request->_readOptions = readOptions;
344
345    imageRequest = request;
346
347    // OSG_NOTICE<<"ImagePager::requestImageFile("<<fileName<<") new request."<<std::endl;
348
349    _readQueue->add(request.get());
350
351    if (!_startThreadCalled)
352    {
353        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
354
355        if (!_startThreadCalled)
356        {
357            _startThreadCalled = true;
358            _done = false;
359
360            for(ImageThreads::iterator itr = _imageThreads.begin();
361                itr != _imageThreads.end();
362                ++itr)
363            {
364                (*itr)->startThread();
365            }
366
367        }
368    }
369}
370
371bool ImagePager::requiresUpdateSceneGraph() const
372{
373    //OSG_NOTICE<<"ImagePager::requiresUpdateSceneGraph()"<<std::endl;
374    return !(_completedQueue->_requestList.empty());
375}
376
377void ImagePager::updateSceneGraph(const osg::FrameStamp&)
378{
379    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_completedQueue->_requestMutex);
380
381    for(RequestQueue::RequestList::iterator itr = _completedQueue->_requestList.begin();
382        itr != _completedQueue->_requestList.end();
383        ++itr)
384    {
385        ImageRequest* imageRequest = itr->get();
386        osg::Texture* texture = dynamic_cast<osg::Texture*>(imageRequest->_attachmentPoint.get());
387        if (texture)
388        {
389            int attachmentIndex = imageRequest->_attachmentIndex > 0 ? imageRequest->_attachmentIndex : 0;
390            texture->setImage(attachmentIndex, imageRequest->_loadedImage.get());
391        }
392        else
393        {
394            OSG_NOTICE<<"ImagePager::updateSceneGraph() : error, image request attachment type not handled yet."<<std::endl;
395        }
396    }
397
398    _completedQueue->_requestList.clear();
399}
Note: See TracBrowser for help on using the browser.