avoid async texload race condition

This commit is contained in:
David Rose 2008-09-11 01:02:11 +00:00
parent f57d2b07da
commit d71d7a0fdb
18 changed files with 129 additions and 80 deletions

View File

@ -2240,6 +2240,7 @@ async_reload_texture(TextureContext *tc) {
nassertv(_loader != (Loader *)NULL);
PT(AsyncTask) request =
new TextureReloadRequest(tc, _supports_compressed_texture);
new TextureReloadRequest(_prepared_objects, tc->get_texture(),
_supports_compressed_texture);
_loader->load_async(request);
}

View File

@ -59,6 +59,7 @@
texturePeeker.I texturePeeker.h \
texturePool.I texturePool.h \
texturePoolFilter.I texturePoolFilter.h \
textureReloadRequest.I textureReloadRequest.h \
textureStage.I textureStage.h \
transformBlend.I transformBlend.h \
transformBlendTable.I transformBlendTable.h \
@ -123,6 +124,7 @@
texturePeeker.cxx \
texturePool.cxx \
texturePoolFilter.cxx \
textureReloadRequest.cxx \
textureStage.cxx \
transformBlend.cxx \
transformBlendTable.cxx \
@ -190,6 +192,7 @@
texturePeeker.I texturePeeker.h \
texturePool.I texturePool.h \
texturePoolFilter.I texturePoolFilter.h \
textureReloadRequest.I textureReloadRequest.h \
textureStage.I textureStage.h \
transformBlend.I transformBlend.h \
transformBlendTable.I transformBlendTable.h \

View File

