1 | /*
|
---|
2 | -----------------------------------------------------------------------------
|
---|
3 | This source file is part of OGRE
|
---|
4 | (Object-oriented Graphics Rendering Engine)
|
---|
5 | For the latest info, see http://www.ogre3d.org/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
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
|
---|
13 | version.
|
---|
14 |
|
---|
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.
|
---|
18 |
|
---|
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.
|
---|
23 | -----------------------------------------------------------------------------
|
---|
24 | */
|
---|
25 | #include "OgreStableHeaders.h"
|
---|
26 | #include "OgreResourceBackgroundQueue.h"
|
---|
27 | #include "OgreLogManager.h"
|
---|
28 | #include "OgreException.h"
|
---|
29 | #include "OgreResourceGroupManager.h"
|
---|
30 | #include "OgreResourceManager.h"
|
---|
31 |
|
---|
32 | namespace Ogre {
|
---|
33 |
|
---|
34 | //------------------------------------------------------------------------
|
---|
35 | //-----------------------------------------------------------------------
|
---|
36 | template<> ResourceBackgroundQueue* Singleton<ResourceBackgroundQueue>::ms_Singleton = 0;
|
---|
37 | ResourceBackgroundQueue* ResourceBackgroundQueue::getSingletonPtr(void)
|
---|
38 | {
|
---|
39 | return ms_Singleton;
|
---|
40 | }
|
---|
41 | ResourceBackgroundQueue& ResourceBackgroundQueue::getSingleton(void)
|
---|
42 | {
|
---|
43 | assert( ms_Singleton ); return ( *ms_Singleton );
|
---|
44 | }
|
---|
45 | //-----------------------------------------------------------------------
|
---|
46 | //------------------------------------------------------------------------
|
---|
47 | ResourceBackgroundQueue::ResourceBackgroundQueue()
|
---|
48 | :mNextTicketID(0), mThread(0)
|
---|
49 | {
|
---|
50 | }
|
---|
51 | //------------------------------------------------------------------------
|
---|
52 | ResourceBackgroundQueue::~ResourceBackgroundQueue()
|
---|
53 | {
|
---|
54 | shutdown();
|
---|
55 | }
|
---|
56 | //------------------------------------------------------------------------
|
---|
57 | void ResourceBackgroundQueue::initialise(void)
|
---|
58 | {
|
---|
59 | #if OGRE_THREAD_SUPPORT
|
---|
60 | OGRE_LOCK_AUTO_MUTEX
|
---|
61 | mThread = new boost::thread(
|
---|
62 | boost::function0<void>(&ResourceBackgroundQueue::threadFunc));
|
---|
63 | LogManager::getSingleton().logMessage(
|
---|
64 | "ResourceBackgroundQueue - threading enabled");
|
---|
65 | #else
|
---|
66 | LogManager::getSingleton().logMessage(
|
---|
67 | "ResourceBackgroundQueue - threading disabled");
|
---|
68 | #endif
|
---|
69 | }
|
---|
70 | //------------------------------------------------------------------------
|
---|
71 | void ResourceBackgroundQueue::shutdown(void)
|
---|
72 | {
|
---|
73 | #if OGRE_THREAD_SUPPORT
|
---|
74 | if (mThread)
|
---|
75 | {
|
---|
76 | // Put a shutdown request on the queue
|
---|
77 | Request req;
|
---|
78 | req.type = RT_SHUTDOWN;
|
---|
79 | addRequest(req);
|
---|
80 | // Wait for thread to finish
|
---|
81 | mThread->join();
|
---|
82 | delete mThread;
|
---|
83 | mThread = 0;
|
---|
84 | mRequestQueue.clear();
|
---|
85 | mRequestTicketMap.clear();
|
---|
86 | }
|
---|
87 | #endif
|
---|
88 | }
|
---|
89 | //------------------------------------------------------------------------
|
---|
90 | BackgroundProcessTicket ResourceBackgroundQueue::initialiseResourceGroup(
|
---|
91 | const String& name, ResourceBackgroundQueueListener* listener)
|
---|
92 | {
|
---|
93 | #if OGRE_THREAD_SUPPORT
|
---|
94 | if (!mThread)
|
---|
95 | {
|
---|
96 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
|
---|
97 | "Thread not initialised",
|
---|
98 | "ResourceBackgroundQueue::initialiseResourceGroup");
|
---|
99 | }
|
---|
100 | // queue a request
|
---|
101 | Request req;
|
---|
102 | req.type = RT_INITIALISE_GROUP;
|
---|
103 | req.groupName = name;
|
---|
104 | req.listener = listener;
|
---|
105 | return addRequest(req);
|
---|
106 | #else
|
---|
107 | // synchronous
|
---|
108 | ResourceGroupManager::getSingleton().initialiseResourceGroup(name);
|
---|
109 | return 0;
|
---|
110 | #endif
|
---|
111 | }
|
---|
112 | //------------------------------------------------------------------------
|
---|
113 | BackgroundProcessTicket
|
---|
114 | ResourceBackgroundQueue::initialiseAllResourceGroups(
|
---|
115 | ResourceBackgroundQueueListener* listener)
|
---|
116 | {
|
---|
117 | #if OGRE_THREAD_SUPPORT
|
---|
118 | if (!mThread)
|
---|
119 | {
|
---|
120 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
|
---|
121 | "Thread not initialised",
|
---|
122 | "ResourceBackgroundQueue::initialiseAllResourceGroups");
|
---|
123 | }
|
---|
124 | // queue a request
|
---|
125 | Request req;
|
---|
126 | req.type = RT_INITIALISE_ALL_GROUPS;
|
---|
127 | req.listener = listener;
|
---|
128 | return addRequest(req);
|
---|
129 | #else
|
---|
130 | // synchronous
|
---|
131 | ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
---|
132 | return 0;
|
---|
133 | #endif
|
---|
134 | }
|
---|
135 | //------------------------------------------------------------------------
|
---|
136 | BackgroundProcessTicket ResourceBackgroundQueue::loadResourceGroup(
|
---|
137 | const String& name, ResourceBackgroundQueueListener* listener)
|
---|
138 | {
|
---|
139 | #if OGRE_THREAD_SUPPORT
|
---|
140 | if (!mThread)
|
---|
141 | {
|
---|
142 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
|
---|
143 | "Thread not initialised",
|
---|
144 | "ResourceBackgroundQueue::loadResourceGroup");
|
---|
145 | }
|
---|
146 | // queue a request
|
---|
147 | Request req;
|
---|
148 | req.type = RT_LOAD_GROUP;
|
---|
149 | req.groupName = name;
|
---|
150 | req.listener = listener;
|
---|
151 | return addRequest(req);
|
---|
152 | #else
|
---|
153 | // synchronous
|
---|
154 | ResourceGroupManager::getSingleton().loadResourceGroup(name);
|
---|
155 | return 0;
|
---|
156 | #endif
|
---|
157 | }
|
---|
158 | //------------------------------------------------------------------------
|
---|
159 | BackgroundProcessTicket ResourceBackgroundQueue::load(
|
---|
160 | const String& resType, const String& name,
|
---|
161 | const String& group, bool isManual,
|
---|
162 | ManualResourceLoader* loader,
|
---|
163 | const NameValuePairList* loadParams,
|
---|
164 | ResourceBackgroundQueueListener* listener)
|
---|
165 | {
|
---|
166 | #if OGRE_THREAD_SUPPORT
|
---|
167 | if (!mThread)
|
---|
168 | {
|
---|
169 | OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
|
---|
170 | "Thread not initialised",
|
---|
171 | "ResourceBackgroundQueue::load");
|
---|
172 | }
|
---|
173 | // queue a request
|
---|
174 | Request req;
|
---|
175 | req.type = RT_LOAD_RESOURCE;
|
---|
176 | req.resourceType = resType;
|
---|
177 | req.resourceName = name;
|
---|
178 | req.groupName = group;
|
---|
179 | req.isManual = isManual;
|
---|
180 | req.loader = loader;
|
---|
181 | req.loadParams = loadParams;
|
---|
182 | req.listener = listener;
|
---|
183 | return addRequest(req);
|
---|
184 | #else
|
---|
185 | // synchronous
|
---|
186 | ResourceManager* rm =
|
---|
187 | ResourceGroupManager::getSingleton()._getResourceManager(resType);
|
---|
188 | rm->load(name, group, isManual, loader, loadParams);
|
---|
189 | return 0;
|
---|
190 | #endif
|
---|
191 | }
|
---|
192 | //------------------------------------------------------------------------
|
---|
193 | bool ResourceBackgroundQueue::isProcessComplete(
|
---|
194 | BackgroundProcessTicket ticket)
|
---|
195 | {
|
---|
196 | return mRequestTicketMap.find(ticket) == mRequestTicketMap.end();
|
---|
197 | }
|
---|
198 | //------------------------------------------------------------------------
|
---|
199 | #if OGRE_THREAD_SUPPORT
|
---|
200 | BackgroundProcessTicket ResourceBackgroundQueue::addRequest(Request& req)
|
---|
201 | {
|
---|
202 | // Lock
|
---|
203 | OGRE_LOCK_AUTO_MUTEX
|
---|
204 |
|
---|
205 | req.ticketID = ++mNextTicketID;
|
---|
206 | mRequestQueue.push_back(req);
|
---|
207 | Request* requestInList = &(mRequestQueue.back());
|
---|
208 | mRequestTicketMap[req.ticketID] = requestInList;
|
---|
209 |
|
---|
210 | // Notify to wake up loading thread
|
---|
211 | mCondition.notify_one();
|
---|
212 |
|
---|
213 | return req.ticketID;
|
---|
214 | }
|
---|
215 | //------------------------------------------------------------------------
|
---|
216 | void ResourceBackgroundQueue::threadFunc(void)
|
---|
217 | {
|
---|
218 | // Background thread implementation
|
---|
219 | // Static (since no params allowed), so get instance
|
---|
220 | ResourceBackgroundQueue& queueInstance =
|
---|
221 | ResourceBackgroundQueue::getSingleton();
|
---|
222 |
|
---|
223 | bool shuttingDown = false;
|
---|
224 | // Spin forever until we're told to shut down
|
---|
225 | while (!shuttingDown)
|
---|
226 | {
|
---|
227 | Request* req;
|
---|
228 | // Manual scope block just to define scope of lock
|
---|
229 | {
|
---|
230 | // Lock; note that 'mCondition.wait()' will free the lock
|
---|
231 | boost::recursive_mutex::scoped_lock queueLock(
|
---|
232 | queueInstance.OGRE_AUTO_MUTEX_NAME);
|
---|
233 | if (queueInstance.mRequestQueue.empty())
|
---|
234 | {
|
---|
235 | // frees lock and suspends the thread
|
---|
236 | queueInstance.mCondition.wait(queueLock);
|
---|
237 | }
|
---|
238 | // When we get back here, it's because we've been notified
|
---|
239 | // and thus the thread as been woken up. Lock has also been
|
---|
240 | // re-acquired.
|
---|
241 |
|
---|
242 | // Process one request
|
---|
243 | req = &(queueInstance.mRequestQueue.front());
|
---|
244 | } // release lock so queueing can be done while we process one request
|
---|
245 | // use of std::list means that references guarateed to remain valid
|
---|
246 |
|
---|
247 | ResourceManager* rm = 0;
|
---|
248 | switch (req->type)
|
---|
249 | {
|
---|
250 | case RT_INITIALISE_GROUP:
|
---|
251 | ResourceGroupManager::getSingleton().initialiseResourceGroup(
|
---|
252 | req->groupName);
|
---|
253 | break;
|
---|
254 | case RT_INITIALISE_ALL_GROUPS:
|
---|
255 | ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
|
---|
256 | break;
|
---|
257 | case RT_LOAD_GROUP:
|
---|
258 | ResourceGroupManager::getSingleton().loadResourceGroup(
|
---|
259 | req->groupName);
|
---|
260 | break;
|
---|
261 | case RT_LOAD_RESOURCE:
|
---|
262 | rm = ResourceGroupManager::getSingleton()._getResourceManager(
|
---|
263 | req->resourceType);
|
---|
264 | rm->load(req->resourceName, req->groupName, req->isManual,
|
---|
265 | req->loader, req->loadParams);
|
---|
266 | break;
|
---|
267 | case RT_SHUTDOWN:
|
---|
268 | // That's all folks
|
---|
269 | shuttingDown = true;
|
---|
270 | break;
|
---|
271 | };
|
---|
272 |
|
---|
273 |
|
---|
274 | {
|
---|
275 | // re-lock to consume completed request
|
---|
276 | boost::recursive_mutex::scoped_lock queueLock(
|
---|
277 | queueInstance.OGRE_AUTO_MUTEX_NAME);
|
---|
278 |
|
---|
279 | // Consume the ticket
|
---|
280 | queueInstance.mRequestTicketMap.erase(req->ticketID);
|
---|
281 | queueInstance.mRequestQueue.pop_front();
|
---|
282 | }
|
---|
283 |
|
---|
284 |
|
---|
285 | }
|
---|
286 |
|
---|
287 |
|
---|
288 |
|
---|
289 | }
|
---|
290 | #endif
|
---|
291 | //------------------------------------------------------------------------
|
---|
292 |
|
---|
293 | }
|
---|
294 |
|
---|
295 |
|
---|
296 |
|
---|