mirror of
https://github.com/panda3d/panda3d.git
synced 2026-04-23 06:59:22 -05:00
threaded model loads
This commit is contained in:
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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 "
|
||||
|
||||
@@ -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
@@ -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
@@ -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"
|
||||
|
||||
@@ -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 ©) :
|
||||
_flags(copy._flags)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderOptions::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void LoaderOptions::
|
||||
operator = (const LoaderOptions ©) {
|
||||
_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 ©) :
|
||||
_flags(copy._flags)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LoaderOptions::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void LoaderOptions::
|
||||
operator = (const LoaderOptions ©) {
|
||||
_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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user