4
4
(Object-oriented Graphics Rendering Engine)
5
5
For the latest info, see http://www.ogre3d.org/
7
Copyright (c) 2000-2006 Torus Knot Software Ltd
8
Also see acknowledgements in Readme.html
10
This program is free software; you can redistribute it and/or modify it under
11
the terms of the GNU Lesser General Public License as published by the Free Software
12
Foundation; either version 2 of the License, or (at your option) any later
15
This program is distributed in the hope that it will be useful, but WITHOUT
16
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19
You should have received a copy of the GNU Lesser General Public License along with
20
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22
http://www.gnu.org/copyleft/lesser.txt.
24
You may alternatively use this source under the terms of a specific version of
25
the OGRE Unrestricted License provided you have obtained such a license from
26
Torus Knot Software Ltd.
7
Copyright (c) 2000-2009 Torus Knot Software Ltd
9
Permission is hereby granted, free of charge, to any person obtaining a copy
10
of this software and associated documentation files (the "Software"), to deal
11
in the Software without restriction, including without limitation the rights
12
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
copies of the Software, and to permit persons to whom the Software is
14
furnished to do so, subject to the following conditions:
16
The above copyright notice and this permission notice shall be included in
17
all copies or substantial portions of the Software.
19
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
26
-----------------------------------------------------------------------------
29
28
#include "OgreStableHeaders.h"
65
//------------------------------------------------------------------------
66
void ResourceBackgroundQueue::initialise(void)
65
//---------------------------------------------------------------------
66
void ResourceBackgroundQueue::initialise()
68
#if OGRE_THREAD_SUPPORT
73
mShuttingDown = false;
76
#if OGRE_THREAD_SUPPORT == 1
77
RenderSystem* rs = Root::getSingleton().getRenderSystem();
80
LogManager::getSingleton().logMessage(
81
"ResourceBackgroundQueue - threading enabled, starting own thread");
83
OGRE_LOCK_MUTEX_NAMED(initMutex, initLock)
85
#if OGRE_THREAD_SUPPORT == 1
86
// Call thread creation pre-hook
87
rs->preExtraThreadsStarted();
90
mThread = OGRE_NEW_T(boost::thread, MEMCATEGORY_RESOURCE)(
91
boost::function0<void>(&ResourceBackgroundQueue::threadFunc));
92
// Wait for init to finish before allowing main thread to continue
93
// this releases the initMutex until notified
94
OGRE_THREAD_WAIT(initSync, initLock)
96
#if OGRE_THREAD_SUPPORT == 1
97
// Call thread creation post-hook
98
rs->postExtraThreadsStarted();
105
LogManager::getSingleton().logMessage(
106
"ResourceBackgroundQueue - threading enabled, user thread");
109
LogManager::getSingleton().logMessage(
110
"ResourceBackgroundQueue - threading disabled");
68
Root::getSingleton().getWorkQueue()->addResponseHandler(RESOURCE_CHANNEL, this);
69
Root::getSingleton().getWorkQueue()->addRequestHandler(RESOURCE_CHANNEL, this);
113
//------------------------------------------------------------------------
114
void ResourceBackgroundQueue::shutdown(void)
71
//---------------------------------------------------------------------
72
void ResourceBackgroundQueue::shutdown()
116
#if OGRE_THREAD_SUPPORT
119
// Put a shutdown request on the queue
121
req.type = RT_SHUTDOWN;
123
// Wait for thread to finish
125
OGRE_DELETE_T(mThread, thread, MEMCATEGORY_RESOURCE);
127
mRequestQueue.clear();
128
mRequestTicketMap.clear();
74
Root::getSingleton().getWorkQueue()->removeRequestHandler(RESOURCE_CHANNEL, this);
75
Root::getSingleton().getWorkQueue()->removeResponseHandler(RESOURCE_CHANNEL, this);
132
77
//------------------------------------------------------------------------
133
78
BackgroundProcessTicket ResourceBackgroundQueue::initialiseResourceGroup(
134
79
const String& name, ResourceBackgroundQueue::Listener* listener)
136
81
#if OGRE_THREAD_SUPPORT
137
if (!mThread && mStartThread)
139
OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
140
"Thread not initialised",
141
"ResourceBackgroundQueue::initialiseResourceGroup");
143
82
// queue a request
145
84
req.type = RT_INITIALISE_GROUP;
146
85
req.groupName = name;
147
86
req.listener = listener;
371
262
bool ResourceBackgroundQueue::isProcessComplete(
372
263
BackgroundProcessTicket ticket)
377
return mRequestTicketMap.find(ticket) == mRequestTicketMap.end();
379
//------------------------------------------------------------------------
380
#if OGRE_THREAD_SUPPORT
381
BackgroundProcessTicket ResourceBackgroundQueue::addRequest(Request& req)
386
req.ticketID = ++mNextTicketID;
387
mRequestQueue.push_back(req);
388
Request* requestInList = &(mRequestQueue.back());
389
mRequestTicketMap[req.ticketID] = requestInList;
391
// Notify to wake up loading thread
392
OGRE_THREAD_NOTIFY_ONE(mCondition)
396
//------------------------------------------------------------------------
397
void ResourceBackgroundQueue::threadFunc(void)
399
// Background thread implementation
400
// Static (since no params allowed), so get instance
401
ResourceBackgroundQueue& queueInstance =
402
ResourceBackgroundQueue::getSingleton();
404
LogManager::getSingleton().logMessage("ResourceBackgroundQueue - thread starting.");
406
// Initialise the thread
407
queueInstance._initThread();
409
// Spin forever until we're told to shut down
410
while (!queueInstance.mShuttingDown)
412
// Our thread will just wait when there is nothing on the queue
413
// _doNextQueuedBackgroundProcess won't do this since the thread
416
// Manual scope block just to define scope of lock
418
// Lock; note that 'mCondition.wait()' will free the lock
419
boost::recursive_mutex::scoped_lock queueLock(
420
queueInstance.OGRE_AUTO_MUTEX_NAME);
421
if (queueInstance.mRequestQueue.empty())
423
// frees lock and suspends the thread
424
queueInstance.mCondition.wait(queueLock);
426
// When we get back here, it's because we've been notified
427
// and thus the thread as been woken up. Lock has also been
429
} // release lock so queueing can be done while we process one request
431
queueInstance._doNextQueuedBackgroundProcess();
436
LogManager::getSingleton().logMessage("ResourceBackgroundQueue - thread stopped.");
265
return mOutstandingRequestSet.find(ticket) == mOutstandingRequestSet.end();
267
//------------------------------------------------------------------------
268
BackgroundProcessTicket ResourceBackgroundQueue::addRequest(ResourceRequest& req)
270
WorkQueue* queue = Root::getSingleton().getWorkQueue();
274
WorkQueue::RequestID requestID =
275
queue->addRequest(RESOURCE_CHANNEL, (uint16)req.type, data);
278
mOutstandingRequestSet.insert(requestID);
282
//-----------------------------------------------------------------------
283
WorkQueue::Response* ResourceBackgroundQueue::handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ)
286
ResourceRequest resreq = any_cast<ResourceRequest>(req->getData());
442
//-----------------------------------------------------------------------
443
void ResourceBackgroundQueue::_initThread()
445
// Register the calling thread with RenderSystem
446
// Note how we assume only one thread is processing the queue
447
#if OGRE_THREAD_SUPPORT == 1
448
Root::getSingleton().getRenderSystem()->registerThread();
451
// notify waiting thread(s)
452
OGRE_LOCK_MUTEX(initMutex)
453
OGRE_THREAD_NOTIFY_ALL(initSync)
457
//-----------------------------------------------------------------------
458
bool ResourceBackgroundQueue::_doNextQueuedBackgroundProcess()
463
// Manual scope block just to define scope of lock
466
// return false if nothing in the queue
467
if (mRequestQueue.empty())
470
// Process one request
471
req = &(mRequestQueue.front());
472
} // release lock so queueing can be done while we process one request
473
// use of std::list means that references guarateed to remain valid
474
// we only allow one background thread
476
288
ResourceManager* rm = 0;
289
Resource* resource = 0;
482
295
case RT_INITIALISE_GROUP:
483
296
ResourceGroupManager::getSingleton().initialiseResourceGroup(
486
299
case RT_INITIALISE_ALL_GROUPS:
487
300
ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
489
302
case RT_PREPARE_GROUP:
490
303
ResourceGroupManager::getSingleton().prepareResourceGroup(
493
306
case RT_LOAD_GROUP:
494
307
#if OGRE_THREAD_SUPPORT == 2
495
308
ResourceGroupManager::getSingleton().prepareResourceGroup(
498
311
ResourceGroupManager::getSingleton().loadResourceGroup(
502
315
case RT_UNLOAD_GROUP:
503
316
ResourceGroupManager::getSingleton().unloadResourceGroup(
506
319
case RT_PREPARE_RESOURCE:
507
320
rm = ResourceGroupManager::getSingleton()._getResourceManager(
509
rm->prepare(req->resourceName, req->groupName, req->isManual,
510
req->loader, req->loadParams);
321
resreq.resourceType);
322
resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
323
resreq.loader, resreq.loadParams).get();
512
325
case RT_LOAD_RESOURCE:
513
326
rm = ResourceGroupManager::getSingleton()._getResourceManager(
327
resreq.resourceType);
515
328
#if OGRE_THREAD_SUPPORT == 2
516
rm->prepare(req->resourceName, req->groupName, req->isManual,
517
req->loader, req->loadParams);
329
resource = rm->prepare(resreq.resourceName, resreq.groupName, resreq.isManual,
330
resreq.loader, resreq.loadParams).get();
519
rm->load(req->resourceName, req->groupName, req->isManual,
520
req->loader, req->loadParams);
332
resource = rm->load(resreq.resourceName, resreq.groupName, resreq.isManual,
333
resreq.loader, resreq.loadParams).get();
523
336
case RT_UNLOAD_RESOURCE:
524
337
rm = ResourceGroupManager::getSingleton()._getResourceManager(
526
if (req->resourceName.empty())
527
rm->unload(req->resourceHandle);
338
resreq.resourceType);
339
if (resreq.resourceName.empty())
340
rm->unload(resreq.resourceHandle);
529
rm->unload(req->resourceName);
533
#if OGRE_THREAD_SUPPORT
534
mShuttingDown = true;
535
#if OGRE_THREAD_SUPPORT == 1
536
Root::getSingleton().getRenderSystem()->unregisterThread();
342
rm->unload(resreq.resourceName);
542
346
catch (Exception& e)
544
req->result.error = true;
545
req->result.message = e.getFullDescription();
548
// Queue notification (don't do shutdown since not needed & listeners
549
// might be being destroyed too
550
if (req->listener && req->type != RT_SHUTDOWN)
552
// Fire in-thread notification first
553
req->listener->operationCompletedInThread(req->ticketID, req->result);
554
// Then queue main thread notification
555
queueFireBackgroundOperationComplete(req);
560
// re-lock to consume completed request
563
// Consume the ticket
564
mRequestTicketMap.erase(req->ticketID);
565
mRequestQueue.pop_front();
571
//-----------------------------------------------------------------------
572
void ResourceBackgroundQueue::_queueFireBackgroundLoadingComplete(Resource* res)
574
OGRE_LOCK_MUTEX(mNotificationQueueMutex);
575
mNotificationQueue.push_back(QueuedNotification(res,true));
578
//-----------------------------------------------------------------------
579
void ResourceBackgroundQueue::_queueFireBackgroundPreparingComplete(Resource* res)
581
OGRE_LOCK_MUTEX(mNotificationQueueMutex);
582
mNotificationQueue.push_back(QueuedNotification(res,false));
585
//-----------------------------------------------------------------------
586
void ResourceBackgroundQueue::queueFireBackgroundOperationComplete(
587
ResourceBackgroundQueue::Request* req)
589
OGRE_LOCK_MUTEX(mNotificationQueueMutex);
590
mNotificationQueue.push_back(QueuedNotification(*req));
348
resreq.result.error = true;
349
resreq.result.message = e.getFullDescription();
351
// return error response
352
ResourceResponse resresp(resource, resreq);
353
return OGRE_NEW WorkQueue::Response(req, false, Any(resresp), e.getFullDescription());
358
resreq.result.error = false;
359
ResourceResponse resresp(resource, resreq);
360
return OGRE_NEW WorkQueue::Response(req, true, Any(resresp));
592
363
//------------------------------------------------------------------------
593
void ResourceBackgroundQueue::_fireOnFrameCallbacks()
364
void ResourceBackgroundQueue::handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ)
595
OGRE_LOCK_MUTEX(mNotificationQueueMutex);
596
for (NotificationQueue::iterator i = mNotificationQueue.begin();
597
i != mNotificationQueue.end(); ++i)
366
if (res->succeeded())
601
i->resource->_fireLoadingComplete();
603
i->resource->_firePreparingComplete();
606
const ResourceBackgroundQueue::Request &r = i->req;
368
ResourceResponse resresp = any_cast<ResourceResponse>(res->getData());
370
// Complete full loading in main thread if semithreading
371
const ResourceRequest& req = resresp.request;
607
372
#if OGRE_THREAD_SUPPORT == 2
608
if (r.type==RT_LOAD_RESOURCE) {
609
ResourceManager *rm = ResourceGroupManager::getSingleton()
610
._getResourceManager(r.resourceType);
611
rm->load(r.resourceName, r.groupName, r.isManual, r.loader, r.loadParams);
612
} else if (r.type==RT_LOAD_GROUP) {
613
ResourceGroupManager::getSingleton().loadResourceGroup(r.groupName);
373
// These load commands would have been downgraded to prepare() for the background
374
if (req.type == RT_LOAD_RESOURCE)
376
ResourceManager *rm = ResourceGroupManager::getSingleton()
377
._getResourceManager(req.resourceType);
378
rm->load(req.resourceName, req.groupName, req.isManual, req.loader, req.loadParams);
380
else if (req.type == RT_LOAD_GROUP)
382
ResourceGroupManager::getSingleton().loadResourceGroup(req.groupName);
616
r.listener->operationCompleted(r.ticketID, r.result);
385
mOutstandingRequestSet.erase(res->getRequest()->getID());
387
// Call resource listener
388
if (resresp.resource)
391
if (req.type == RT_LOAD_RESOURCE)
393
resresp.resource->_fireLoadingComplete();
397
resresp.resource->_firePreparingComplete();
401
// Call queue listener
403
req.listener->operationCompleted(res->getRequest()->getID(), req.result);
619
mNotificationQueue.clear();
622
407
//------------------------------------------------------------------------