threaded model loads

This commit is contained in:
David Rose
2006-08-22 15:33:51 +00:00
parent 4ebff51ec0
commit 1f1761da76
25 changed files with 752 additions and 779 deletions
-3
View File
@@ -10,7 +10,6 @@
#define SOURCES \
config_downloader.h \
asyncUtility.I asyncUtility.h \
bioPtr.I bioPtr.h \
bioStreamPtr.I bioStreamPtr.h \
bioStream.I bioStream.h bioStreamBuf.h \
@@ -39,7 +38,6 @@
#define INCLUDED_SOURCES \
config_downloader.cxx \
asyncUtility.cxx \
bioPtr.cxx \
bioStreamPtr.cxx \
bioStream.cxx bioStreamBuf.cxx \
@@ -66,7 +64,6 @@
urlSpec.cxx
#define INSTALL_HEADERS \
asyncUtility.h asyncUtility.I \
bioPtr.I bioPtr.h \
bioStreamPtr.I bioStreamPtr.h \
bioStream.I bioStream.h bioStreamBuf.h \
-37
View File
@@ -1,37 +0,0 @@
// Filename: asyncUtility.I
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::set_frequency
// Access: Public
// Description: Fraction of a second.
////////////////////////////////////////////////////////////////////
INLINE void AsyncUtility::
set_frequency(float frequency) {
_frequency = frequency;
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::get_frequency
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE float AsyncUtility::
get_frequency() const {
return _frequency;
}
-161
View File
@@ -1,161 +0,0 @@
// Filename: asyncUtility.cxx
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "config_downloader.h"
#include "asyncUtility.h"
#if defined(WIN32)
#define WINDOWS_LEAN_AND_MEAN
#include <wtypes.h>
#undef WINDOWS_LEAN_AND_MEAN
#else
#include <sys/time.h>
#endif
////////////////////////////////////////////////////////////////////
// Defines
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AsyncUtility::
AsyncUtility(float frequency) : _frequency(frequency) {
_next_token = 1;
_shutdown = false;
_threaded = false;
_threads_enabled = true;
#ifdef OLD_HAVE_IPC
_request_cond = new condition_variable(_lock);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
AsyncUtility::
~AsyncUtility() {
#ifdef OLD_HAVE_IPC
delete _request_cond;
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::create_thread
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void AsyncUtility::
create_thread() {
#ifdef OLD_HAVE_IPC
if (_threaded == false && _threads_enabled == true) {
downloader_cat.debug()
<< "AsyncUtility::create_thread()" << endl;
_thread = thread::create(&st_callback, this, thread::PRIORITY_NORMAL);
_threaded = true;
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::destroy_thread
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void AsyncUtility::
destroy_thread() {
#ifdef OLD_HAVE_IPC
if (_threaded == false)
return;
// Tell the thread to shut itself down.
// We need to grab the lock in order to signal the condition variable
_lock.lock();
_shutdown = true;
_request_cond->signal();
_lock.unlock();
// Join the loader thread - calling process blocks until the loader
// thread returns.
void *ret;
_thread->join(&ret);
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::st_callback
// Access: Protected, Static
// Description: This is a static wrapper around the callback()
// method, below. It's static just so we can pass it to
// the thread-creation function. In addition, the
// function has a void* return type even though we
// don't actually return anything. This is necessary
// because ipc assumes a function that does not return
// anything indicates that the associated thread should
// be created as unjoinable (detached).
////////////////////////////////////////////////////////////////////
void* AsyncUtility::
st_callback(void *arg) {
#ifdef OLD_HAVE_IPC
nassertr(arg != NULL, NULL);
((AsyncUtility *)arg)->callback();
#endif
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::callback
// Access: Protected
// Description: This is the main body of the sub-thread. It waits
// forever for a request to show up, and then serves it.
////////////////////////////////////////////////////////////////////
void AsyncUtility::
callback() {
#ifdef OLD_HAVE_IPC
while (process_request()) {
// Sleep until a signal arrives
_lock.lock();
_request_cond->wait();
_lock.unlock();
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: AsyncUtility::nap
// Access: Protected
// Description:
////////////////////////////////////////////////////////////////////
void AsyncUtility::
nap() const {
#ifdef OLD_HAVE_IPC
#ifdef WIN32
_sleep((DWORD)(1000 * _frequency));
#else
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = (long)(1000000 * _frequency);
select(0, NULL, NULL, NULL, &tv);
#endif
#endif // OLD_HAVE_IPC
}
-73
View File
@@ -1,73 +0,0 @@
// Filename: asyncUtility.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef ASYNCUTILITY_H
#define ASYNCUTILITY_H
//
////////////////////////////////////////////////////////////////////
// Includes
////////////////////////////////////////////////////////////////////
#include "pandabase.h"
#include "pnotify.h"
#include "typedef.h"
#ifdef OLD_HAVE_IPC
#include <ipc_mutex.h>
#include <ipc_condition.h>
#include <ipc_thread.h>
#endif
////////////////////////////////////////////////////////////////////
// Class : AsyncUtility
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS AsyncUtility {
PUBLISHED:
INLINE void set_frequency(float frequency);
INLINE float get_frequency() const;
void create_thread();
public:
AsyncUtility(float frequency = 0.2);
virtual ~AsyncUtility();
protected:
void destroy_thread();
static void* st_callback(void *arg);
void callback();
virtual bool process_request() = 0;
void nap() const;
protected:
int _next_token;
bool _shutdown;
bool _threaded;
float _frequency;
bool _threads_enabled;
#ifdef OLD_HAVE_IPC
mutex _lock;
condition_variable *_request_cond;
thread *_thread;
#endif
};
#include "asyncUtility.I"
#endif
@@ -1,4 +1,3 @@
#include "asyncUtility.cxx"
#include "bioPtr.cxx"
#include "bioStream.cxx"
#include "bioStreamBuf.cxx"
+2 -4
View File
@@ -52,8 +52,7 @@
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h \
trueClock.I trueClock.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \
unicodeLatinMap.h \
vector_uchar.h \
@@ -164,8 +163,7 @@
textEncoder.h textEncoder.I \
threadSafePointerTo.I threadSafePointerTo.h \
threadSafePointerToBase.I threadSafePointerToBase.h \
tokenBoard.I \
tokenBoard.h trueClock.I trueClock.h \
trueClock.I trueClock.h \
typedReferenceCount.I typedReferenceCount.h typedef.h \
unicodeLatinMap.h \
vector_uchar.h \
-78
View File
@@ -1,78 +0,0 @@
// Filename: tokenBoard.I
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TokenBoard::is_done_token()
// Access: Public
// Description: Returns true if the indicated token id is on the
// done queue, false otherwise.
////////////////////////////////////////////////////////////////////
template<class TokenType>
bool TokenBoard<TokenType>::
is_done_token(int id) {
// First, empty the done list, copying them to really_done. We have
// to do this since we can only examine tokens on the head of the
// done list, and the token we're looking for might not be at the
// head.
while (!_done.empty()) {
_really_done.push_back(_done.front());
_done.pop_front();
}
// Now we can search really_done for our desired id.
TYPENAME plist< PT(TokenType) >::iterator found;
found = find_if(_really_done.begin(), _really_done.end(),
TokenMatch<TokenType>(id));
return (found != _really_done.end());
}
////////////////////////////////////////////////////////////////////
// Function: TokenBoard::get_done_token
// Access: Public
// Description: Locates the token by the given id in the list of done
// tokens, removes it from the list, and returns its
// pointer (which should be deleted by the calling
// function). Returns NULL if the token was not on the
// done list.
////////////////////////////////////////////////////////////////////
template<class TokenType>
PT(TokenType) TokenBoard<TokenType>::
get_done_token(int id) {
// First, empty the done list, copying them to really_done. We have
// to do this since we can only examine tokens on the head of the
// done list, and the token we're looking for might not be at the
// head.
while (!_done.empty()) {
_really_done.push_back(_done.front());
_done.pop_front();
}
// Now we can search really_done for our desired id.
TYPENAME plist< PT(TokenType) >::iterator found;
found = find_if(_really_done.begin(), _really_done.end(),
TokenMatch<TokenType>(id));
if (found == _really_done.end()) {
return NULL;
} else {
PT(TokenType) tok = *found;
_really_done.erase(found);
return tok;
}
}
-76
View File
@@ -1,76 +0,0 @@
// Filename: tokenBoard.h
// Created by: mike (09Jan97)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef TOKENBOARD_H
#define TOKENBOARD_H
#include "pandabase.h"
#include "plist.h"
#include "circBuffer.h"
#include "pointerTo.h"
////////////////////////////////////////////////////////////////////
// Struct : TokenMatch
// Description : This is an STL predicate function object that is used
// to find a particular id in a list of token pointers.
// It returns true when the token's id matches the
// numeric id supplied to the constructor.
////////////////////////////////////////////////////////////////////
template<class TokenType>
class TokenMatch {
public:
TokenMatch(int id) {
_want_id = id;
}
bool operator()(PT(TokenType) tok) const {
return (int)tok->_id == _want_id;
}
int _want_id;
};
const int MAX_TOKENBOARD_REQUESTS = 100;
////////////////////////////////////////////////////////////////////
// Class : TokenBoard
// Description :
////////////////////////////////////////////////////////////////////
template<class TokenType>
class TokenBoard {
public:
bool is_done_token(int id);
PT(TokenType) get_done_token(int id);
// waiting holds the list of requests sent to the DBASE process, not
// yet handled.
CircBuffer<PT(TokenType), MAX_TOKENBOARD_REQUESTS> _waiting;
// done holds the list of requests handled by the DBASE process, but
// not yet discovered by APP. Probably this queue will only have
// one item at a time on it.
CircBuffer<PT(TokenType), MAX_TOKENBOARD_REQUESTS> _done;
// really_done holds the requests extracted from done. These are
// extracted into the local list so we can safely search for and
// remove a particular token from the middle of the list (we can
// only remove from the head of a circular buffer).
plist< PT(TokenType) > _really_done;
};
#include "tokenBoard.I"
#endif
+7 -1
View File
@@ -18,7 +18,7 @@
#include "materialPool.h"
#include "config_gobj.h"
#include "mutexHolder.h"
MaterialPool *MaterialPool::_global_ptr = (MaterialPool *)NULL;
@@ -41,6 +41,8 @@ write(ostream &out) {
////////////////////////////////////////////////////////////////////
Material *MaterialPool::
ns_get_material(Material *temp) {
MutexHolder holder(_lock);
CPT(Material) cpttemp = temp;
Materials::iterator mi = _materials.find(cpttemp);
if (mi == _materials.end()) {
@@ -62,6 +64,8 @@ ns_get_material(Material *temp) {
////////////////////////////////////////////////////////////////////
int MaterialPool::
ns_garbage_collect() {
MutexHolder holder(_lock);
int num_released = 0;
Materials new_set;
@@ -91,6 +95,8 @@ ns_garbage_collect() {
////////////////////////////////////////////////////////////////////
void MaterialPool::
ns_list_contents(ostream &out) const {
MutexHolder holder(_lock);
out << _materials.size() << " materials:\n";
Materials::const_iterator mi;
for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
+3 -3
View File
@@ -20,11 +20,9 @@
#define MATERIALPOOL_H
#include "pandabase.h"
#include "material.h"
#include "pointerTo.h"
#include "pmutex.h"
#include "pset.h"
////////////////////////////////////////////////////////////////////
@@ -63,6 +61,8 @@ private:
static MaterialPool *_global_ptr;
Mutex _lock;
// We store a map of CPT(Material) to PT(Material). These are two
// equivalent structures, but different pointers. The first pointer
// never leaves this class. If the second pointer changes value,
+129 -28
View File
@@ -28,6 +28,7 @@
#include "texturePoolFilter.h"
#include "configVariableList.h"
#include "load_dso.h"
#include "mutexHolder.h"
TexturePool *TexturePool::_global_ptr;
@@ -54,6 +55,8 @@ write(ostream &out) {
////////////////////////////////////////////////////////////////////
void TexturePool::
register_texture_type(MakeTextureFunc *func, const string &extensions) {
MutexHolder holder(_lock);
vector_string words;
extract_words(downcase(extensions), words);
@@ -71,6 +74,8 @@ register_texture_type(MakeTextureFunc *func, const string &extensions) {
////////////////////////////////////////////////////////////////////
void TexturePool::
register_filter(TexturePoolFilter *filter) {
MutexHolder holder(_lock);
gobj_cat.info()
<< "Registering Texture filter " << *filter << "\n";
_filter_registry.push_back(filter);
@@ -86,6 +91,8 @@ register_filter(TexturePoolFilter *filter) {
////////////////////////////////////////////////////////////////////
TexturePool::MakeTextureFunc *TexturePool::
get_texture_type(const string &extension) const {
MutexHolder holder(_lock);
string c = downcase(extension);
TypeRegistry::const_iterator ti;
ti = _type_registry.find(extension);
@@ -136,6 +143,8 @@ make_texture(const string &extension) const {
////////////////////////////////////////////////////////////////////
void TexturePool::
write_texture_types(ostream &out, int indent_level) const {
MutexHolder holder(_lock);
PNMFileTypeRegistry *pnm_reg = PNMFileTypeRegistry::get_global_ptr();
pnm_reg->write(out, indent_level);
@@ -201,6 +210,8 @@ TexturePool() {
////////////////////////////////////////////////////////////////////
bool TexturePool::
ns_has_texture(const Filename &orig_filename) {
MutexHolder holder(_lock);
Filename filename(orig_filename);
if (!_fake_texture_image.empty()) {
@@ -239,13 +250,16 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
vfs->resolve_filename(filename, get_texture_path()) ||
vfs->resolve_filename(filename, get_model_path());
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
{
MutexHolder holder(_lock);
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
}
}
// The texture was not found in the pool.
@@ -293,7 +307,23 @@ ns_load_texture(const Filename &orig_filename, int primary_file_num_channels,
tex->set_filename(orig_filename);
tex->set_fullpath(filename);
tex->_texture_pool_key = filename;
_textures[filename] = tex;
{
MutexHolder holder(_lock);
// Now look again--someone may have just loaded this texture in
// another thread.
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
}
_textures[filename] = tex;
}
if (store_record) {
// Store the on-disk cache record for next time.
@@ -335,13 +365,17 @@ ns_load_texture(const Filename &orig_filename,
vfs->resolve_filename(alpha_filename, get_texture_path()) ||
vfs->resolve_filename(alpha_filename, get_model_path());
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
{
MutexHolder holder(_lock);
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
}
}
PT(Texture) tex;
@@ -393,7 +427,22 @@ ns_load_texture(const Filename &orig_filename,
tex->set_alpha_filename(orig_alpha_filename);
tex->set_alpha_fullpath(alpha_filename);
tex->_texture_pool_key = filename;
_textures[filename] = tex;
{
MutexHolder holder(_lock);
// Now look again.
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
Texture *tex = (*ti).second;
nassertr(!tex->get_fullpath().empty(), tex);
return tex;
}
_textures[filename] = tex;
}
if (store_record) {
// Store the on-disk cache record for next time.
@@ -424,11 +473,15 @@ ns_load_3d_texture(const Filename &filename_pattern,
vfs->resolve_filename(filename, get_texture_path()) ||
vfs->resolve_filename(filename, get_model_path());
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
{
MutexHolder holder(_lock);
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
}
}
PT(Texture) tex;
@@ -470,7 +523,20 @@ ns_load_3d_texture(const Filename &filename_pattern,
tex->set_filename(filename_pattern);
tex->set_fullpath(filename);
tex->_texture_pool_key = filename;
_textures[filename] = tex;
{
MutexHolder holder(_lock);
// Now look again.
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
}
_textures[filename] = tex;
}
if (store_record) {
// Store the on-disk cache record for next time.
@@ -496,11 +562,15 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
vfs->resolve_filename(filename, get_texture_path()) ||
vfs->resolve_filename(filename, get_model_path());
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
{
MutexHolder holder(_lock);
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
}
}
PT(Texture) tex;
@@ -542,7 +612,20 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
tex->set_filename(filename_pattern);
tex->set_fullpath(filename);
tex->_texture_pool_key = filename;
_textures[filename] = tex;
{
MutexHolder holder(_lock);
// Now look again.
Textures::const_iterator ti;
ti = _textures.find(filename);
if (ti != _textures.end()) {
// This texture was previously loaded.
return (*ti).second;
}
_textures[filename] = tex;
}
if (store_record) {
// Store the on-disk cache record for next time.
@@ -561,6 +644,8 @@ ns_load_cube_map(const Filename &filename_pattern, bool read_mipmaps) {
////////////////////////////////////////////////////////////////////
Texture *TexturePool::
ns_get_normalization_cube_map(int size) {
MutexHolder holder(_lock);
if (_normalization_cube_map == (Texture *)NULL) {
_normalization_cube_map = new Texture("normalization_cube_map");
}
@@ -580,6 +665,8 @@ ns_get_normalization_cube_map(int size) {
void TexturePool::
ns_add_texture(Texture *tex) {
PT(Texture) keep = tex;
MutexHolder holder(_lock);
if (!tex->_texture_pool_key.empty()) {
ns_release_texture(tex);
}
@@ -601,6 +688,8 @@ ns_add_texture(Texture *tex) {
////////////////////////////////////////////////////////////////////
void TexturePool::
ns_release_texture(Texture *tex) {
MutexHolder holder(_lock);
if (!tex->_texture_pool_key.empty()) {
Textures::iterator ti;
ti = _textures.find(tex->_texture_pool_key);
@@ -618,6 +707,8 @@ ns_release_texture(Texture *tex) {
////////////////////////////////////////////////////////////////////
void TexturePool::
ns_release_all_textures() {
MutexHolder holder(_lock);
Textures::iterator ti;
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
Texture *tex = (*ti).second;
@@ -635,6 +726,8 @@ ns_release_all_textures() {
////////////////////////////////////////////////////////////////////
int TexturePool::
ns_garbage_collect() {
MutexHolder holder(_lock);
int num_released = 0;
Textures new_set;
@@ -675,6 +768,8 @@ ns_garbage_collect() {
////////////////////////////////////////////////////////////////////
void TexturePool::
ns_list_contents(ostream &out) const {
MutexHolder holder(_lock);
out << _textures.size() << " textures:\n";
Textures::const_iterator ti;
for (ti = _textures.begin(); ti != _textures.end(); ++ti) {
@@ -741,6 +836,8 @@ pre_load(const Filename &orig_filename, const Filename &orig_alpha_filename,
bool read_mipmaps) {
PT(Texture) tex;
MutexHolder holder(_lock);
FilterRegistry::iterator fi;
for (fi = _filter_registry.begin();
fi != _filter_registry.end();
@@ -765,6 +862,8 @@ PT(Texture) TexturePool::
post_load(Texture *tex) {
PT(Texture) result = tex;
MutexHolder holder(_lock);
FilterRegistry::iterator fi;
for (fi = _filter_registry.begin();
fi != _filter_registry.end();
@@ -784,6 +883,8 @@ post_load(Texture *tex) {
////////////////////////////////////////////////////////////////////
void TexturePool::
load_filters() {
MutexHolder holder(_lock);
ConfigVariableList texture_filter
("texture-filter",
PRC_DESC("Names one or more external libraries that should be loaded for the "
+3 -1
View File
@@ -23,7 +23,7 @@
#include "texture.h"
#include "filename.h"
#include "config_gobj.h"
#include "pmutex.h"
#include "pmap.h"
class TexturePoolFilter;
@@ -121,6 +121,8 @@ private:
void load_filters();
static TexturePool *_global_ptr;
Mutex _lock;
typedef phash_map<string, PT(Texture), string_hash> Textures;
Textures _textures;
string _fake_texture_image;
+288 -196
View File
@@ -20,7 +20,7 @@
#include "loaderFileType.h"
#include "loaderFileTypeRegistry.h"
#include "config_pgraph.h"
#include "modelPool.h"
#include "config_express.h"
#include "config_util.h"
#include "virtualFileSystem.h"
@@ -28,62 +28,68 @@
#include "pt_Event.h"
#include "throw_event.h"
#include "eventParameter.h"
#include "circBuffer.h"
#include "filename.h"
#include "load_dso.h"
#include "string_utils.h"
#include "plist.h"
#include "pvector.h"
#include "bamCache.h"
#include "bamCacheRecord.h"
#include "mutexHolder.h"
#include <algorithm>
bool Loader::_file_types_loaded = false;
////////////////////////////////////////////////////////////////////
// Struct : LoaderToken
// Description : Holds a request for the loader (load or delete), as
// well as the return information after the request has
// completed.
////////////////////////////////////////////////////////////////////
class LoaderToken : public ReferenceCount {
public:
INLINE LoaderToken(uint id, const string &event_name, const Filename &path,
bool search, PandaNode *node=NULL) :
_id(id),
_event_name(event_name),
_path(path),
_search(search),
_node(node)
{ }
uint _id;
string _event_name;
Filename _path;
bool _search;
PT(PandaNode) _node;
};
////////////////////////////////////////////////////////////////////
// Function: Loader::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
Loader::
Loader() : AsyncUtility() {
_token_board = new LoaderTokenBoard;
Loader(const string &name, int num_threads) :
Namable(name),
_cvar(_lock)
{
_num_threads = num_threads;
if (_num_threads < 0) {
// -1 means the default number of threads.
ConfigVariableInt loader_num_threads
("loader-num-threads", 1,
PRC_DESC("The number of threads that will be started by the Loader class "
"to load models asynchronously. These threads will only be "
"started if the asynchronous interface is used, and if threading "
"support is compiled into Panda. The default is one thread, "
"which allows models to be loaded one at a time in a single "
"asychronous thread. You can set this higher, particularly if "
"you have many CPU's available, to allow loading multiple models "
"simultaneously."));
_num_threads = loader_num_threads;
}
_next_id = 1;
_state = S_initial;
}
////////////////////////////////////////////////////////////////////
// Function: Loader::Destructor
// Access: Published
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
Loader::
~Loader() {
destroy_thread();
delete _token_board;
if (_state == S_started) {
// Clean up all of the threads.
MutexHolder holder(_lock);
_state = S_shutdown;
_cvar.signal();
Threads::iterator ti;
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
(*ti)->join();
}
}
}
////////////////////////////////////////////////////////////////////
@@ -189,83 +195,98 @@ find_all_files(const Filename &filename, const DSearchPath &search_path,
}
////////////////////////////////////////////////////////////////////
// Function: Loader::request_load
// Function: Loader::begin_request
// Access: Published
// Description: Requests an asynchronous load of a file. The request
// will be queued and served by the asynchronous thread.
// If event_name is nonempty, it is the name of the
// event that will be thrown (with the uint id as its
// single parameter) when the loading is completed later.
// Description: The first step of an asynchronous load request. This
// method slots a record to hold a new request for a
// model load, and returns a unique ID corresponding to
// that record.
//
// The return value is an integer which can be used to
// identify this particular request later to
// fetch_load(), or 0 if there has been an error.
// The parameter is the event name that is to be
// generated when the model is successfully loaded.
//
// If search is true, the file is searched for along the
// model path; otherwise, only the exact filename is
// loaded.
// The caller should record the new ID, and then call
// request_load() with the same ID.
////////////////////////////////////////////////////////////////////
uint Loader::
request_load(const string &event_name, const Filename &filename, bool search) {
int Loader::
begin_request(const string &event_name) {
if (!_file_types_loaded) {
load_file_types();
}
PT(LoaderToken) tok;
if (asynchronous_loads) {
LoaderRequest *request = new LoaderRequest;
request->_event_name = event_name;
// Make sure we actually are threaded
if (!_threaded) {
loader_cat.info()
<< "Loader::request_load() - create_thread() was "
<< "never called! Calling it now..." << endl;
create_thread();
}
// We need to grab the lock in order to signal the condition variable
#ifdef OLD_HAVE_IPC
_lock.lock();
#endif
if (_token_board->_waiting.full()) {
loader_cat.error()
<< "Loader::request_load() - Too many pending requests\n";
return 0;
}
if (loader_cat.is_debug()) {
loader_cat.debug()
<< "Load requested for file: " << filename << "\n";
}
tok = new LoaderToken(_next_token++, event_name, filename, search);
_token_board->_waiting.push_back(tok);
#ifdef OLD_HAVE_IPC
_request_cond->signal();
_lock.unlock();
#endif
} else {
// If we're not running asynchronously, process the load request
// directly now.
if (_token_board->_waiting.full()) {
loader_cat.error()
<< "Loader::request_load() - Too many pending requests\n";
return 0;
}
if (loader_cat.is_debug()) {
loader_cat.debug()
<< "Load requested for file: " << filename << "\n";
}
tok = new LoaderToken(_next_token++, event_name, filename, search);
_token_board->_waiting.push_back(tok);
process_request();
{
MutexHolder holder(_lock);
request->_id = _next_id;
++_next_id;
_initial.push_back(request);
}
return tok->_id;
return request->_id;
}
////////////////////////////////////////////////////////////////////
// Function: Loader::request_load
// Access: Published
// Description: The second step of an asychronous load request. Once
// the caller has obtained a unique ID with
// begin_request(), it should then call request_load()
// to specify the actual filename that should be loaded.
//
// The model will be loaded in the background. When it
// is successfully loaded, the event name (specified to
// begin_request) will be generated, with one parameter:
// the ID of this request. At any point after that, the
// caller must then call fetch_load() to retrieve the
// requested model.
//
// Note that it is possible that the loaded event will
// be generated even before this function returns.
// Thus, it is necessary for the caller to save the ID
// and prepare its to receive the loaded event before
// making this call.
////////////////////////////////////////////////////////////////////
void Loader::
request_load(int id, const Filename &filename,
const LoaderOptions &options) {
MutexHolder holder(_lock);
int index = find_id(_initial, id);
if (index == -1) {
nassert_raise("No such loader ID.");
return;
}
LoaderRequest *request = _initial[index];
_initial.erase(_initial.begin() + index);
request->_filename = filename;
request->_options = options;
_pending.push_back(request);
_cvar.signal();
// Now try to start the thread(s).
if (_state == S_initial) {
_state = S_started;
if (Thread::is_threading_supported()) {
for (int i = 0; i < _num_threads; ++i) {
PT(LoaderThread) thread = new LoaderThread(this);
if (thread->start(TP_low, true, true)) {
_threads.push_back(thread);
}
}
}
}
if (_threads.empty()) {
// For some reason, we still have no threads--maybe we don't
// even have threading available. In that case, load the model
// by hand.
poll_loader();
}
}
////////////////////////////////////////////////////////////////////
@@ -275,126 +296,83 @@ request_load(const string &event_name, const Filename &filename, bool search) {
// completed and not yet been fetched, false otherwise.
////////////////////////////////////////////////////////////////////
bool Loader::
check_load(uint id) {
return _token_board->is_done_token(id);
check_load(int id) {
MutexHolder holder(_lock);
int index = find_id(_finished, id);
return (index != -1);
}
////////////////////////////////////////////////////////////////////
// Function: Loader::fetch_load
// Access: Published
// Description: Returns the Node associated with the indicated id
// Description: Returns the node associated with the indicated id
// number (returned by a previous call to request_load),
// or NULL if the request has not yet completed.
// or NULL if there was an error loading the model. It
// is illegal to call this if check_load() does not
// return true (and the caller has not received the
// finished event for this id).
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
fetch_load(uint id) {
PT(LoaderToken) tok = _token_board->get_done_token(id);
if (tok.is_null()) {
loader_cat.debug()
<< "Request to fetch id " << id << " which has not yet completed.\n";
fetch_load(int id) {
MutexHolder holder(_lock);
int index = find_id(_finished, id);
if (index == -1) {
nassert_raise("No such loader ID.");
return NULL;
}
PT(PandaNode) node = tok->_node;
return node;
LoaderRequest *request = _finished[index];
_finished.erase(_finished.begin() + index);
PT(PandaNode) model = request->_model;
delete request;
return model;
}
////////////////////////////////////////////////////////////////////
// Function: Loader::load_file_types
// Access: Private, Static
// Description: Loads up all of the dynamic libraries named in a
// load-file-type Configure variable. Presumably this
// will make the various file types available for
// runtime loading.
// Function: Loader::output
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void Loader::
load_file_types() {
if (!_file_types_loaded) {
int num_unique_values = load_file_type.get_num_unique_values();
output(ostream &out) const {
out << "Loader " << get_name();
for (int i = 0; i < num_unique_values; i++) {
string param = load_file_type.get_unique_value(i);
vector_string words;
extract_words(param, words);
if (words.size() == 1) {
// Exactly one word: load the named library immediately.
string name = words[0];
Filename dlname = Filename::dso_filename("lib" + name + ".so");
loader_cat.info()
<< "loading file type module: " << name << endl;
void *tmp = load_dso(dlname);
if (tmp == (void *)NULL) {
loader_cat.warning()
<< "Unable to load " << dlname.to_os_specific()
<< ": " << load_dso_error() << endl;
}
} else if (words.size() > 1) {
// Multiple words: the first n words are filename extensions,
// and the last word is the name of the library to load should
// any of those filename extensions be encountered.
LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_global_ptr();
size_t num_extensions = words.size() - 1;
string library_name = words[num_extensions];
for (size_t i = 0; i < num_extensions; i++) {
string extension = words[i];
if (extension[0] == '.') {
extension = extension.substr(1);
}
registry->register_deferred_type(extension, library_name);
}
}
}
_file_types_loaded = true;
if (_state == S_started) {
MutexHolder holder(_lock);
out << " " << _pending.size() << " pending, "
<< " " << _finished.size() << " finished.";
}
}
////////////////////////////////////////////////////////////////////
// Function: Loader::process_request
// Function: Loader::poll_loader
// Access: Private
// Description: Serves any requests on the token board, moving them
// to the done queue.
// Description: Called internally to empty the requests from the
// _pending queue. Assumes the lock is already held.
////////////////////////////////////////////////////////////////////
bool Loader::
process_request() {
if (_shutdown) {
if (loader_cat.is_debug())
loader_cat.debug()
<< "Loader shutting down...\n";
return false;
void Loader::
poll_loader() {
while (!_pending.empty()) {
LoaderRequest *request = _pending[0];
_pending.pop_front();
// Now release the lock while we load the model.
_lock.release();
request->_model = load_file(request->_filename, request->_options);
// Grab the lock again.
_lock.lock();
_finished.push_back(request);
PT_Event event = new Event(request->_event_name);
event->add_parameter(EventParameter(request->_id));
throw_event(event);
}
// If there is actually a request token - process it
while (!_token_board->_waiting.empty()) {
PT(LoaderToken) tok = _token_board->_waiting.front();
_token_board->_waiting.pop_front();
tok->_node = load_file(tok->_path, tok->_search);
if (tok->_node == (PandaNode *)NULL) {
loader_cat.error()
<< "Loader::callback() - couldn't find file: "
<< tok->_path << "\n";
} else {
_token_board->_done.push_back(tok);
// Throw a "done" event now.
if (!tok->_event_name.empty()) {
PT_Event done = new Event(tok->_event_name);
done->add_parameter(EventParameter((int)tok->_id));
throw_event(done);
}
}
if (loader_cat.is_debug()) {
loader_cat.debug()
<< "loading complete for " << tok->_path << "\n";
}
}
return true;
}
////////////////////////////////////////////////////////////////////
@@ -410,6 +388,17 @@ process_request() {
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
load_file(const Filename &filename, const LoaderOptions &options) const {
if (options.allow_ram_cache()) {
// If we're allowing a RAM cache (and we don't have any other
// funny options), use the ModelPool to load the file.
PT(PandaNode) node = ModelPool::load_model(filename, options);
if (node != (PandaNode *)NULL) {
// But return a deep copy of the shared model.
node = node->copy_subgraph();
}
return node;
}
Results results;
int num_files;
@@ -471,7 +460,7 @@ load_file(const Filename &filename, const LoaderOptions &options) const {
PT(BamCacheRecord) record;
if (cache->get_active()) {
if (cache->get_active() && options.allow_disk_cache()) {
// See if the texture can be found in the on-disk cache, if it is
// active.
record = cache->lookup(path, "bam");
@@ -510,3 +499,106 @@ load_file(const Filename &filename, const LoaderOptions &options) const {
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: Loader::load_file_types
// Access: Private, Static
// Description: Loads up all of the dynamic libraries named in a
// load-file-type Configure variable. Presumably this
// will make the various file types available for
// runtime loading.
////////////////////////////////////////////////////////////////////
void Loader::
load_file_types() {
if (!_file_types_loaded) {
int num_unique_values = load_file_type.get_num_unique_values();
for (int i = 0; i < num_unique_values; i++) {
string param = load_file_type.get_unique_value(i);
vector_string words;
extract_words(param, words);
if (words.size() == 1) {
// Exactly one word: load the named library immediately.
string name = words[0];
Filename dlname = Filename::dso_filename("lib" + name + ".so");
loader_cat.info()
<< "loading file type module: " << name << endl;
void *tmp = load_dso(dlname);
if (tmp == (void *)NULL) {
loader_cat.warning()
<< "Unable to load " << dlname.to_os_specific()
<< ": " << load_dso_error() << endl;
}
} else if (words.size() > 1) {
// Multiple words: the first n words are filename extensions,
// and the last word is the name of the library to load should
// any of those filename extensions be encountered.
LoaderFileTypeRegistry *registry = LoaderFileTypeRegistry::get_global_ptr();
size_t num_extensions = words.size() - 1;
string library_name = words[num_extensions];
for (size_t i = 0; i < num_extensions; i++) {
string extension = words[i];
if (extension[0] == '.') {
extension = extension.substr(1);
}
registry->register_deferred_type(extension, library_name);
}
}
}
_file_types_loaded = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: Loader::find_id
// Access: Private, Static
// Description: Returns the index number within the given request
// queue of the request with the indicated ID, or -1 if
// no request in the queue has this ID.
////////////////////////////////////////////////////////////////////
int Loader::
find_id(const Requests &requests, int id) {
for (int i = 0; i < (int)requests.size(); ++i) {
if (requests[i]->_id == id) {
return i;
}
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: Loader::LoaderThread::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
Loader::LoaderThread::
LoaderThread(Loader *loader) :
Thread(loader->get_name(), loader->get_name()),
_loader(loader)
{
}
////////////////////////////////////////////////////////////////////
// Function: Loader::LoaderThread::thread_main
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void Loader::LoaderThread::
thread_main() {
MutexHolder holder(_loader->_lock);
while (_loader->_state != Loader::S_shutdown) {
_loader->poll_loader();
_loader->_cvar.wait();
}
// We're going down. Signal the next thread, if there is one.
_loader->_cvar.signal();
}
+74 -15
View File
@@ -21,23 +21,36 @@
#include "pandabase.h"
#include "namable.h"
#include "loaderOptions.h"
#include "pnotify.h"
#include "pandaNode.h"
#include "filename.h"
#include "tokenBoard.h"
#include "asyncUtility.h"
#include "dSearchPath.h"
#include "thread.h"
#include "pmutex.h"
#include "conditionVar.h"
#include "pvector.h"
#include "pdeque.h"
class LoaderToken;
class LoaderFileType;
////////////////////////////////////////////////////////////////////
// Class : Loader
// Description : Handles database loading through asynchronous
// threading
// Description : A convenient class for loading models from disk, in
// bam or egg format (or any of a number of other
// formats implemented by a LoaderFileType, such as
// ptloader).
//
// This class supports synchronous as well as
// asynchronous loading. In asynchronous loading, the
// model is loaded in the background by a thread, and an
// event will be generated when the model is available.
// If threading is not available, the asynchronous
// loading interface may be used, but it loads
// synchronously.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Loader : public AsyncUtility {
class EXPCL_PANDA Loader : public Namable {
private:
class ConsiderFile {
public:
@@ -66,8 +79,9 @@ PUBLISHED:
Files _files;
};
Loader();
~Loader();
Loader(const string &name = "loader",
int num_threads = -1);
virtual ~Loader();
int find_all_files(const Filename &filename, const DSearchPath &search_path,
Results &results) const;
@@ -75,19 +89,64 @@ PUBLISHED:
INLINE PT(PandaNode) load_sync(const Filename &filename,
const LoaderOptions &options = LoaderOptions()) const;
uint request_load(const string &event_name, const Filename &filename, bool search = true);
bool check_load(uint id);
PT(PandaNode) fetch_load(uint id);
int begin_request(const string &event_name);
void request_load(int id, const Filename &filename,
const LoaderOptions &options = LoaderOptions());
bool check_load(int id);
PT(PandaNode) fetch_load(int id);
virtual void output(ostream &out) const;
private:
void poll_loader();
PT(PandaNode) load_file(const Filename &filename, const LoaderOptions &options) const;
static void load_file_types();
static bool _file_types_loaded;
virtual bool process_request();
PT(PandaNode) load_file(const Filename &filename, const LoaderOptions &options) const;
private:
class LoaderThread : public Thread {
public:
LoaderThread(Loader *loader);
virtual void thread_main();
Loader *_loader;
};
typedef TokenBoard<LoaderToken> LoaderTokenBoard;
LoaderTokenBoard *_token_board;
typedef pvector< PT(LoaderThread) > Threads;
class LoaderRequest {
public:
int _id;
string _event_name;
Filename _filename;
LoaderOptions _options;
PT(PandaNode) _model;
};
// We declare this a deque rather than a vector, on the assumption
// that we will usually be popping requests from the front (although
// the interface does not require this).
typedef pdeque<LoaderRequest *> Requests;
static int find_id(const Requests &requests, int id);
int _num_threads;
Mutex _lock; // Protects all the following members.
ConditionVar _cvar; // condition: _pending.empty()
enum State {
S_initial,
S_started,
S_shutdown
};
Requests _initial, _pending, _finished;
int _next_id;
Threads _threads;
State _state;
friend class LoaderThread;
};
#include "loader.I"
+95 -71
View File
@@ -1,71 +1,95 @@
// Filename: loaderOptions.I
// Created by: drose (05Oct05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE LoaderOptions::
LoaderOptions(int flags) :
_flags(flags)
{
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE LoaderOptions::
LoaderOptions(const LoaderOptions &copy) :
_flags(copy._flags)
{
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LoaderOptions::
operator = (const LoaderOptions &copy) {
_flags = copy._flags;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::set_flags
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LoaderOptions::
set_flags(int flags) {
_flags = flags;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::get_flags
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int LoaderOptions::
get_flags() const {
return _flags;
}
// Filename: loaderOptions.I
// Created by: drose (05Oct05)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE LoaderOptions::
LoaderOptions(int flags) :
_flags(flags)
{
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE LoaderOptions::
LoaderOptions(const LoaderOptions &copy) :
_flags(copy._flags)
{
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::Copy Assignment Operator
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LoaderOptions::
operator = (const LoaderOptions &copy) {
_flags = copy._flags;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::set_flags
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE void LoaderOptions::
set_flags(int flags) {
_flags = flags;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::get_flags
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE int LoaderOptions::
get_flags() const {
return _flags;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::allow_disk_cache
// Access: Published
// Description: Returns true if the loader flags allow retrieving the
// model from the on-disk bam cache (if it is enabled),
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool LoaderOptions::
allow_disk_cache() const {
return (_flags & LF_no_disk_cache) == 0;
}
////////////////////////////////////////////////////////////////////
// Function: LoaderOptions::allow_ram_cache
// Access: Published
// Description: Returns true if the loader flags allow retrieving the
// model from the in-memory ModelPool cache, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool LoaderOptions::
allow_ram_cache() const {
return ((_flags & (LF_no_ram_cache | LF_convert_anim)) == 0 &&
(_flags & LF_search) != 0);
}
+6
View File
@@ -36,6 +36,9 @@ PUBLISHED:
LF_convert_skeleton = 0x0004,
LF_convert_channels = 0x0008,
LF_convert_anim = 0x000c, // skeleton + channels
LF_no_disk_cache = 0x0010, // disallow BamCache
LF_no_ram_cache = 0x0020, // disallow ModelPool
LF_no_cache = 0x0030, // no_disk + no_ram
};
INLINE LoaderOptions(int flags = LF_search | LF_report_errors);
@@ -45,6 +48,9 @@ PUBLISHED:
INLINE void set_flags(int flags);
INLINE int get_flags() const;
INLINE bool allow_disk_cache() const;
INLINE bool allow_ram_cache() const;
private:
int _flags;
};
+2 -2
View File
@@ -53,8 +53,8 @@ verify_model(const string &filename) {
// file cannot be found, returns NULL.
////////////////////////////////////////////////////////////////////
INLINE PandaNode *ModelPool::
load_model(const string &filename) {
return get_ptr()->ns_load_model(filename);
load_model(const string &filename, const LoaderOptions &options) {
return get_ptr()->ns_load_model(filename, options);
}
////////////////////////////////////////////////////////////////////
+38 -8
View File
@@ -19,6 +19,7 @@
#include "modelPool.h"
#include "loader.h"
#include "config_pgraph.h"
#include "mutexHolder.h"
ModelPool *ModelPool::_global_ptr = (ModelPool *)NULL;
@@ -44,6 +45,7 @@ write(ostream &out) {
////////////////////////////////////////////////////////////////////
bool ModelPool::
ns_has_model(const string &filename) {
MutexHolder holder(_lock);
Models::const_iterator ti;
ti = _models.find(filename);
if (ti != _models.end()) {
@@ -60,23 +62,44 @@ ns_has_model(const string &filename) {
// Description: The nonstatic implementation of load_model().
////////////////////////////////////////////////////////////////////
PandaNode *ModelPool::
ns_load_model(const string &filename) {
Models::const_iterator ti;
ti = _models.find(filename);
if (ti != _models.end()) {
// This model was previously loaded.
return (*ti).second;
ns_load_model(const string &filename, const LoaderOptions &options) {
{
MutexHolder holder(_lock);
Models::const_iterator ti;
ti = _models.find(filename);
if (ti != _models.end()) {
// This model was previously loaded.
return (*ti).second;
}
}
loader_cat.info()
<< "Loading model " << filename << "\n";
PT(PandaNode) node = model_loader.load_sync(filename);
LoaderOptions new_options(options);
new_options.set_flags(new_options.get_flags() | LoaderOptions::LF_no_ram_cache);
PT(PandaNode) node = model_loader.load_sync(filename, new_options);
if (node.is_null()) {
// This model was not found.
return (PandaNode *)NULL;
}
_models[filename] = node;
{
MutexHolder holder(_lock);
// Look again, in case someone has just loaded the model in
// another thread.
Models::const_iterator ti;
ti = _models.find(filename);
if (ti != _models.end()) {
// This model was previously loaded.
return (*ti).second;
}
_models[filename] = node;
}
return node;
}
@@ -87,6 +110,7 @@ ns_load_model(const string &filename) {
////////////////////////////////////////////////////////////////////
void ModelPool::
ns_add_model(const string &filename, PandaNode *model) {
MutexHolder holder(_lock);
// We blow away whatever model was there previously, if any.
_models[filename] = model;
}
@@ -98,6 +122,7 @@ ns_add_model(const string &filename, PandaNode *model) {
////////////////////////////////////////////////////////////////////
void ModelPool::
ns_release_model(const string &filename) {
MutexHolder holder(_lock);
Models::iterator ti;
ti = _models.find(filename);
if (ti != _models.end()) {
@@ -112,6 +137,7 @@ ns_release_model(const string &filename) {
////////////////////////////////////////////////////////////////////
void ModelPool::
ns_release_all_models() {
MutexHolder holder(_lock);
_models.clear();
}
@@ -122,6 +148,8 @@ ns_release_all_models() {
////////////////////////////////////////////////////////////////////
int ModelPool::
ns_garbage_collect() {
MutexHolder holder(_lock);
int num_released = 0;
Models new_set;
@@ -150,6 +178,8 @@ ns_garbage_collect() {
////////////////////////////////////////////////////////////////////
void ModelPool::
ns_list_contents(ostream &out) const {
MutexHolder holder(_lock);
out << _models.size() << " models:\n";
Models::const_iterator ti;
for (ti = _models.begin(); ti != _models.end(); ++ti) {
+8 -3
View File
@@ -24,8 +24,9 @@
#include "filename.h"
#include "pandaNode.h"
#include "pointerTo.h"
#include "pmutex.h"
#include "pmap.h"
#include "loaderOptions.h"
////////////////////////////////////////////////////////////////////
// Class : ModelPool
@@ -50,7 +51,8 @@ class EXPCL_PANDA ModelPool {
PUBLISHED:
INLINE static bool has_model(const string &filename);
INLINE static bool verify_model(const string &filename);
INLINE static PandaNode *load_model(const string &filename);
INLINE static PandaNode *load_model(const string &filename,
const LoaderOptions &options = LoaderOptions());
INLINE static void add_model(const string &filename, PandaNode *model);
INLINE static void release_model(const string &filename);
@@ -65,7 +67,8 @@ private:
INLINE ModelPool();
bool ns_has_model(const string &filename);
PandaNode *ns_load_model(const string &filename);
PandaNode *ns_load_model(const string &filename,
const LoaderOptions &options);
void ns_add_model(const string &filename, PandaNode *model);
void ns_release_model(const string &filename);
void ns_release_all_models();
@@ -75,6 +78,8 @@ private:
static ModelPool *get_ptr();
static ModelPool *_global_ptr;
Mutex _lock;
typedef pmap<string, PT(PandaNode) > Models;
Models _models;
};
+36 -6
View File
@@ -43,6 +43,8 @@ write(ostream &out) {
////////////////////////////////////////////////////////////////////
bool ShaderPool::
ns_has_shader(const string &str) {
MutexHolder holder(_lock);
string index_str;
Filename filename;
int face_index;
@@ -70,11 +72,15 @@ ns_load_shader(const string &str) {
int face_index;
lookup_filename(str, index_str, filename, face_index);
Shaders::const_iterator ti;
ti = _shaders.find(index_str);
if (ti != _shaders.end()) {
// This shader was previously loaded.
return (*ti).second;
{
MutexHolder holder(_lock);
Shaders::const_iterator ti;
ti = _shaders.find(index_str);
if (ti != _shaders.end()) {
// This shader was previously loaded.
return (*ti).second;
}
}
/*
@@ -111,7 +117,21 @@ ns_load_shader(const string &str) {
return NULL;
}
_shaders[index_str] = shader;
{
MutexHolder holder(_lock);
// Now try again. Someone may have loaded the shader in another
// thread.
Shaders::const_iterator ti;
ti = _shaders.find(index_str);
if (ti != _shaders.end()) {
// This shader was previously loaded.
return (*ti).second;
}
_shaders[index_str] = shader;
}
return shader;
}
@@ -122,6 +142,8 @@ ns_load_shader(const string &str) {
////////////////////////////////////////////////////////////////////
void ShaderPool::
ns_add_shader(const string &str, Shader *shader) {
MutexHolder holder(_lock);
string index_str;
Filename filename;
int face_index;
@@ -138,6 +160,8 @@ ns_add_shader(const string &str, Shader *shader) {
////////////////////////////////////////////////////////////////////
void ShaderPool::
ns_release_shader(const string &filename) {
MutexHolder holder(_lock);
Shaders::iterator ti;
ti = _shaders.find(filename);
if (ti != _shaders.end()) {
@@ -152,6 +176,8 @@ ns_release_shader(const string &filename) {
////////////////////////////////////////////////////////////////////
void ShaderPool::
ns_release_all_shaders() {
MutexHolder holder(_lock);
_shaders.clear();
}
@@ -162,6 +188,8 @@ ns_release_all_shaders() {
////////////////////////////////////////////////////////////////////
int ShaderPool::
ns_garbage_collect() {
MutexHolder holder(_lock);
int num_released = 0;
Shaders new_set;
@@ -192,6 +220,8 @@ ns_garbage_collect() {
////////////////////////////////////////////////////////////////////
void ShaderPool::
ns_list_contents(ostream &out) const {
MutexHolder holder(_lock);
out << _shaders.size() << " shaders:\n";
Shaders::const_iterator ti;
for (ti = _shaders.begin(); ti != _shaders.end(); ++ti) {
+3 -3
View File
@@ -20,10 +20,9 @@
#define SHADERPOOL_H
#include "pandabase.h"
#include "shader.h"
#include "filename.h"
#include "pmutex.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
@@ -65,8 +64,9 @@ private:
Filename &filename, int &face_index);
static ShaderPool *get_ptr();
static ShaderPool *_global_ptr;
Mutex _lock;
typedef pmap<string, CPT(Shader) > Shaders;
Shaders _shaders;
};
+16 -1
View File
@@ -249,6 +249,17 @@ sleep(double seconds) {
ThreadImpl::sleep(seconds);
}
////////////////////////////////////////////////////////////////////
// Function: Thread::is_started
// Access: Public
// Description: Returns true if the thread has been started, false if
// it has not, or if join() has already been called.
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
is_started() const {
return _started;
}
////////////////////////////////////////////////////////////////////
// Function: Thread::interrupt
// Access: Public
@@ -260,6 +271,7 @@ sleep(double seconds) {
////////////////////////////////////////////////////////////////////
INLINE void Thread::
interrupt() {
nassertv(_started);
_impl.interrupt();
}
@@ -273,7 +285,10 @@ interrupt() {
INLINE void Thread::
join() {
TAU_PROFILE("void Thread::join()", " ", TAU_USER);
_impl.join();
if (_started) {
_impl.join();
_started = false;
}
}
////////////////////////////////////////////////////////////////////
+2
View File
@@ -79,6 +79,8 @@ PUBLISHED:
virtual void output(ostream &out) const;
public:
INLINE bool is_started() const;
bool start(ThreadPriority priority, bool global, bool joinable);
INLINE void interrupt();
INLINE void join();
+37 -6
View File
@@ -24,6 +24,7 @@
#include "virtualFileSystem.h"
#include "nodePath.h"
#include "loader.h"
#include "mutexHolder.h"
FontPool *FontPool::_global_ptr = (FontPool *)NULL;
@@ -47,6 +48,8 @@ write(ostream &out) {
////////////////////////////////////////////////////////////////////
bool FontPool::
ns_has_font(const string &str) {
MutexHolder holder(_lock);
string index_str;
Filename filename;
int face_index;
@@ -74,11 +77,15 @@ ns_load_font(const string &str) {
int face_index;
lookup_filename(str, index_str, filename, face_index);
Fonts::const_iterator ti;
ti = _fonts.find(index_str);
if (ti != _fonts.end()) {
// This font was previously loaded.
return (*ti).second;
{
MutexHolder holder(_lock);
Fonts::const_iterator ti;
ti = _fonts.find(index_str);
if (ti != _fonts.end()) {
// This font was previously loaded.
return (*ti).second;
}
}
text_cat.info()
@@ -114,7 +121,21 @@ ns_load_font(const string &str) {
return NULL;
}
_fonts[index_str] = font;
{
MutexHolder holder(_lock);
// Look again. It may have been loaded by another thread.
Fonts::const_iterator ti;
ti = _fonts.find(index_str);
if (ti != _fonts.end()) {
// This font was previously loaded.
return (*ti).second;
}
_fonts[index_str] = font;
}
return font;
}
@@ -125,6 +146,8 @@ ns_load_font(const string &str) {
////////////////////////////////////////////////////////////////////
void FontPool::
ns_add_font(const string &str, TextFont *font) {
MutexHolder holder(_lock);
string index_str;
Filename filename;
int face_index;
@@ -141,6 +164,8 @@ ns_add_font(const string &str, TextFont *font) {
////////////////////////////////////////////////////////////////////
void FontPool::
ns_release_font(const string &filename) {
MutexHolder holder(_lock);
Fonts::iterator ti;
ti = _fonts.find(filename);
if (ti != _fonts.end()) {
@@ -155,6 +180,8 @@ ns_release_font(const string &filename) {
////////////////////////////////////////////////////////////////////
void FontPool::
ns_release_all_fonts() {
MutexHolder holder(_lock);
_fonts.clear();
}
@@ -165,6 +192,8 @@ ns_release_all_fonts() {
////////////////////////////////////////////////////////////////////
int FontPool::
ns_garbage_collect() {
MutexHolder holder(_lock);
int num_released = 0;
Fonts new_set;
@@ -193,6 +222,8 @@ ns_garbage_collect() {
////////////////////////////////////////////////////////////////////
void FontPool::
ns_list_contents(ostream &out) const {
MutexHolder holder(_lock);
out << _fonts.size() << " fonts:\n";
Fonts::const_iterator ti;
for (ti = _fonts.begin(); ti != _fonts.end(); ++ti) {
+3 -2
View File
@@ -23,8 +23,8 @@
#include "texture.h"
#include "textFont.h"
#include "filename.h"
#include "pmutex.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
@@ -66,8 +66,9 @@ private:
Filename &filename, int &face_index);
static FontPool *get_ptr();
static FontPool *_global_ptr;
Mutex _lock;
typedef pmap<string, PT(TextFont) > Fonts;
Fonts _fonts;
};