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

Revision 13159, 10.8 kB (checked in by robert, 9 days ago)

Release OpenSceneGraph-3.2.1

  • 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(..), 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::ref_ptr<osg::Image> image = osgDB::readImageFile(imageRequest->_fileName);
210            if (image.valid())
211            {
212                osg::ImageSequence* is = dynamic_cast<osg::ImageSequence*>(imageRequest->_attachmentPoint.get());
213                if (is)
214                {
215                    if (imageRequest->_attachmentIndex >= 0)
216                    {
217                        is->setImage(imageRequest->_attachmentIndex, image.get());
218                    }
219                    else
220                    {
221                        is->addImage(image.get());
222                    }
223                }
224                else
225                {
226                    imageRequest->_loadedImage = image;
227
228                    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_pager->_completedQueue->_requestMutex);
229                    _pager->_completedQueue->_requestList.push_back(imageRequest);
230                }
231            }
232
233        }
234        else
235        {
236            OpenThreads::Thread::YieldCurrentThread();
237        }
238
239
240        // go to sleep till our the next time our thread gets scheduled.
241
242        if (firstTime)
243        {
244            // do a yield to get round a peculiar thread hang when testCancel() is called
245            // in certain circumstances - of which there is no particular pattern.
246            YieldCurrentThread();
247            firstTime = false;
248        }
249
250    } while (!testCancel() && !_done);
251
252    OSG_INFO<<"ImagePager::ImageThread::done()"<<std::endl;
253
254}
255
256//////////////////////////////////////////////////////////////////////////////////////
257//
258// ImagePager
259//
260ImagePager::ImagePager():
261    _done(false)
262{
263    _startThreadCalled = false;
264    _databasePagerThreadPaused = false;
265
266    _readQueue = new ReadQueue(this,"Image Queue");
267    _completedQueue = new RequestQueue;
268    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 1"));
269    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 2"));
270    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 3"));
271    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 4"));
272    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 5"));
273    _imageThreads.push_back(new ImageThread(this, ImageThread::HANDLE_ALL_REQUESTS, "Image Thread 6"));
274
275    // 1 second
276    _preLoadTime = 1.0;
277}
278
279ImagePager::~ImagePager()
280{
281    cancel();
282}
283
284int ImagePager::cancel()
285{
286    int result = 0;
287
288    for(ImageThreads::iterator itr = _imageThreads.begin();
289        itr != _imageThreads.end();
290        ++itr)
291    {
292        (*itr)->setDone(true);
293    }
294
295    // release the frameBlock and _databasePagerThreadBlock in case its holding up thread cancellation.
296    _readQueue->release();
297
298    for(ImageThreads::iterator itr = _imageThreads.begin();
299        itr != _imageThreads.end();
300        ++itr)
301    {
302        (*itr)->cancel();
303    }
304
305    _done = true;
306    _startThreadCalled = false;
307
308    //std::cout<<"DatabasePager::~DatabasePager() stopped running"<<std::endl;
309    return result;
310}
311
312osg::Image* ImagePager::readImageFile(const std::string& fileName)
313{
314    return osgDB::readImageFile(fileName);
315}
316
317void ImagePager::requestImageFile(const std::string& fileName,osg::Object* attachmentPoint, int attachmentIndex, double timeToMergeBy, const osg::FrameStamp*)
318{
319    OSG_INFO<<"ImagePager::requestNodeFile("<<fileName<<")"<<std::endl;
320
321    osg::ref_ptr<ImageRequest> request = new ImageRequest;
322    request->_timeToMergeBy = timeToMergeBy;
323    request->_fileName = fileName;
324    request->_attachmentPoint = attachmentPoint;
325    request->_attachmentIndex = attachmentIndex;
326    request->_requestQueue = _readQueue.get();
327
328    _readQueue->add(request.get());
329
330    if (!_startThreadCalled)
331    {
332        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_run_mutex);
333
334        if (!_startThreadCalled)
335        {
336            _startThreadCalled = true;
337            _done = false;
338
339            for(ImageThreads::iterator itr = _imageThreads.begin();
340                itr != _imageThreads.end();
341                ++itr)
342            {
343                (*itr)->startThread();
344            }
345
346        }
347    }
348}
349
350bool ImagePager::requiresUpdateSceneGraph() const
351{
352    //OSG_NOTICE<<"ImagePager::requiresUpdateSceneGraph()"<<std::endl;
353    return !(_completedQueue->_requestList.empty());
354}
355
356void ImagePager::updateSceneGraph(const osg::FrameStamp&)
357{
358    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_completedQueue->_requestMutex);
359
360    for(RequestQueue::RequestList::iterator itr = _completedQueue->_requestList.begin();
361        itr != _completedQueue->_requestList.end();
362        ++itr)
363    {
364        ImageRequest* imageRequest = itr->get();
365        osg::Texture* texture = dynamic_cast<osg::Texture*>(imageRequest->_attachmentPoint.get());
366        if (texture)
367        {
368            int attachmentIndex = imageRequest->_attachmentIndex > 0 ? imageRequest->_attachmentIndex : 0;
369            texture->setImage(attachmentIndex, imageRequest->_loadedImage.get());
370        }
371        else
372        {
373            OSG_NOTICE<<"ImagePager::updateSceneGraph() : error, image request attachment type not handled yet."<<std::endl;
374        }
375    }
376
377    _completedQueue->_requestList.clear();
378}
Note: See TracBrowser for help on using the browser.