Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreResourceBackgroundQueue.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 15.1 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreResourceBackgroundQueue.h"
31#include "OgreLogManager.h"
32#include "OgreException.h"
33#include "OgreResourceGroupManager.h"
34#include "OgreResourceManager.h"
35#include "OgreRoot.h"
36#include "OgreRenderSystem.h"
37
38namespace Ogre {
39
40        //------------------------------------------------------------------------
41    //-----------------------------------------------------------------------
42    template<> ResourceBackgroundQueue* Singleton<ResourceBackgroundQueue>::ms_Singleton = 0;
43    ResourceBackgroundQueue* ResourceBackgroundQueue::getSingletonPtr(void)
44    {
45        return ms_Singleton;
46    }
47    ResourceBackgroundQueue& ResourceBackgroundQueue::getSingleton(void)
48    { 
49        assert( ms_Singleton );  return ( *ms_Singleton ); 
50    }
51    //-----------------------------------------------------------------------   
52        //------------------------------------------------------------------------
53        ResourceBackgroundQueue::ResourceBackgroundQueue()
54                :mNextTicketID(0), mStartThread(true), mThread(0)
55#if OGRE_THREAD_SUPPORT
56        , mShuttingDown(false)
57#endif
58        {
59        }
60        //------------------------------------------------------------------------
61        ResourceBackgroundQueue::~ResourceBackgroundQueue()
62        {
63                shutdown();
64        }
65        //------------------------------------------------------------------------
66        void ResourceBackgroundQueue::initialise(void)
67        {
68#if OGRE_THREAD_SUPPORT
69                if (mStartThread)
70                {
71                        {
72                                OGRE_LOCK_AUTO_MUTEX
73                                mShuttingDown = false;
74                        }
75
76                        RenderSystem* rs = Root::getSingleton().getRenderSystem();
77
78                        LogManager::getSingleton().logMessage(
79                                "ResourceBackgroundQueue - threading enabled, starting own thread");
80                        {
81                                OGRE_LOCK_MUTEX_NAMED(initMutex, initLock)
82
83                                // Call thread creation pre-hook
84                                rs->preExtraThreadsStarted();
85
86                                mThread = new boost::thread(
87                                        boost::function0<void>(&ResourceBackgroundQueue::threadFunc));
88                                // Wait for init to finish before allowing main thread to continue
89                                // this releases the initMutex until notified
90                                OGRE_THREAD_WAIT(initSync, initLock)
91
92                                // Call thread creation post-hook
93                                rs->postExtraThreadsStarted();
94                        }
95
96                }
97                else
98                {
99                        LogManager::getSingleton().logMessage(
100                                "ResourceBackgroundQueue - threading enabled, user thread");
101                }
102#else
103                LogManager::getSingleton().logMessage(
104                        "ResourceBackgroundQueue - threading disabled");       
105#endif
106        }
107        //------------------------------------------------------------------------
108        void ResourceBackgroundQueue::shutdown(void)
109        {
110#if OGRE_THREAD_SUPPORT
111                if (mThread)
112                {
113                        // Put a shutdown request on the queue
114                        Request req;
115                        req.type = RT_SHUTDOWN;
116                        addRequest(req);
117                        // Wait for thread to finish
118                        mThread->join();
119                        delete mThread;
120                        mThread = 0;
121                        mRequestQueue.clear();
122                        mRequestTicketMap.clear();
123                }
124#endif
125        }
126        //------------------------------------------------------------------------
127        BackgroundProcessTicket ResourceBackgroundQueue::initialiseResourceGroup(
128                const String& name, ResourceBackgroundQueue::Listener* listener)
129        {
130#if OGRE_THREAD_SUPPORT
131                if (!mThread && mStartThread)
132                {
133                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
134                                "Thread not initialised",
135                                "ResourceBackgroundQueue::initialiseResourceGroup");
136                }
137                // queue a request
138                Request req;
139                req.type = RT_INITIALISE_GROUP;
140                req.groupName = name;
141                req.listener = listener;
142                return addRequest(req);
143#else
144                // synchronous
145                ResourceGroupManager::getSingleton().initialiseResourceGroup(name);
146                return 0; 
147#endif
148        }
149        //------------------------------------------------------------------------
150        BackgroundProcessTicket
151        ResourceBackgroundQueue::initialiseAllResourceGroups( 
152                ResourceBackgroundQueue::Listener* listener)
153        {
154#if OGRE_THREAD_SUPPORT
155                if (!mThread && mStartThread)
156                {
157                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
158                                "Thread not initialised",
159                                "ResourceBackgroundQueue::initialiseAllResourceGroups");
160                }
161                // queue a request
162                Request req;
163                req.type = RT_INITIALISE_ALL_GROUPS;
164                req.listener = listener;
165                return addRequest(req);
166#else
167                // synchronous
168                ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
169                return 0; 
170#endif
171        }
172        //------------------------------------------------------------------------
173        BackgroundProcessTicket ResourceBackgroundQueue::loadResourceGroup(
174                const String& name, ResourceBackgroundQueue::Listener* listener)
175        {
176#if OGRE_THREAD_SUPPORT
177                if (!mThread && mStartThread)
178                {
179                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
180                                "Thread not initialised",
181                                "ResourceBackgroundQueue::loadResourceGroup");
182                }
183                // queue a request
184                Request req;
185                req.type = RT_LOAD_GROUP;
186                req.groupName = name;
187                req.listener = listener;
188                return addRequest(req);
189#else
190                // synchronous
191                ResourceGroupManager::getSingleton().loadResourceGroup(name);
192                return 0; 
193#endif
194        }
195        //------------------------------------------------------------------------
196        BackgroundProcessTicket ResourceBackgroundQueue::load(
197                const String& resType, const String& name, 
198                const String& group, bool isManual, 
199                ManualResourceLoader* loader, 
200                const NameValuePairList* loadParams, 
201                ResourceBackgroundQueue::Listener* listener)
202        {
203#if OGRE_THREAD_SUPPORT
204                if (!mThread && mStartThread)
205                {
206                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
207                                "Thread not initialised",
208                                "ResourceBackgroundQueue::load");
209                }
210                // queue a request
211                Request req;
212                req.type = RT_LOAD_RESOURCE;
213                req.resourceType = resType;
214                req.resourceName = name;
215                req.groupName = group;
216                req.isManual = isManual;
217                req.loader = loader;
218                req.loadParams = loadParams;
219                req.listener = listener;
220                return addRequest(req);
221#else
222                // synchronous
223                ResourceManager* rm = 
224                        ResourceGroupManager::getSingleton()._getResourceManager(resType);
225                rm->load(name, group, isManual, loader, loadParams);
226                return 0; 
227#endif
228        }
229        //---------------------------------------------------------------------
230        BackgroundProcessTicket ResourceBackgroundQueue::unload(
231                const String& resType, const String& name, Listener* listener)
232        {
233#if OGRE_THREAD_SUPPORT
234                if (!mThread && mStartThread)
235                {
236                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
237                                "Thread not initialised",
238                                "ResourceBackgroundQueue::unload");
239                }
240                // queue a request
241                Request req;
242                req.type = RT_UNLOAD_RESOURCE;
243                req.resourceType = resType;
244                req.resourceName = name;
245                req.listener = listener;
246                return addRequest(req);
247#else
248                // synchronous
249                ResourceManager* rm = 
250                        ResourceGroupManager::getSingleton()._getResourceManager(resType);
251                rm->unload(name);
252                return 0; 
253#endif
254
255        }
256        //---------------------------------------------------------------------
257        BackgroundProcessTicket ResourceBackgroundQueue::unload(
258                const String& resType, ResourceHandle handle, Listener* listener)
259        {
260#if OGRE_THREAD_SUPPORT
261                if (!mThread && mStartThread)
262                {
263                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
264                                "Thread not initialised",
265                                "ResourceBackgroundQueue::unload");
266                }
267                // queue a request
268                Request req;
269                req.type = RT_UNLOAD_RESOURCE;
270                req.resourceType = resType;
271                req.resourceHandle = handle;
272                req.listener = listener;
273                return addRequest(req);
274#else
275                // synchronous
276                ResourceManager* rm = 
277                        ResourceGroupManager::getSingleton()._getResourceManager(resType);
278                rm->unload(handle);
279                return 0; 
280#endif
281
282        }
283        //---------------------------------------------------------------------
284        BackgroundProcessTicket ResourceBackgroundQueue::unloadResourceGroup(
285                const String& name, Listener* listener)
286        {
287#if OGRE_THREAD_SUPPORT
288                if (!mThread && mStartThread)
289                {
290                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
291                                "Thread not initialised",
292                                "ResourceBackgroundQueue::unloadResourceGroup");
293                }
294                // queue a request
295                Request req;
296                req.type = RT_UNLOAD_GROUP;
297                req.groupName = name;
298                req.listener = listener;
299                return addRequest(req);
300#else
301                // synchronous
302                ResourceGroupManager::getSingleton().unloadResourceGroup(name);
303                return 0; 
304#endif
305
306        }
307        //------------------------------------------------------------------------
308        bool ResourceBackgroundQueue::isProcessComplete(
309                        BackgroundProcessTicket ticket)
310        {
311                // Lock
312                OGRE_LOCK_AUTO_MUTEX
313
314                return mRequestTicketMap.find(ticket) == mRequestTicketMap.end();
315        }
316        //------------------------------------------------------------------------
317#if OGRE_THREAD_SUPPORT
318        BackgroundProcessTicket ResourceBackgroundQueue::addRequest(Request& req)
319        {
320                // Lock
321                OGRE_LOCK_AUTO_MUTEX
322
323                req.ticketID = ++mNextTicketID;
324                mRequestQueue.push_back(req);
325                Request* requestInList = &(mRequestQueue.back());
326                mRequestTicketMap[req.ticketID] = requestInList;
327
328                // Notify to wake up loading thread
329                OGRE_THREAD_NOTIFY_ONE(mCondition)
330
331                return req.ticketID;
332        }
333        //------------------------------------------------------------------------
334        void ResourceBackgroundQueue::threadFunc(void)
335        {
336                // Background thread implementation
337                // Static (since no params allowed), so get instance
338                ResourceBackgroundQueue& queueInstance = 
339                        ResourceBackgroundQueue::getSingleton();
340
341                LogManager::getSingleton().logMessage("ResourceBackgroundQueue - thread starting.");
342
343                // Initialise the thread
344                queueInstance._initThread();
345
346                // Spin forever until we're told to shut down
347                while (!queueInstance.mShuttingDown)
348                {
349                        // Our thread will just wait when there is nothing on the queue
350                        // _doNextQueuedBackgroundProcess won't do this since the thread
351                        // may be shared
352
353            // Manual scope block just to define scope of lock
354            {
355                // Lock; note that 'mCondition.wait()' will free the lock
356                boost::recursive_mutex::scoped_lock queueLock(
357                    queueInstance.OGRE_AUTO_MUTEX_NAME);
358                if (queueInstance.mRequestQueue.empty())
359                {
360                    // frees lock and suspends the thread
361                    queueInstance.mCondition.wait(queueLock);
362                }
363                // When we get back here, it's because we've been notified
364                // and thus the thread as been woken up. Lock has also been
365                // re-acquired.
366            } // release lock so queueing can be done while we process one request
367
368                        queueInstance._doNextQueuedBackgroundProcess();
369
370
371                }
372
373                LogManager::getSingleton().logMessage("ResourceBackgroundQueue - thread stopped.");
374
375       
376               
377        }
378#endif
379        //-----------------------------------------------------------------------
380        void ResourceBackgroundQueue::_initThread()
381        {
382                // Register the calling thread with RenderSystem
383                // Note how we assume only one thread is processing the queue
384                Root::getSingleton().getRenderSystem()->registerThread();
385                {
386                        // notify waiting thread(s)
387                        OGRE_LOCK_MUTEX(initMutex)
388                        OGRE_THREAD_NOTIFY_ALL(initSync)
389                }
390
391        }
392        //-----------------------------------------------------------------------
393        bool ResourceBackgroundQueue::_doNextQueuedBackgroundProcess()
394        {
395
396                Request* req;
397                // Manual scope block just to define scope of lock
398                {
399                        OGRE_LOCK_AUTO_MUTEX
400                        // return false if nothing in the queue
401                        if (mRequestQueue.empty())
402                                return false;
403
404                        // Process one request
405                        req = &(mRequestQueue.front());
406                } // release lock so queueing can be done while we process one request
407                // use of std::list means that references guarateed to remain valid
408                // we only allow one background thread
409
410                ResourceManager* rm = 0;
411                switch (req->type)
412                {
413                case RT_INITIALISE_GROUP:
414                        ResourceGroupManager::getSingleton().initialiseResourceGroup(
415                                req->groupName);
416                        break;
417                case RT_INITIALISE_ALL_GROUPS:
418                        ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
419                        break;
420                case RT_LOAD_GROUP:
421                        ResourceGroupManager::getSingleton().loadResourceGroup(
422                                req->groupName);
423                        break;
424                case RT_UNLOAD_GROUP:
425                        ResourceGroupManager::getSingleton().unloadResourceGroup(
426                                req->groupName);
427                        break;
428                case RT_LOAD_RESOURCE:
429                        rm = ResourceGroupManager::getSingleton()._getResourceManager(
430                                req->resourceType);
431                        rm->load(req->resourceName, req->groupName, req->isManual, 
432                                req->loader, req->loadParams);
433                        break;
434                case RT_UNLOAD_RESOURCE:
435                        rm = ResourceGroupManager::getSingleton()._getResourceManager(
436                                req->resourceType);
437                        if (req->resourceName.empty())
438                                rm->unload(req->resourceHandle);
439                        else
440                                rm->unload(req->resourceName);
441                        break;
442                case RT_SHUTDOWN:
443                        // That's all folks
444#if OGRE_THREAD_SUPPORT
445                        mShuttingDown = true;
446                        Root::getSingleton().getRenderSystem()->unregisterThread();
447#endif
448                        break;
449                };
450
451                // Queue notification (don't do shutdown since not needed & listeners
452                // might be being destroyed too
453                if (req->listener && req->type != RT_SHUTDOWN)
454                {
455                        // Fire in-thread notification first
456                        req->listener->operationCompletedInThread(req->ticketID);
457                        // Then queue main thread notification
458                        queueFireBackgroundOperationComplete(req->listener, req->ticketID);
459                }
460
461
462                {
463                        // re-lock to consume completed request
464                        OGRE_LOCK_AUTO_MUTEX
465
466                        // Consume the ticket
467                        mRequestTicketMap.erase(req->ticketID);
468                        mRequestQueue.pop_front();
469                }
470
471                return true;
472
473        }
474        //-----------------------------------------------------------------------
475        void ResourceBackgroundQueue::_queueFireBackgroundLoadingComplete(
476                Resource::Listener* listener, Resource* res)
477        {
478                OGRE_LOCK_MUTEX(mNotificationQueueMutex);
479                mNotificationQueue.push_back(QueuedNotification(listener, res));
480
481        }
482        //-----------------------------------------------------------------------
483        void ResourceBackgroundQueue::queueFireBackgroundOperationComplete(
484                ResourceBackgroundQueue::Listener* listener, BackgroundProcessTicket ticket)
485        {
486                OGRE_LOCK_MUTEX(mNotificationQueueMutex);
487                mNotificationQueue.push_back(QueuedNotification(listener, ticket));
488        }
489        //-----------------------------------------------------------------------
490        void ResourceBackgroundQueue::_fireBackgroundLoadingComplete()
491        {
492                OGRE_LOCK_MUTEX(mNotificationQueueMutex);
493                for (NotificationQueue::iterator i = mNotificationQueue.begin();
494                        i != mNotificationQueue.end(); ++i)
495                {
496                        if (i->resource)
497                                i->resourceListener->backgroundLoadingComplete(i->resource);
498                        else
499                                i->opListener->operationCompleted(i->ticket);
500                }
501                mNotificationQueue.clear();
502
503        }
504        //------------------------------------------------------------------------
505
506}
507
508
509
Note: See TracBrowser for help on using the repository browser.