@ -38,6 +38,7 @@
#include "sliderTable.h"
#include "texture.h"
#include "texturePoolFilter.h"
#include "textureReloadRequest.h"
#include "textureStage.h"
#include "textureContext.h"
#include "shader.h"
@ -397,6 +398,16 @@ ConfigVariableInt adaptive_lru_max_updates_per_frame
PRC_DESC("The number of pages the AdaptiveLru class will update per "
"frame. Do not set this too high or it will degrade "
"performance."));
ConfigVariableDouble async_load_delay
("async-load-delay", 0.0,
PRC_DESC("If this is nonzero, it represents an artificial delay, "
"in seconds, that is imposed on every asynchronous load attempt "
"(within the thread). Its purpose is to help debug errors that "
"may occur when an asynchronous load is delayed. The "
"delay is per-model, and all aync loads will be queued "
"up behind the delay--it is as if the time it takes to read a "
"file is increased by this amount per read."));
ConfigureFn(config_gobj) {
@ -435,6 +446,7 @@ ConfigureFn(config_gobj) {
Texture::init_type();
TextureContext::init_type();
TexturePoolFilter::init_type();
TextureReloadRequest::init_type();
TextureStage::init_type();
TransformBlend::init_type();
TransformBlendTable::init_type();

View File

@ -95,6 +95,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_page_threads;
extern EXPCL_PANDA_GOBJ ConfigVariableInt graphics_memory_limit;
extern EXPCL_PANDA_GOBJ ConfigVariableDouble adaptive_lru_weight;
extern EXPCL_PANDA_GOBJ ConfigVariableInt adaptive_lru_max_updates_per_frame;
extern EXPCL_PANDA_GOBJ ConfigVariableDouble async_load_delay;
#endif

View File

@ -17,6 +17,7 @@
#include "texturePeeker.cxx"
#include "texturePool.cxx"
#include "texturePoolFilter.cxx"
#include "textureReloadRequest.cxx"
#include "textureStage.cxx"
#include "transformBlend.cxx"
#include "transformBlendTable.cxx"

View File

@ -71,6 +71,7 @@ PreparedGraphicsObjects::
TextureContext *tc = (*tci);
tc->set_owning_chain(NULL);
}
// Is this a leak? Should we delete these TextureContexts?
_released_textures.clear();
release_all_geoms();
@ -213,7 +214,7 @@ void PreparedGraphicsObjects::
release_texture(TextureContext *tc) {
ReMutexHolder holder(_lock);
tc->get_texture()->clear_prepared(this);
tc->_texture->clear_prepared(this);
// We have to set the Texture pointer to NULL at this point, since
// the Texture itself might destruct at any time after it has been
@ -256,7 +257,7 @@ release_all_textures() {
tci != _prepared_textures.end();
++tci) {
TextureContext *tc = (*tci);
tc->get_texture()->clear_prepared(this);
tc->_texture->clear_prepared(this);
tc->_texture = (Texture *)NULL;
_released_textures.insert(tc);

View File

@ -2010,6 +2010,26 @@ is_prepared(PreparedGraphicsObjects *prepared_objects) const {
return prepared_objects->is_texture_queued(this);
}
////////////////////////////////////////////////////////////////////
// Function: Texture::was_image_modified
// Access: Published
// Description: Returns true if the texture needs to be re-loaded
// onto the indicated GSG, either because its image data
// is out-of-date, or because it's not fully prepared
// now.
////////////////////////////////////////////////////////////////////
bool Texture::
was_image_modified(PreparedGraphicsObjects *prepared_objects) const {
ReMutexHolder holder(_lock);
Contexts::const_iterator ci;
ci = _contexts.find(prepared_objects);
if (ci != _contexts.end()) {
TextureContext *tc = (*ci).second;
return tc->was_image_modified();
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Texture::release
// Access: Published

View File

@ -346,6 +346,7 @@ PUBLISHED:
void prepare(PreparedGraphicsObjects *prepared_objects);
bool is_prepared(PreparedGraphicsObjects *prepared_objects) const;
bool was_image_modified(PreparedGraphicsObjects *prepared_objects) const;
bool release(PreparedGraphicsObjects *prepared_objects);
int release_all();

View File

@ -20,24 +20,37 @@
// via load_async(), to begin an asynchronous load.
////////////////////////////////////////////////////////////////////
INLINE TextureReloadRequest::
TextureReloadRequest(TextureContext *tc, bool allow_compressed) :
_texture_context(tc),
TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture,
bool allow_compressed) :
_pgo(pgo),
_texture(texture),
_allow_compressed(allow_compressed),
_is_ready(false)
{
nassertv(_texture_context != (TextureContext *)NULL);
_texture = _texture_context->get_texture();
nassertv(_pgo != (PreparedGraphicsObjects *)NULL);
nassertv(_texture != (Texture *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: TextureReloadRequest::get_texture_context
// Function: TextureReloadRequest::get_prepared_graphics_objects
// Access: Published
// Description: Returns the TextureContext object associated with
// Description: Returns the PreparedGraphicsObjects object associated with
// this asynchronous TextureReloadRequest.
////////////////////////////////////////////////////////////////////
INLINE TextureContext *TextureReloadRequest::
get_texture_context() const {
return _texture_context;
INLINE PreparedGraphicsObjects *TextureReloadRequest::
get_prepared_graphics_objects() const {
return _pgo;
}
////////////////////////////////////////////////////////////////////
// Function: TextureReloadRequest::get_texture
// Access: Published
// Description: Returns the Texture object associated with
// this asynchronous TextureReloadRequest.
////////////////////////////////////////////////////////////////////
INLINE Texture *TextureReloadRequest::
get_texture() const {
return _texture;
}
////////////////////////////////////////////////////////////////////

View File

@ -13,7 +13,7 @@
////////////////////////////////////////////////////////////////////
#include "textureReloadRequest.h"
#include "loader.h"
#include "textureContext.h"
TypeHandle TextureReloadRequest::_type_handle;
@ -25,16 +25,18 @@ TypeHandle TextureReloadRequest::_type_handle;
bool TextureReloadRequest::
do_task() {
// Don't reload the texture if it doesn't need it.
if (_texture_context->was_image_modified()) {
if (_texture->was_image_modified(_pgo)) {
double delay = async_load_delay;
if (delay != 0.0) {
Thread::sleep(delay);
}
if (_allow_compressed) {
_texture->get_ram_image();
} else {
_texture->get_uncompressed_ram_image();
if (_texture->was_image_modified(_pgo)) {
if (_allow_compressed) {
_texture->get_ram_image();
} else {
_texture->get_uncompressed_ram_image();
}
}
}
_is_ready = true;

View File

@ -19,8 +19,9 @@
#include "asyncTask.h"
#include "texture.h"
#include "textureContext.h"
#include "preparedGraphicsObjects.h"
#include "pointerTo.h"
#include "pmutex.h"
////////////////////////////////////////////////////////////////////
// Class : TextureReloadRequest
@ -30,14 +31,16 @@
// used by GraphicsStateGuardian::async_reload_texture(),
// when get_incomplete_render() is true.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH TextureReloadRequest : public AsyncTask {
class EXPCL_PANDA_GOBJ TextureReloadRequest : public AsyncTask {
public:
ALLOC_DELETED_CHAIN(TextureReloadRequest);
PUBLISHED:
INLINE TextureReloadRequest(TextureContext *tc, bool allow_compressed);
INLINE TextureReloadRequest(PreparedGraphicsObjects *pgo, Texture *texture,
bool allow_compressed);
INLINE TextureContext *get_texture_context() const;
INLINE PreparedGraphicsObjects *get_prepared_graphics_objects() const;
INLINE Texture *get_texture() const;
INLINE bool get_allow_compressed() const;
INLINE bool is_ready() const;
@ -45,9 +48,9 @@ protected:
virtual bool do_task();
private:
TextureContext *_texture_context;
bool _allow_compressed;
PT(PreparedGraphicsObjects) _pgo;
PT(Texture) _texture;
bool _allow_compressed;
bool _is_ready;
public:

View File

@ -118,7 +118,6 @@
textureAttrib.I textureAttrib.h \
texGenAttrib.I texGenAttrib.h \
textureCollection.I textureCollection.h \
textureReloadRequest.I textureReloadRequest.h \
textureStageCollection.I textureStageCollection.h \
transformState.I transformState.h \
transparencyAttrib.I transparencyAttrib.h \
@ -231,7 +230,6 @@
textureAttrib.cxx \
texGenAttrib.cxx \
textureCollection.cxx \
textureReloadRequest.cxx \
textureStageCollection.cxx \
transformState.cxx \
transparencyAttrib.cxx \
@ -342,7 +340,6 @@
textureAttrib.I textureAttrib.h \
texGenAttrib.I texGenAttrib.h \
textureCollection.I textureCollection.h \
textureReloadRequest.I textureReloadRequest.h \
textureStageCollection.I textureStageCollection.h \
transformState.I transformState.h \
transparencyAttrib.I transparencyAttrib.h \

View File

@ -94,7 +94,6 @@
#include "texMatrixAttrib.h"
#include "texProjectorEffect.h"
#include "textureAttrib.h"
#include "textureReloadRequest.h"
#include "texGenAttrib.h"
#include "transformState.h"
#include "transparencyAttrib.h"
@ -274,16 +273,6 @@ ConfigVariableBool flatten_geoms
"only the NodePath interfaces; you may still make the lower-level "
"SceneGraphReducer calls directly."));
ConfigVariableDouble async_load_delay
("async-load-delay", 0.0,
PRC_DESC("If this is nonzero, it represents an artificial delay, "
"in seconds, that is imposed on every asynchronous load attempt "
"(within the thread). Its purpose is to help debug errors that "
"may occur when an asynchronous load is delayed. The "
"delay is per-model, and all aync loads will be queued "
"up behind the delay--it is as if the time it takes to read a "
"file is increased by this amount per read."));
ConfigVariableBool polylight_info
("polylight-info", false,
PRC_DESC("Set this true to view some info statements regarding the polylight. "
@ -460,7 +449,6 @@ init_libpgraph() {
TexMatrixAttrib::init_type();
TexProjectorEffect::init_type();
TextureAttrib::init_type();
TextureReloadRequest::init_type();
TexGenAttrib::init_type();
TransformState::init_type();
TransparencyAttrib::init_type();

View File

@ -53,7 +53,6 @@ extern ConfigVariableInt max_collect_indices;
extern ConfigVariableBool premunge_data;
extern ConfigVariableBool preserve_geom_nodes;
extern ConfigVariableBool flatten_geoms;
extern ConfigVariableDouble async_load_delay;
extern ConfigVariableBool polylight_info;
extern ConfigVariableDouble lod_fade_time;

View File

@ -25,7 +25,6 @@
#include "textureAttrib.cxx"
#include "texGenAttrib.cxx"
#include "textureCollection.cxx"
#include "textureReloadRequest.cxx"
#include "textureStageCollection.cxx"
#include "transformState.cxx"
#include "transparencyAttrib.cxx"

View File

@ -765,13 +765,13 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader,
case AlphaTestAttrib::M_less:
case AlphaTestAttrib::M_less_equal:
alpha_test_state = 1; // aless
_c->zb->reference_alpha = (int)_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX;
_c->zb->reference_alpha = (int)(_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
break;
case AlphaTestAttrib::M_greater:
case AlphaTestAttrib::M_greater_equal:
alpha_test_state = 2; // amore
_c->zb->reference_alpha = (int)_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX;
_c->zb->reference_alpha = (int)(_target._alpha_test->get_reference_alpha() * ZB_POINT_ALPHA_MAX);
break;
}

View File

@ -78,15 +78,23 @@ typedef unsigned int PIXEL;
#define PSZB 4
#define PSZSH 5
#define PIXEL_MULT(p1, p2) \
RGB_TO_PIXEL((PIXEL_R(p1) * PIXEL_R(p2)) >> 16, \
(PIXEL_G(p1) * PIXEL_G(p2)) >> 16, \
(PIXEL_B(p1) * PIXEL_B(p2)) >> 16)
// Returns an unsigned product of c1 * c2
#define PCOMPONENT_MULT(c1, c2) \
((((unsigned int)(c1) * (unsigned int)(c2))) >> 16)
// Returns a signed product of c1 * c2, where c1 is initially signed.
// We leave 2 bits on the top to differentiate between c1 < 0 and c1 >
// 0xffff; the result has the same sign.
#define PALPHA_MULT(c1, c2) \
(((int)(((int)(c1) >> 2) * (unsigned int)(c2))) >> 14)
#define PCOMPONENT_BLEND(c1, c2, a2) \
((((unsigned int)(c1) * ((unsigned int)0xffff - (unsigned int)(a2)) + (unsigned int)(c2) * (unsigned int)(a2))) >> 16)
#define PIXEL_BLEND(r1, g1, b1, r2, g2, b2, a2) \
RGBA_TO_PIXEL(((r1) * (0xffff - (a2)) + (r2) * (a2)) >> 16, \
((g1) * (0xffff - (a2)) + (g2) * (a2)) >> 16, \
((b1) * (0xffff - (a2)) + (b2) * (a2)) >> 16, \
RGBA_TO_PIXEL(PCOMPONENT_BLEND(r1, r2, a2), \
PCOMPONENT_BLEND(g1, g2, a2), \
PCOMPONENT_BLEND(b1, b2, a2), \
a2)
#define PIXEL_BLEND_RGB(rgb, r, g, b, a) \
PIXEL_BLEND(PIXEL_R(rgb), PIXEL_G(rgb), PIXEL_B(rgb), r, g, b, a)

View File

@ -182,16 +182,16 @@ static void FNAME(flat_textured) (ZBuffer *zb,
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
int a = oa0 * PIXEL_A(tmp) >> 16; \
int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(or0 * PIXEL_R(tmp) >> 16, \
og0 * PIXEL_G(tmp) >> 16, \
ob0 * PIXEL_B(tmp) >> 16, \
RGBA_TO_PIXEL(PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \
a), \
or0 * PIXEL_R(tmp) >> 16, \
og0 * PIXEL_G(tmp) >> 16, \
ob0 * PIXEL_B(tmp) >> 16, \
PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \
a); \
STORE_Z(pz[_a], zz); \
} \
@ -243,16 +243,16 @@ static void FNAME(smooth_textured) (ZBuffer *zb,
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
int a = oa1 * PIXEL_A(tmp) >> 16; \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16, \
og1 * PIXEL_G(tmp) >> 16, \
ob1 * PIXEL_B(tmp) >> 16, \
RGBA_TO_PIXEL(PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \
a), \
or1 * PIXEL_R(tmp) >> 16, \
og1 * PIXEL_G(tmp) >> 16, \
ob1 * PIXEL_B(tmp) >> 16, \
PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \
a); \
STORE_Z(pz[_a], zz); \
} \
@ -422,16 +422,16 @@ static void FNAME(flat_perspective) (ZBuffer *zb,
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
int a = oa0 * PIXEL_A(tmp) >> 16; \
int a = PALPHA_MULT(oa0, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(or0 * PIXEL_R(tmp) >> 16, \
og0 * PIXEL_G(tmp) >> 16, \
ob0 * PIXEL_B(tmp) >> 16, \
RGBA_TO_PIXEL(PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \
a), \
or0 * PIXEL_R(tmp) >> 16, \
og0 * PIXEL_G(tmp) >> 16, \
ob0 * PIXEL_B(tmp) >> 16, \
PCOMPONENT_MULT(or0, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og0, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob0, PIXEL_B(tmp)), \
a); \
STORE_Z(pz[_a], zz); \
} \
@ -556,17 +556,17 @@ static void FNAME(smooth_perspective) (ZBuffer *zb,
{ \
zz=z >> ZB_POINT_Z_FRAC_BITS; \
if (ZCMP(pz[_a], zz)) { \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
int a = oa1 * PIXEL_A(tmp) >> 16; \
tmp = ZB_LOOKUP_TEXTURE(texture_levels, s, t, mipmap_level, mipmap_dx); \
int a = PALPHA_MULT(oa1, PIXEL_A(tmp)); \
if (ACMP(zb, a)) { \
STORE_PIX(pp[_a], \
RGBA_TO_PIXEL(or1 * PIXEL_R(tmp) >> 16, \
og1 * PIXEL_G(tmp) >> 16, \
ob1 * PIXEL_B(tmp) >> 16, \
RGBA_TO_PIXEL(PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \
a), \
or1 * PIXEL_R(tmp) >> 16, \
og1 * PIXEL_G(tmp) >> 16, \
ob1 * PIXEL_B(tmp) >> 16, \
PCOMPONENT_MULT(or1, PIXEL_R(tmp)), \
PCOMPONENT_MULT(og1, PIXEL_G(tmp)), \
PCOMPONENT_MULT(ob1, PIXEL_B(tmp)), \
a); \
STORE_Z(pz[_a], zz); \
} \