| [148] | 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-2013 Torus Knot Software Ltd | 
|---|
 | 8 |  | 
|---|
 | 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: | 
|---|
 | 15 |  | 
|---|
 | 16 | The above copyright notice and this permission notice shall be included in | 
|---|
 | 17 | all copies or substantial portions of the Software. | 
|---|
 | 18 |  | 
|---|
 | 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 | 
|---|
 | 25 | THE SOFTWARE. | 
|---|
 | 26 | ----------------------------------------------------------------------------- | 
|---|
 | 27 | */ | 
|---|
 | 28 | #ifndef __ResourceBackgroundQueue_H__ | 
|---|
 | 29 | #define __ResourceBackgroundQueue_H__ | 
|---|
 | 30 |  | 
|---|
 | 31 |  | 
|---|
 | 32 | #include "OgrePrerequisites.h" | 
|---|
 | 33 | #include "OgreCommon.h" | 
|---|
 | 34 | #include "OgreSingleton.h" | 
|---|
 | 35 | #include "OgreResource.h" | 
|---|
 | 36 | #include "OgreWorkQueue.h" | 
|---|
 | 37 | #include "OgreHeaderPrefix.h" | 
|---|
 | 38 |  | 
|---|
 | 39 | namespace Ogre { | 
|---|
 | 40 |         /** \addtogroup Core | 
|---|
 | 41 |         *  @{ | 
|---|
 | 42 |         */ | 
|---|
 | 43 |         /** \addtogroup Resources | 
|---|
 | 44 |         *  @{ | 
|---|
 | 45 |         */ | 
|---|
 | 46 |  | 
|---|
 | 47 |         /// Identifier of a background process | 
|---|
 | 48 |         typedef WorkQueue::RequestID BackgroundProcessTicket; | 
|---|
 | 49 |  | 
|---|
 | 50 |         /** Encapsulates the result of a background queue request */ | 
|---|
 | 51 |         struct BackgroundProcessResult | 
|---|
 | 52 |         { | 
|---|
 | 53 |                 /// Whether an error occurred | 
|---|
 | 54 |                 bool error; | 
|---|
 | 55 |                 /// Any messages from the process | 
|---|
 | 56 |                 String message; | 
|---|
 | 57 |  | 
|---|
 | 58 |                 BackgroundProcessResult() : error(false) {} | 
|---|
 | 59 |         }; | 
|---|
 | 60 |  | 
|---|
 | 61 |          | 
|---|
 | 62 |         /** This class is used to perform Resource operations in a | 
|---|
 | 63 |                 background thread.  | 
|---|
 | 64 |         @remarks | 
|---|
 | 65 |                 All these requests are now queued via Root::getWorkQueue in order | 
|---|
 | 66 |                 to share the thread pool amongst all background tasks. You should therefore | 
|---|
 | 67 |                 refer to that class for configuring the behaviour of the threads | 
|---|
 | 68 |                 themselves, this class merely provides an interface that is specific | 
|---|
 | 69 |                 to resource loading around this common functionality. | 
|---|
 | 70 |         @par | 
|---|
 | 71 |                 The general approach here is that on requesting a background resource | 
|---|
 | 72 |                 process, your request is placed on a queue ready for the background | 
|---|
 | 73 |                 thread to be picked up, and you will get a 'ticket' back, identifying | 
|---|
 | 74 |                 the request. Your call will then return and your thread can | 
|---|
 | 75 |                 proceed, knowing that at some point in the background the operation will  | 
|---|
 | 76 |                 be performed. In it's own thread, the resource operation will be  | 
|---|
 | 77 |                 performed, and once finished the ticket will be marked as complete.  | 
|---|
 | 78 |                 You can check the status of tickets by calling isProcessComplete()  | 
|---|
 | 79 |                 from your queueing thread.  | 
|---|
 | 80 |         */ | 
|---|
 | 81 |         class _OgreExport ResourceBackgroundQueue : public Singleton<ResourceBackgroundQueue>, public ResourceAlloc,  | 
|---|
 | 82 |                 public WorkQueue::RequestHandler, public WorkQueue::ResponseHandler | 
|---|
 | 83 |         { | 
|---|
 | 84 |         public: | 
|---|
 | 85 |                 /** This abstract listener interface lets you get notifications of | 
|---|
 | 86 |                 completed background processes instead of having to poll ticket  | 
|---|
 | 87 |                 statuses. | 
|---|
 | 88 |                 @note | 
|---|
 | 89 |                 For simplicity, these callbacks are not issued direct from the background | 
|---|
 | 90 |                 loading thread, they are queued themselves to be sent from the main thread | 
|---|
 | 91 |                 so that you don't have to be concerned about thread safety.  | 
|---|
 | 92 |                 */ | 
|---|
 | 93 |                 class _OgreExport Listener | 
|---|
 | 94 |                 { | 
|---|
 | 95 |                 public: | 
|---|
 | 96 |                         /** Called when a requested operation completes, queued into main thread.  | 
|---|
 | 97 |                         @note | 
|---|
 | 98 |                                 For simplicity, this callback is not issued direct from the background | 
|---|
 | 99 |                                 loading thread, it is queued to be sent from the main thread | 
|---|
 | 100 |                                 so that you don't have to be concerned about thread safety.  | 
|---|
 | 101 |                         */ | 
|---|
 | 102 |                         virtual void operationCompleted(BackgroundProcessTicket ticket, const BackgroundProcessResult& result) = 0; | 
|---|
 | 103 |                         /// Need virtual destructor in case subclasses use it | 
|---|
 | 104 |                         virtual ~Listener() {} | 
|---|
 | 105 |  | 
|---|
 | 106 |                 }; | 
|---|
 | 107 |  | 
|---|
 | 108 |         protected: | 
|---|
 | 109 |  | 
|---|
 | 110 |                 uint16 mWorkQueueChannel; | 
|---|
 | 111 |                 /** Enumerates the type of requests */ | 
|---|
 | 112 |                 enum RequestType | 
|---|
 | 113 |                 { | 
|---|
 | 114 |                         RT_INITIALISE_GROUP = 0, | 
|---|
 | 115 |                         RT_INITIALISE_ALL_GROUPS = 1, | 
|---|
 | 116 |                         RT_PREPARE_GROUP = 2, | 
|---|
 | 117 |                         RT_PREPARE_RESOURCE = 3, | 
|---|
 | 118 |                         RT_LOAD_GROUP = 4, | 
|---|
 | 119 |                         RT_LOAD_RESOURCE = 5, | 
|---|
 | 120 |                         RT_UNLOAD_GROUP = 6, | 
|---|
 | 121 |                         RT_UNLOAD_RESOURCE = 7 | 
|---|
 | 122 |                 }; | 
|---|
 | 123 |                 /** Encapsulates a queued request for the background queue */ | 
|---|
 | 124 |                 struct ResourceRequest | 
|---|
 | 125 |                 { | 
|---|
 | 126 |                         RequestType type; | 
|---|
 | 127 |                         String resourceName; | 
|---|
 | 128 |                         ResourceHandle resourceHandle; | 
|---|
 | 129 |                         String resourceType; | 
|---|
 | 130 |                         String groupName; | 
|---|
 | 131 |                         bool isManual;  | 
|---|
 | 132 |                         ManualResourceLoader* loader; | 
|---|
 | 133 |                         NameValuePairList* loadParams; | 
|---|
 | 134 |                         Listener* listener; | 
|---|
 | 135 |                         BackgroundProcessResult result; | 
|---|
 | 136 |  | 
|---|
 | 137 |                         _OgreExport friend std::ostream& operator<<(std::ostream& o, const ResourceRequest& r) | 
|---|
 | 138 |                         { (void)r; return o; } | 
|---|
 | 139 |                 }; | 
|---|
 | 140 |  | 
|---|
 | 141 |                 typedef set<BackgroundProcessTicket>::type OutstandingRequestSet;        | 
|---|
 | 142 |                 OutstandingRequestSet mOutstandingRequestSet; | 
|---|
 | 143 |  | 
|---|
 | 144 |                 /// Struct that holds details of queued notifications | 
|---|
 | 145 |                 struct ResourceResponse | 
|---|
 | 146 |                 { | 
|---|
 | 147 |                         ResourceResponse(ResourcePtr r, const ResourceRequest& req) | 
|---|
 | 148 |                                 : resource(r), request(req) | 
|---|
 | 149 |                         {} | 
|---|
 | 150 |  | 
|---|
 | 151 |                         ResourcePtr resource; | 
|---|
 | 152 |                         ResourceRequest request; | 
|---|
 | 153 |  | 
|---|
 | 154 |                         _OgreExport friend std::ostream& operator<<(std::ostream& o, const ResourceResponse& r) | 
|---|
 | 155 |                         { (void)r; return o; } | 
|---|
 | 156 |                 }; | 
|---|
 | 157 |  | 
|---|
 | 158 |                 BackgroundProcessTicket addRequest(ResourceRequest& req); | 
|---|
 | 159 |  | 
|---|
 | 160 |         public: | 
|---|
 | 161 |                 ResourceBackgroundQueue(); | 
|---|
 | 162 |                 virtual ~ResourceBackgroundQueue(); | 
|---|
 | 163 |  | 
|---|
 | 164 |                 /** Initialise the background queue system.  | 
|---|
 | 165 |                 @note Called automatically by Root::initialise. | 
|---|
 | 166 |                 */ | 
|---|
 | 167 |                 virtual void initialise(void); | 
|---|
 | 168 |  | 
|---|
 | 169 |                 /** Shut down the background queue system.  | 
|---|
 | 170 |                 @note Called automatically by Root::shutdown. | 
|---|
 | 171 |                 */ | 
|---|
 | 172 |                 virtual void shutdown(void); | 
|---|
 | 173 |  | 
|---|
 | 174 |                 /** Initialise a resource group in the background. | 
|---|
 | 175 |                 @see ResourceGroupManager::initialiseResourceGroup | 
|---|
 | 176 |                 @param name The name of the resource group to initialise | 
|---|
 | 177 |                 @param listener Optional callback interface, take note of warnings in  | 
|---|
 | 178 |                         the header and only use if you understand them. | 
|---|
 | 179 |                 @return Ticket identifying the request, use isProcessComplete() to  | 
|---|
 | 180 |                         determine if completed if not using listener | 
|---|
 | 181 |                 */ | 
|---|
 | 182 |                 virtual BackgroundProcessTicket initialiseResourceGroup( | 
|---|
 | 183 |                         const String& name, Listener* listener = 0); | 
|---|
 | 184 |  | 
|---|
 | 185 |                 /** Initialise all resource groups which are yet to be initialised in  | 
|---|
 | 186 |                         the background. | 
|---|
 | 187 |                 @see ResourceGroupManager::intialiseResourceGroup | 
|---|
 | 188 |                 @param listener Optional callback interface, take note of warnings in  | 
|---|
 | 189 |                         the header and only use if you understand them. | 
|---|
 | 190 |                 @return Ticket identifying the request, use isProcessComplete() to  | 
|---|
 | 191 |                         determine if completed if not using listener | 
|---|
 | 192 |                 */ | 
|---|
 | 193 |                 virtual BackgroundProcessTicket initialiseAllResourceGroups(  | 
|---|
 | 194 |                         Listener* listener = 0); | 
|---|
 | 195 |                 /** Prepares a resource group in the background. | 
|---|
 | 196 |                 @see ResourceGroupManager::prepareResourceGroup | 
|---|
 | 197 |                 @param name The name of the resource group to prepare | 
|---|
 | 198 |                 @param listener Optional callback interface, take note of warnings in  | 
|---|
 | 199 |                         the header and only use if you understand them. | 
|---|
 | 200 |                 @return Ticket identifying the request, use isProcessComplete() to  | 
|---|
 | 201 |                         determine if completed if not using listener | 
|---|
 | 202 |                 */ | 
|---|
 | 203 |                 virtual BackgroundProcessTicket prepareResourceGroup(const String& name,  | 
|---|
 | 204 |                         Listener* listener = 0); | 
|---|
 | 205 |  | 
|---|
 | 206 |                 /** Loads a resource group in the background. | 
|---|
 | 207 |                 @see ResourceGroupManager::loadResourceGroup | 
|---|
 | 208 |                 @param name The name of the resource group to load | 
|---|
 | 209 |                 @param listener Optional callback interface, take note of warnings in  | 
|---|
 | 210 |                         the header and only use if you understand them. | 
|---|
 | 211 |                 @return Ticket identifying the request, use isProcessComplete() to  | 
|---|
 | 212 |                         determine if completed if not using listener | 
|---|
 | 213 |                 */ | 
|---|
 | 214 |                 virtual BackgroundProcessTicket loadResourceGroup(const String& name,  | 
|---|
 | 215 |                         Listener* listener = 0); | 
|---|
 | 216 |  | 
|---|
 | 217 |  | 
|---|
 | 218 |                 /** Unload a single resource in the background.  | 
|---|
 | 219 |                 @see ResourceManager::unload | 
|---|
 | 220 |                 @param resType The type of the resource  | 
|---|
 | 221 |                         (from ResourceManager::getResourceType()) | 
|---|
 | 222 |                 @param name The name of the Resource | 
|---|
 | 223 |                 */ | 
|---|
 | 224 |                 virtual BackgroundProcessTicket unload( | 
|---|
 | 225 |                         const String& resType, const String& name,  | 
|---|
 | 226 |                         Listener* listener = 0); | 
|---|
 | 227 |  | 
|---|
 | 228 |                 /** Unload a single resource in the background.  | 
|---|
 | 229 |                 @see ResourceManager::unload | 
|---|
 | 230 |                 @param resType The type of the resource  | 
|---|
 | 231 |                         (from ResourceManager::getResourceType()) | 
|---|
 | 232 |                 @param handle Handle to the resource  | 
|---|
 | 233 |                 */ | 
|---|
 | 234 |                 virtual BackgroundProcessTicket unload( | 
|---|
 | 235 |                         const String& resType, ResourceHandle handle,  | 
|---|
 | 236 |                         Listener* listener = 0); | 
|---|
 | 237 |  | 
|---|
 | 238 |                 /** Unloads a resource group in the background. | 
|---|
 | 239 |                 @see ResourceGroupManager::unloadResourceGroup | 
|---|
 | 240 |                 @param name The name of the resource group to load | 
|---|
 | 241 |                 @return Ticket identifying the request, use isProcessComplete() to  | 
|---|
 | 242 |                         determine if completed if not using listener | 
|---|
 | 243 |                 */ | 
|---|
 | 244 |                 virtual BackgroundProcessTicket unloadResourceGroup(const String& name,  | 
|---|
 | 245 |                         Listener* listener = 0); | 
|---|
 | 246 |  | 
|---|
 | 247 |  | 
|---|
 | 248 |                 /** Prepare a single resource in the background.  | 
|---|
 | 249 |                 @see ResourceManager::prepare | 
|---|
 | 250 |                 @param resType The type of the resource  | 
|---|
 | 251 |                         (from ResourceManager::getResourceType()) | 
|---|
 | 252 |                 @param name The name of the Resource | 
|---|
 | 253 |                 @param group The resource group to which this resource will belong | 
|---|
 | 254 |                 @param isManual Is the resource to be manually loaded? If so, you should | 
|---|
 | 255 |                         provide a value for the loader parameter | 
|---|
 | 256 |                 @param loader The manual loader which is to perform the required actions | 
|---|
 | 257 |                         when this resource is loaded; only applicable when you specify true | 
|---|
 | 258 |                         for the previous parameter. NOTE: must be thread safe!! | 
|---|
 | 259 |         @param loadParams Optional pointer to a list of name/value pairs  | 
|---|
 | 260 |             containing loading parameters for this type of resource. Remember  | 
|---|
 | 261 |                         that this must have a lifespan longer than the return of this call! | 
|---|
 | 262 |                 */ | 
|---|
 | 263 |                 virtual BackgroundProcessTicket prepare( | 
|---|
 | 264 |                         const String& resType, const String& name,  | 
|---|
 | 265 |             const String& group, bool isManual = false,  | 
|---|
 | 266 |                         ManualResourceLoader* loader = 0,  | 
|---|
 | 267 |                         const NameValuePairList* loadParams = 0,  | 
|---|
 | 268 |                         Listener* listener = 0); | 
|---|
 | 269 |  | 
|---|
 | 270 |                 /** Load a single resource in the background.  | 
|---|
 | 271 |                 @see ResourceManager::load | 
|---|
 | 272 |                 @param resType The type of the resource  | 
|---|
 | 273 |                         (from ResourceManager::getResourceType()) | 
|---|
 | 274 |                 @param name The name of the Resource | 
|---|
 | 275 |                 @param group The resource group to which this resource will belong | 
|---|
 | 276 |                 @param isManual Is the resource to be manually loaded? If so, you should | 
|---|
 | 277 |                         provide a value for the loader parameter | 
|---|
 | 278 |                 @param loader The manual loader which is to perform the required actions | 
|---|
 | 279 |                         when this resource is loaded; only applicable when you specify true | 
|---|
 | 280 |                         for the previous parameter. NOTE: must be thread safe!! | 
|---|
 | 281 |         @param loadParams Optional pointer to a list of name/value pairs  | 
|---|
 | 282 |             containing loading parameters for this type of resource. Remember  | 
|---|
 | 283 |                         that this must have a lifespan longer than the return of this call! | 
|---|
 | 284 |                 */ | 
|---|
 | 285 |                 virtual BackgroundProcessTicket load( | 
|---|
 | 286 |                         const String& resType, const String& name,  | 
|---|
 | 287 |             const String& group, bool isManual = false,  | 
|---|
 | 288 |                         ManualResourceLoader* loader = 0,  | 
|---|
 | 289 |                         const NameValuePairList* loadParams = 0,  | 
|---|
 | 290 |                         Listener* listener = 0); | 
|---|
 | 291 |                 /** Returns whether a previously queued process has completed or not.  | 
|---|
 | 292 |                 @remarks | 
|---|
 | 293 |                         This method of checking that a background process has completed is | 
|---|
 | 294 |                         the 'polling' approach. Each queued method takes an optional listener | 
|---|
 | 295 |                         parameter to allow you to register a callback instead, which is | 
|---|
 | 296 |                         arguably more efficient. | 
|---|
 | 297 |                 @param ticket The ticket which was returned when the process was queued | 
|---|
 | 298 |                 @return true if process has completed (or if the ticket is  | 
|---|
 | 299 |                         unrecognised), false otherwise | 
|---|
 | 300 |                 @note Tickets are not stored once complete so do not accumulate over  | 
|---|
 | 301 |                         time. | 
|---|
 | 302 |                 This is why a non-existent ticket will return 'true'. | 
|---|
 | 303 |                 */ | 
|---|
 | 304 |                 virtual bool isProcessComplete(BackgroundProcessTicket ticket); | 
|---|
 | 305 |  | 
|---|
 | 306 |                 /** Aborts background process. | 
|---|
 | 307 |                 */ | 
|---|
 | 308 |                 void abortRequest( BackgroundProcessTicket ticket ); | 
|---|
 | 309 |  | 
|---|
 | 310 |                 /// Implementation for WorkQueue::RequestHandler | 
|---|
 | 311 |                 bool canHandleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ); | 
|---|
 | 312 |                 /// Implementation for WorkQueue::RequestHandler | 
|---|
 | 313 |                 WorkQueue::Response* handleRequest(const WorkQueue::Request* req, const WorkQueue* srcQ); | 
|---|
 | 314 |                 /// Implementation for WorkQueue::ResponseHandler | 
|---|
 | 315 |                 bool canHandleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ); | 
