00001 // Filename: geomMunger.cxx 00002 // Created by: drose (10Mar05) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "geomMunger.h" 00016 #include "geom.h" 00017 #include "geomCacheManager.h" 00018 #include "lightMutexHolder.h" 00019 #include "lightReMutexHolder.h" 00020 #include "pStatTimer.h" 00021 00022 GeomMunger::Registry *GeomMunger::_registry = NULL; 00023 TypeHandle GeomMunger::_type_handle; 00024 00025 PStatCollector GeomMunger::_munge_pcollector("*:Munge"); 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: GeomMunger::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 GeomMunger:: 00033 GeomMunger(GraphicsStateGuardianBase *gsg) : 00034 _gsg(gsg), 00035 _is_registered(false) 00036 { 00037 #ifndef NDEBUG 00038 Registry *registry = get_registry(); 00039 LightReMutexHolder holder(registry->_registry_lock); 00040 _registered_key = registry->_mungers.end(); 00041 #endif 00042 } 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: GeomMunger::Copy Constructor 00046 // Access: Public 00047 // Description: 00048 //////////////////////////////////////////////////////////////////// 00049 GeomMunger:: 00050 GeomMunger(const GeomMunger ©) : 00051 _is_registered(false) 00052 { 00053 #ifndef NDEBUG 00054 Registry *registry = get_registry(); 00055 LightReMutexHolder holder(registry->_registry_lock); 00056 _registered_key = registry->_mungers.end(); 00057 #endif 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: GeomMunger::Copy Assignment Operator 00062 // Access: Public 00063 // Description: 00064 //////////////////////////////////////////////////////////////////// 00065 void GeomMunger:: 00066 operator = (const GeomMunger ©) { 00067 nassertv(!_is_registered); 00068 } 00069 00070 //////////////////////////////////////////////////////////////////// 00071 // Function: GeomMunger::Destructor 00072 // Access: Public, Virtual 00073 // Description: 00074 //////////////////////////////////////////////////////////////////// 00075 GeomMunger:: 00076 ~GeomMunger() { 00077 unregister_myself(); 00078 nassertv(_formats_by_animation.empty()); 00079 } 00080 00081 //////////////////////////////////////////////////////////////////// 00082 // Function: GeomMunger::remove_data 00083 // Access: Public 00084 // Description: Removes a prepared GeomVertexData from the cache. 00085 //////////////////////////////////////////////////////////////////// 00086 void GeomMunger:: 00087 remove_data(const GeomVertexData *data) { 00088 // If this assertion is triggered, maybe we accidentally deleted a 00089 // GeomVertexData while we were in the process of unregistering, 00090 // causing a recursive re-entry. 00091 nassertv(_is_registered); 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: GeomMunger::munge_geom 00096 // Access: Public 00097 // Description: Applies the indicated munger to the geom and its 00098 // data, and returns a (possibly different) geom and 00099 // data, according to the munger's whim. 00100 // 00101 // The assumption is that for a particular geom and a 00102 // particular munger, the result will always be the 00103 // same; so this result may be cached. 00104 // 00105 // If force is false, this may do nothing and return 00106 // false if the vertex data is nonresident. If force is 00107 // true, this will always return true, but it may have 00108 // to block while the vertex data is paged in. 00109 //////////////////////////////////////////////////////////////////// 00110 bool GeomMunger:: 00111 munge_geom(CPT(Geom) &geom, CPT(GeomVertexData) &data, 00112 bool force, Thread *current_thread) { 00113 CPT(GeomVertexData) source_data = data; 00114 00115 // Look up the munger in the geom's cache--maybe we've recently 00116 // applied it. 00117 PT(Geom::CacheEntry) entry; 00118 00119 Geom::CacheKey key(source_data, this); 00120 00121 geom->_cache_lock.acquire(); 00122 Geom::Cache::const_iterator ci = geom->_cache.find(&key); 00123 if (ci == geom->_cache.end()) { 00124 geom->_cache_lock.release(); 00125 } else { 00126 entry = (*ci).second; 00127 geom->_cache_lock.release(); 00128 nassertr(entry->_source == geom, false); 00129 00130 // Here's an element in the cache for this computation. Record a 00131 // cache hit, so this element will stay in the cache a while 00132 // longer. 00133 entry->refresh(current_thread); 00134 00135 // Now check that it's fresh. 00136 Geom::CDCacheReader cdata(entry->_cycler, current_thread); 00137 if (cdata->_source == geom && 00138 cdata->_geom_result != (Geom *)NULL && 00139 geom->get_modified(current_thread) <= cdata->_geom_result->get_modified(current_thread) && 00140 data->get_modified(current_thread) <= cdata->_data_result->get_modified(current_thread)) { 00141 // The cache entry is still good; use it. 00142 00143 geom = cdata->_geom_result; 00144 data = cdata->_data_result; 00145 return true; 00146 } 00147 00148 // The cache entry is stale, but we'll recompute it below. Note 00149 // that there's a small race condition here; another thread might 00150 // recompute the cache at the same time. No big deal, since it'll 00151 // compute the same result. 00152 } 00153 00154 if (!force && (!geom->request_resident() || !data->request_resident())) { 00155 // Oh dear, the data isn't resident. We can't munge it, so give up. 00156 return false; 00157 } 00158 00159 // Ok, invoke the munger. 00160 PStatTimer timer(_munge_pcollector, current_thread); 00161 00162 PT(Geom) orig_geom = (Geom *)geom.p(); 00163 data = munge_data(data); 00164 munge_geom_impl(geom, data, current_thread); 00165 00166 // Record the new result in the cache. 00167 if (entry == (Geom::CacheEntry *)NULL) { 00168 // Create a new entry for the result. 00169 entry = new Geom::CacheEntry(orig_geom, source_data, this); 00170 { 00171 LightMutexHolder holder(orig_geom->_cache_lock); 00172 bool inserted = orig_geom->_cache.insert(Geom::Cache::value_type(&entry->_key, entry)).second; 00173 if (!inserted) { 00174 // Some other thread must have beat us to the punch. Never 00175 // mind. 00176 return true; 00177 } 00178 } 00179 00180 // And tell the cache manager about the new entry. (It might 00181 // immediately request a delete from the cache of the thing we 00182 // just added.) 00183 entry->record(current_thread); 00184 } 00185 00186 // Finally, store the cached result on the entry. 00187 Geom::CDCacheWriter cdata(entry->_cycler, true, current_thread); 00188 cdata->_source = (Geom *)orig_geom.p(); 00189 cdata->set_result(geom, data); 00190 00191 return true; 00192 } 00193 00194 //////////////////////////////////////////////////////////////////// 00195 // Function: GeomMunger::do_munge_format 00196 // Access: Protected 00197 // Description: The protected implementation of munge_format(). This 00198 // exists just to cast away the const pointer. 00199 //////////////////////////////////////////////////////////////////// 00200 CPT(GeomVertexFormat) GeomMunger:: 00201 do_munge_format(const GeomVertexFormat *format, 00202 const GeomVertexAnimationSpec &animation) { 00203 nassertr(_is_registered, NULL); 00204 nassertr(format->is_registered(), NULL); 00205 00206 LightMutexHolder holder(_formats_lock); 00207 00208 Formats &formats = _formats_by_animation[animation]; 00209 00210 Formats::iterator fi; 00211 fi = formats.find(format); 00212 if (fi != formats.end()) { 00213 // This format was previously munged, so the answer will be the 00214 // same. 00215 return (*fi).second; 00216 } 00217 00218 // We have to munge this format for the first time. 00219 CPT(GeomVertexFormat) derived_format = munge_format_impl(format, animation); 00220 nassertr(derived_format->is_registered(), NULL); 00221 00222 // Store the answer in the map, so we can quickly get it next time. 00223 bool inserted = formats.insert(Formats::value_type(format, derived_format)).second; 00224 nassertr(inserted, NULL); 00225 00226 return derived_format; 00227 } 00228 00229 //////////////////////////////////////////////////////////////////// 00230 // Function: GeomMunger::munge_format_impl 00231 // Access: Protected, Virtual 00232 // Description: Given a source GeomVertexFormat, converts it if 00233 // necessary to the appropriate format for rendering. 00234 //////////////////////////////////////////////////////////////////// 00235 CPT(GeomVertexFormat) GeomMunger:: 00236 munge_format_impl(const GeomVertexFormat *orig, const GeomVertexAnimationSpec &) { 00237 return orig; 00238 } 00239 00240 //////////////////////////////////////////////////////////////////// 00241 // Function: GeomMunger::munge_data_impl 00242 // Access: Protected, Virtual 00243 // Description: Given a source GeomVertexData, converts it as 00244 // necessary for rendering. 00245 //////////////////////////////////////////////////////////////////// 00246 CPT(GeomVertexData) GeomMunger:: 00247 munge_data_impl(const GeomVertexData *data) { 00248 nassertr(_is_registered, NULL); 00249 00250 CPT(GeomVertexFormat) orig_format = data->get_format(); 00251 CPT(GeomVertexFormat) new_format = 00252 munge_format(orig_format, orig_format->get_animation()); 00253 00254 if (new_format == orig_format) { 00255 // Trivial case. 00256 return data; 00257 } 00258 00259 return data->convert_to(new_format); 00260 } 00261 00262 //////////////////////////////////////////////////////////////////// 00263 // Function: GeomMunger::munge_geom_impl 00264 // Access: Protected, Virtual 00265 // Description: Converts a Geom and/or its data as necessary. 00266 //////////////////////////////////////////////////////////////////// 00267 void GeomMunger:: 00268 munge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &, Thread *) { 00269 // The default implementation does nothing (the work has already 00270 // been done in munge_format_impl() and munge_data_impl()). 00271 } 00272 00273 //////////////////////////////////////////////////////////////////// 00274 // Function: GeomMunger::do_premunge_format 00275 // Access: Protected 00276 // Description: The protected implementation of premunge_format(). This 00277 // exists just to cast away the const pointer. 00278 //////////////////////////////////////////////////////////////////// 00279 CPT(GeomVertexFormat) GeomMunger:: 00280 do_premunge_format(const GeomVertexFormat *format) { 00281 nassertr(_is_registered, NULL); 00282 nassertr(format->is_registered(), NULL); 00283 00284 LightMutexHolder holder(_formats_lock); 00285 00286 Formats::iterator fi; 00287 fi = _premunge_formats.find(format); 00288 if (fi != _premunge_formats.end()) { 00289 // This format was previously munged, so the answer will be the 00290 // same. 00291 return (*fi).second; 00292 } 00293 00294 // We have to munge this format for the first time. 00295 CPT(GeomVertexFormat) derived_format = premunge_format_impl(format); 00296 nassertr(derived_format->is_registered(), NULL); 00297 00298 // Store the answer in the map, so we can quickly get it next time. 00299 bool inserted = _premunge_formats.insert(Formats::value_type(format, derived_format)).second; 00300 nassertr(inserted, NULL); 00301 00302 return derived_format; 00303 } 00304 00305 //////////////////////////////////////////////////////////////////// 00306 // Function: GeomMunger::premunge_format_impl 00307 // Access: Protected, Virtual 00308 // Description: Given a source GeomVertexFormat, converts it if 00309 // necessary to the appropriate format for rendering. 00310 //////////////////////////////////////////////////////////////////// 00311 CPT(GeomVertexFormat) GeomMunger:: 00312 premunge_format_impl(const GeomVertexFormat *orig) { 00313 return orig; 00314 } 00315 00316 //////////////////////////////////////////////////////////////////// 00317 // Function: GeomMunger::premunge_data_impl 00318 // Access: Protected, Virtual 00319 // Description: Given a source GeomVertexData, converts it as 00320 // necessary for rendering. 00321 //////////////////////////////////////////////////////////////////// 00322 CPT(GeomVertexData) GeomMunger:: 00323 premunge_data_impl(const GeomVertexData *data) { 00324 nassertr(_is_registered, NULL); 00325 00326 CPT(GeomVertexFormat) orig_format = data->get_format(); 00327 CPT(GeomVertexFormat) new_format = premunge_format(orig_format); 00328 00329 if (new_format == orig_format) { 00330 // Trivial case. 00331 return data; 00332 } 00333 00334 return data->convert_to(new_format); 00335 } 00336 00337 //////////////////////////////////////////////////////////////////// 00338 // Function: GeomMunger::premunge_geom_impl 00339 // Access: Protected, Virtual 00340 // Description: Converts a Geom and/or its data as necessary. 00341 //////////////////////////////////////////////////////////////////// 00342 void GeomMunger:: 00343 premunge_geom_impl(CPT(Geom) &, CPT(GeomVertexData) &) { 00344 // The default implementation does nothing (the work has already 00345 // been done in premunge_format_impl() and premunge_data_impl()). 00346 } 00347 00348 //////////////////////////////////////////////////////////////////// 00349 // Function: GeomMunger::compare_to_impl 00350 // Access: Protected, Virtual 00351 // Description: Called to compare two GeomMungers who are known to be 00352 // of the same type, for an apples-to-apples comparison. 00353 // This will never be called on two pointers of a 00354 // different type. 00355 //////////////////////////////////////////////////////////////////// 00356 int GeomMunger:: 00357 compare_to_impl(const GeomMunger *other) const { 00358 return 0; 00359 } 00360 00361 //////////////////////////////////////////////////////////////////// 00362 // Function: GeomMunger::geom_compare_to_impl 00363 // Access: Protected, Virtual 00364 // Description: Compares two GeomMungers, considering only whether 00365 // they would produce a different answer to 00366 // munge_format(), munge_data(), or munge_geom(). (They 00367 // still might be different in other ways, but if they 00368 // would produce the same answer, this function will 00369 // consider them to be the same.) 00370 //////////////////////////////////////////////////////////////////// 00371 int GeomMunger:: 00372 geom_compare_to_impl(const GeomMunger *other) const { 00373 return 0; 00374 } 00375 00376 //////////////////////////////////////////////////////////////////// 00377 // Function: GeomMunger::make_registry 00378 // Access: Private 00379 // Description: Returns the global registry object. 00380 //////////////////////////////////////////////////////////////////// 00381 void GeomMunger:: 00382 make_registry() { 00383 if (_registry == (Registry *)NULL) { 00384 _registry = new Registry; 00385 } 00386 } 00387 00388 //////////////////////////////////////////////////////////////////// 00389 // Function: GeomMunger::do_register 00390 // Access: Private 00391 // Description: Called internally when the munger is registered. 00392 //////////////////////////////////////////////////////////////////// 00393 void GeomMunger:: 00394 do_register(Thread *current_thread) { 00395 if (gobj_cat.is_debug()) { 00396 gobj_cat.debug() 00397 << "GeomMunger::do_register(): " << (void *)this << "\n"; 00398 } 00399 nassertv(!_is_registered); 00400 nassertv(_formats_by_animation.empty()); 00401 00402 // Tell the cache manager to hang on to this new GeomMunger, so we 00403 // don't waste our time re-registering the same GeomMunger over and 00404 // over again. 00405 CacheEntry *entry = new CacheEntry; 00406 entry->_munger = this; 00407 entry->record(current_thread); 00408 00409 _is_registered = true; 00410 } 00411 00412 //////////////////////////////////////////////////////////////////// 00413 // Function: GeomMunger::do_unregister 00414 // Access: Private 00415 // Description: Called internally when the munger is unregistered. 00416 //////////////////////////////////////////////////////////////////// 00417 void GeomMunger:: 00418 do_unregister() { 00419 if (gobj_cat.is_debug()) { 00420 gobj_cat.debug() 00421 << "GeomMunger::do_unregister(): " << (void *)this << "\n"; 00422 } 00423 nassertv(_is_registered); 00424 _is_registered = false; 00425 00426 // Unregistering means we should blow away the cache. 00427 _formats_by_animation.clear(); 00428 } 00429 00430 //////////////////////////////////////////////////////////////////// 00431 // Function: GeomMunger::CacheEntry::output 00432 // Access: Public, Virtual 00433 // Description: 00434 //////////////////////////////////////////////////////////////////// 00435 void GeomMunger::CacheEntry:: 00436 output(ostream &out) const { 00437 out << "munger " << _munger; 00438 } 00439 00440 //////////////////////////////////////////////////////////////////// 00441 // Function: GeomMunger::Registry::Constructor 00442 // Access: Public 00443 // Description: 00444 //////////////////////////////////////////////////////////////////// 00445 GeomMunger::Registry:: 00446 Registry() { 00447 } 00448 00449 //////////////////////////////////////////////////////////////////// 00450 // Function: GeomMunger::Registry::register_munger 00451 // Access: Public 00452 // Description: Adds the indicated munger to the registry, if there 00453 // is not an equivalent munger already there; in either 00454 // case, returns the pointer to the equivalent munger 00455 // now in the registry. 00456 // 00457 // This must be called before a munger may be used in a 00458 // Geom. After this call, you should discard the 00459 // original pointer you passed in (which may or may not 00460 // now be invalid) and let its reference count decrement 00461 // normally; you should use only the returned value from 00462 // this point on. 00463 //////////////////////////////////////////////////////////////////// 00464 PT(GeomMunger) GeomMunger::Registry:: 00465 register_munger(GeomMunger *munger, Thread *current_thread) { 00466 if (munger->is_registered()) { 00467 return munger; 00468 } 00469 00470 // Save the incoming pointer in a local PointerTo, so that if it has 00471 // a zero reference count and is not added into the map below, it 00472 // will be automatically deleted when this function returns. 00473 PT(GeomMunger) pt_munger = munger; 00474 00475 LightReMutexHolder holder(_registry_lock); 00476 00477 Mungers::iterator mi = _mungers.insert(munger).first; 00478 GeomMunger *new_munger = (*mi); 00479 if (!new_munger->is_registered()) { 00480 new_munger->_registered_key = mi; 00481 new_munger->do_register(current_thread); 00482 } 00483 00484 return new_munger; 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: GeomMunger::Registry::unregister_munger 00489 // Access: Public 00490 // Description: Removes the indicated munger from the registry. 00491 // Normally this should not be done until the munger is 00492 // destructing. 00493 //////////////////////////////////////////////////////////////////// 00494 void GeomMunger::Registry:: 00495 unregister_munger(GeomMunger *munger) { 00496 LightReMutexHolder holder(_registry_lock); 00497 00498 nassertv(munger->is_registered()); 00499 nassertv(munger->_registered_key != _mungers.end()); 00500 _mungers.erase(munger->_registered_key); 00501 munger->_registered_key = _mungers.end(); 00502 munger->do_unregister(); 00503 } 00504 00505 //////////////////////////////////////////////////////////////////// 00506 // Function: GeomMunger::Registry::unregister_mungers_for_gsg 00507 // Access: Public 00508 // Description: Removes all the mungers from the registry that are 00509 // associated with the indicated GSG. 00510 //////////////////////////////////////////////////////////////////// 00511 void GeomMunger::Registry:: 00512 unregister_mungers_for_gsg(GraphicsStateGuardianBase *gsg) { 00513 LightReMutexHolder holder(_registry_lock); 00514 00515 Mungers::iterator mi = _mungers.begin(); 00516 while (mi != _mungers.end()) { 00517 GeomMunger *munger = (*mi); 00518 Mungers::iterator mnext = mi; 00519 ++mnext; 00520 00521 if (munger->get_gsg() == gsg) { 00522 nassertv(mi == munger->_registered_key); 00523 _mungers.erase(mi); 00524 munger->_registered_key = _mungers.end(); 00525 munger->do_unregister(); 00526 } 00527 00528 mi = mnext; 00529 } 00530 }