pgraph: Change TransformState hashing not to require grabbing lock

Instead, set it atomically, with a special hash value used instead of a flag for indicating that the hash is not known.
This commit is contained in:
rdb 2021-11-16 14:48:17 +01:00
parent 60c5589671
commit 9ebfef4b83
3 changed files with 43 additions and 41 deletions

View File

@ -856,8 +856,8 @@ INLINE void TransformState::
check_hash() const {
// This pretends to be a const function, even though it's not, because it
// only updates a transparent cache value.
if ((_flags & F_hash_known) == 0) {
((TransformState *)this)->calc_hash();
if (_hash == H_unknown) {
calc_hash();
}
}
@ -937,15 +937,6 @@ check_mat() const {
}
}
/**
* Computes the hash value.
*/
INLINE void TransformState::
calc_hash() {
LightMutexHolder holder(_lock);
do_calc_hash();
}
/**
* Derives the components from the matrix, if possible.
*/

View File

@ -1406,10 +1406,10 @@ init_states() {
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
state->_inv_mat = new LMatrix4(state->_mat);
state->_hash = int_hash::add_hash(0, F_is_invalid | F_is_identity | F_is_2d);
state->_hash = H_identity;
state->_flags = F_is_identity | F_singular_known | F_components_known
| F_has_components | F_mat_known | F_quat_known | F_hpr_known
| F_uniform_scale | F_identity_scale | F_is_2d | F_hash_known
| F_uniform_scale | F_identity_scale | F_is_2d
| F_norm_quat_known;
state->cache_ref();
state->_saved_entry = _states.store(state, nullptr);
@ -1417,9 +1417,9 @@ init_states() {
}
{
TransformState *state = new TransformState;
state->_hash = int_hash::add_hash(0, F_is_invalid);
state->_flags = F_is_singular | F_singular_known | F_components_known
| F_mat_known | F_is_invalid | F_hash_known;
state->_hash = H_invalid;
state->_flags = F_is_singular | F_singular_known | F_components_known
| F_mat_known | F_is_invalid;
state->cache_ref();
state->_saved_entry = _states.store(state, nullptr);
_invalid_state = state;
@ -2002,15 +2002,18 @@ remove_cache_pointers() {
* Computes a suitable hash value for phash_map.
*/
void TransformState::
do_calc_hash() {
calc_hash() const {
// It's OK not to grab the lock here, because (1) this does not depend on
// cached values (only given components are considered), and (2) the hash
// itself is set atomically.
PStatTimer timer(_transform_hash_pcollector);
_hash = 0;
AtomicAdjust::Integer hash = 0;
static const int significant_flags =
(F_is_invalid | F_is_identity | F_components_given | F_hpr_given | F_is_2d);
int flags = (_flags & significant_flags);
_hash = int_hash::add_hash(_hash, flags);
hash = int_hash::add_hash(hash, flags);
nassertv((flags & (F_is_invalid | F_is_identity)) == 0);
@ -2019,37 +2022,41 @@ do_calc_hash() {
if ((_flags & F_components_given) != 0) {
// If the transform was specified componentwise, hash it componentwise.
_hash = _pos.add_hash(_hash);
hash = _pos.add_hash(hash);
if ((_flags & F_hpr_given) != 0) {
_hash = _hpr.add_hash(_hash);
} else if ((_flags & F_quat_given) != 0) {
_hash = _quat.add_hash(_hash);
hash = _hpr.add_hash(hash);
}
else if ((_flags & F_quat_given) != 0) {
hash = _quat.add_hash(hash);
}
_hash = _scale.add_hash(_hash);
_hash = _shear.add_hash(_hash);
} else {
hash = _scale.add_hash(hash);
hash = _shear.add_hash(hash);
}
else {
// Otherwise, hash the matrix . . .
if (_uniquify_matrix) {
// . . . but only if the user thinks that's worthwhile.
if ((_flags & F_mat_known) == 0) {
// Calculate the matrix without doubly-locking.
do_calc_mat();
}
_hash = _mat.add_hash(_hash);
} else {
check_mat();
hash = _mat.add_hash(hash);
}
else {
// Otherwise, hash the pointer only--any two different matrix-based
// TransformStates are considered to be different, even if their
// matrices have the same values.
_hash = pointer_hash::add_hash(_hash, this);
hash = pointer_hash::add_hash(hash, this);
}
}
_flags |= F_hash_known;
if (hash == H_unknown || hash == H_identity || hash == H_invalid) {
// Arbitrarily offset the hash not to conflict with these special values.
hash += 0x10000;
}
// We don't care if some other thread set this in the meantime, since every
// thread should have computed the same hash.
AtomicAdjust::set(_hash, hash);
}
/**

View File

@ -326,8 +326,7 @@ private:
INLINE void check_quat() const;
INLINE void check_norm_quat() const;
INLINE void check_mat() const;
INLINE void calc_hash();
void do_calc_hash();
void calc_hash() const;
void calc_singular();
INLINE void calc_components();
void do_calc_components();
@ -365,7 +364,6 @@ private:
F_has_nonzero_shear = 0x00004000,
F_is_destructing = 0x00008000,
F_is_2d = 0x00010000,
F_hash_known = 0x00020000,
F_norm_quat_known = 0x00040000,
};
LPoint3 _pos;
@ -373,7 +371,13 @@ private:
LQuaternion _quat, _norm_quat;
LMatrix4 _mat;
LMatrix4 *_inv_mat = nullptr;
size_t _hash;
enum HashValue : AtomicAdjust::Integer {
H_unknown = 0,
H_identity = 1,
H_invalid = 2,
};
mutable AtomicAdjust::Integer _hash = H_unknown;
unsigned int _flags;