|---|
 | 316 |                 /// Implementation for WorkQueue::ResponseHandler | 
|---|
 | 317 |                 void handleResponse(const WorkQueue::Response* res, const WorkQueue* srcQ); | 
|---|
 | 318 |  | 
|---|
 | 319 |                 /** Override standard Singleton retrieval. | 
|---|
 | 320 |         @remarks | 
|---|
 | 321 |         Why do we do this? Well, it's because the Singleton | 
|---|
 | 322 |         implementation is in a .h file, which means it gets compiled | 
|---|
 | 323 |         into anybody who includes it. This is needed for the | 
|---|
 | 324 |         Singleton template to work, but we actually only want it | 
|---|
 | 325 |         compiled into the implementation of the class based on the | 
|---|
 | 326 |         Singleton, not all of them. If we don't change this, we get | 
|---|
 | 327 |         link errors when trying to use the Singleton-based class from | 
|---|
 | 328 |         an outside dll. | 
|---|
 | 329 |         @par | 
|---|
 | 330 |         This method just delegates to the template version anyway, | 
|---|
 | 331 |         but the implementation stays in this single compilation unit, | 
|---|
 | 332 |         preventing link errors. | 
|---|
 | 333 |         */ | 
|---|
 | 334 |         static ResourceBackgroundQueue& getSingleton(void); | 
|---|
 | 335 |         /** Override standard Singleton retrieval. | 
|---|
 | 336 |         @remarks | 
|---|
 | 337 |         Why do we do this? Well, it's because the Singleton | 
|---|
 | 338 |         implementation is in a .h file, which means it gets compiled | 
|---|
 | 339 |         into anybody who includes it. This is needed for the | 
|---|
 | 340 |         Singleton template to work, but we actually only want it | 
|---|
 | 341 |         compiled into the implementation of the class based on the | 
|---|
 | 342 |         Singleton, not all of them. If we don't change this, we get | 
|---|
 | 343 |         link errors when trying to use the Singleton-based class from | 
|---|
 | 344 |         an outside dll. | 
|---|
 | 345 |         @par | 
|---|
 | 346 |         This method just delegates to the template version anyway, | 
|---|
 | 347 |         but the implementation stays in this single compilation unit, | 
|---|
 | 348 |         preventing link errors. | 
|---|
 | 349 |         */ | 
|---|
 | 350 |         static ResourceBackgroundQueue* getSingletonPtr(void); | 
|---|
 | 351 |  | 
|---|
 | 352 |         }; | 
|---|
 | 353 |  | 
|---|
 | 354 |         /** @} */ | 
|---|
 | 355 |         /** @} */ | 
|---|
 | 356 |  | 
|---|
 | 357 | } | 
|---|
 | 358 |  | 
|---|
 | 359 | #include "OgreHeaderSuffix.h" | 
|---|
 | 360 |  | 
|---|
 | 361 | #endif | 
|---|
 | 362 |  | 
|---|