pipelining getting close; uprev bam version to 6.0
This commit is contained in:
parent
7023429790
commit
1d2282a879
|
|
@ -320,15 +320,14 @@
|
|||
|
||||
// Do you want to compile in support for pipelining? This enables
|
||||
// setting and accessing multiple different copies of frame-specific
|
||||
// data stored in nodes, etc. At the moment, Panda cannot actually
|
||||
// take advantage of this support to do anything useful, but
|
||||
// eventually this will enable multi-stage pipelining of the render
|
||||
// process, as well as potentially remote rendering using a
|
||||
// distributed scene graph. For now, we enable this when building
|
||||
// optimize 1 only, since turning this on does perform some additional
|
||||
// sanity checks, but doesn't do anything else useful other than
|
||||
// increase run-time overhead.
|
||||
#defer DO_PIPELINING $[<= $[OPTIMIZE], 1]
|
||||
// data stored in nodes, etc. This is necessary, in conjunction with
|
||||
// HAVE_THREADS, to implement threaded multistage rendering in Panda.
|
||||
// However, compiling this option in does add some additional runtime
|
||||
// overhead even if it is not used. By default, we enable pipelining
|
||||
// whenever threads are enabled, assuming that if you have threads,
|
||||
// you also want to use piplining. We also enable it at OPTIMIZE
|
||||
// level 1, since that enables additional runtime checks.
|
||||
#defer DO_PIPELINING $[or $[<= $[OPTIMIZE], 1],$[HAVE_THREADS]]
|
||||
|
||||
// Do you want to use one of the alternative malloc implementations?
|
||||
// This is almost always a good idea on Windows, where the standard
|
||||
|
|
@ -578,9 +577,13 @@
|
|||
// that Panda can use.
|
||||
#define HAVE_THREADS
|
||||
|
||||
// Even if threading is not defined, you might want to double-check
|
||||
// that ordinary mutexes are not locked reentrantly:
|
||||
#define CHECK_REENTRANT_MUTEX
|
||||
// Whether threading is defined or not, you might want to validate the
|
||||
// thread and synchronization operations. With threading enabled,
|
||||
// defining this will also enable deadlock detection and logging.
|
||||
// Without threading enabled, defining this will simply verify that a
|
||||
// mutex is not recursively locked. There is, of course, additional
|
||||
// run-time overhead for these tests.
|
||||
#defer DEBUG_THREADS $[<= $[OPTIMIZE], 2]
|
||||
|
||||
// Do you want to build the network interface? What additional libraries
|
||||
// are required? Currently, this requires NSPR.
|
||||
|
|
|
|||
|
|
@ -232,8 +232,8 @@ $[cdefine HAVE_CHROMIUM]
|
|||
/* Define if we want to compile the threading code. */
|
||||
$[cdefine HAVE_THREADS]
|
||||
|
||||
/* Define to check that ordinary (non-reentrant) Mutexes are not reentrantly locked. */
|
||||
$[cdefine CHECK_REENTRANT_MUTEX]
|
||||
/* Define to enable deadlock detection, mutex recursion checks, etc. */
|
||||
$[cdefine DEBUG_THREADS]
|
||||
|
||||
/* Define if we want to compile the net code. */
|
||||
$[cdefine HAVE_NET]
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@
|
|||
#set HAVE_OPENCV $[HAVE_OPENCV]
|
||||
|
||||
#set HAVE_THREADS $[HAVE_THREADS]
|
||||
#set CHECK_REENTRANT_MUTEX $[CHECK_REENTRANT_MUTEX]
|
||||
#set DEBUG_THREADS $[DEBUG_THREADS]
|
||||
|
||||
#set NET_IPATH $[unixfilename $[NET_IPATH]]
|
||||
#set NET_LPATH $[unixfilename $[NET_LPATH]]
|
||||
|
|
|
|||
|
|
@ -68,16 +68,15 @@ output(ostream &out) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionInvSphere::recompute_bound
|
||||
// Function: CollisionInvSphere::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionInvSphere::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundedObject::recompute_bound(pipeline_stage);
|
||||
PT(BoundingVolume) CollisionInvSphere::
|
||||
compute_internal_bounds() const {
|
||||
// An inverse sphere always has an infinite bounding volume, since
|
||||
// everything outside the sphere is solid matter.
|
||||
return set_bound_ptr(new OmniBoundingVolume());
|
||||
return new OmniBoundingVolume();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
virtual void output(ostream &out) const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
virtual PT(CollisionEntry)
|
||||
test_intersection_from_sphere(const CollisionEntry &entry) const;
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ prepare_collider(const ColliderDef &def) {
|
|||
_colliders.push_back(def);
|
||||
|
||||
CollisionSolid *collider = def._collider;
|
||||
const BoundingVolume *bv = collider->get_bound();
|
||||
CPT(BoundingVolume) bv = collider->get_bounds();
|
||||
if (!bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
_local_bounds.push_back((GeometricBoundingVolume *)NULL);
|
||||
} else {
|
||||
|
|
@ -118,7 +118,7 @@ any_in_bounds() {
|
|||
}
|
||||
#endif // NDEBUG
|
||||
|
||||
const BoundingVolume *node_bv = node()->get_bound();
|
||||
CPT(BoundingVolume) node_bv = node()->get_bounds();
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
const GeometricBoundingVolume *node_gbv;
|
||||
DCAST_INTO_R(node_gbv, node_bv, false);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ get_into_collide_mask() const {
|
|||
INLINE void CollisionNode::
|
||||
clear_solids() {
|
||||
_solids.clear();
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -114,7 +114,7 @@ INLINE void CollisionNode::
|
|||
set_solid(int n, CollisionSolid *solid) {
|
||||
nassertv(n >= 0 && n < get_num_solids());
|
||||
_solids[n] = solid;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -127,7 +127,7 @@ INLINE void CollisionNode::
|
|||
remove_solid(int n) {
|
||||
nassertv(n >= 0 && n < get_num_solids());
|
||||
_solids.erase(_solids.begin() + n);
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -140,7 +140,7 @@ remove_solid(int n) {
|
|||
INLINE int CollisionNode::
|
||||
add_solid(CollisionSolid *solid) {
|
||||
_solids.push_back(solid);
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
return _solids.size() - 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ xform(const LMatrix4f &mat) {
|
|||
|
||||
solid->xform(mat);
|
||||
}
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -157,7 +157,7 @@ combine_with(PandaNode *other) {
|
|||
const PT(CollisionSolid) *solids_begin = &cother->_solids[0];
|
||||
const PT(CollisionSolid) *solids_end = solids_begin + cother->_solids.size();
|
||||
_solids.insert(_solids.end(), solids_begin, solids_end);
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
@ -348,17 +348,17 @@ get_collide_geom() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionNode::recompute_internal_bound
|
||||
// Function: CollisionNode::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description: Called when needed to recompute the node's
|
||||
// _internal_bound object. Nodes that contain anything
|
||||
// of substance should redefine this to do the right
|
||||
// thing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionNode::
|
||||
recompute_internal_bound(int pipeline_stage) {
|
||||
PT(BoundingVolume) CollisionNode::
|
||||
compute_internal_bounds(int pipeline_stage) const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
BoundingVolume *bound = PandaNode::recompute_internal_bound(pipeline_stage);
|
||||
PT(BoundingVolume) bound = PandaNode::compute_internal_bounds(pipeline_stage);
|
||||
nassertr(bound != (BoundingVolume *)NULL, bound);
|
||||
|
||||
// Now actually compute the bounding volume by putting it around all
|
||||
|
|
@ -367,7 +367,7 @@ recompute_internal_bound(int pipeline_stage) {
|
|||
|
||||
Solids::const_iterator gi;
|
||||
for (gi = _solids.begin(); gi != _solids.end(); ++gi) {
|
||||
child_volumes.push_back((*gi)->get_bound());
|
||||
child_volumes.push_back((*gi)->get_bounds());
|
||||
}
|
||||
|
||||
const BoundingVolume **child_begin = &child_volumes[0];
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ PUBLISHED:
|
|||
INLINE static CollideMask get_default_collide_mask();
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_internal_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;
|
||||
|
||||
private:
|
||||
CPT(RenderState) get_last_pos_state();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionPlane::Default Constructor
|
||||
// Access: Protected
|
||||
|
|
@ -78,7 +79,7 @@ dist_to_plane(const LPoint3f &point) const {
|
|||
INLINE void CollisionPlane::
|
||||
set_plane(const Planef &plane) {
|
||||
_plane = plane;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -88,16 +88,13 @@ output(ostream &out) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionPlane::recompute_bound
|
||||
// Function: CollisionPlane::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionPlane::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundedObject::recompute_bound(pipeline_stage);
|
||||
// Less than ideal: we throw away whatever we just allocated in
|
||||
// BoundedObject.
|
||||
return set_bound_ptr(new BoundingPlane(_plane));
|
||||
PT(BoundingVolume) CollisionPlane::
|
||||
compute_internal_bounds() const {
|
||||
return new BoundingPlane(_plane);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ PUBLISHED:
|
|||
INLINE const Planef &get_plane() const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
protected:
|
||||
virtual PT(CollisionEntry)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionPolygon::Constructor
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -356,14 +356,14 @@ write(ostream &out, int indent_level) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionPolygon::recompute_bound
|
||||
// Function: CollisionPolygon::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionPolygon::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
PT(BoundingVolume) CollisionPolygon::
|
||||
compute_internal_bounds() const {
|
||||
// First, get ourselves a fresh, empty bounding volume.
|
||||
BoundingVolume *bound = BoundedObject::recompute_bound(pipeline_stage);
|
||||
PT(BoundingVolume) bound = CollisionSolid::compute_internal_bounds();
|
||||
nassertr(bound != (BoundingVolume*)0L, bound);
|
||||
|
||||
GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public:
|
|||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
virtual PT(CollisionEntry)
|
||||
test_intersection_from_sphere(const CollisionEntry &entry) const;
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ CollisionRay(const CollisionRay ©) :
|
|||
INLINE void CollisionRay::
|
||||
set_origin(const LPoint3f &origin) {
|
||||
_origin = origin;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
}
|
||||
|
||||
|
|
@ -110,7 +110,7 @@ get_origin() const {
|
|||
INLINE void CollisionRay::
|
||||
set_direction(const LVector3f &direction) {
|
||||
_direction = direction;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
nassertv(_direction != LPoint3f::zero());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,23 +119,20 @@ set_from_lens(LensNode *camera, const LPoint2f &point) {
|
|||
_direction = far_point - near_point;
|
||||
}
|
||||
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionRay::recompute_bound
|
||||
// Function: CollisionRay::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionRay::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundedObject::recompute_bound(pipeline_stage);
|
||||
// Less than ideal: we throw away whatever we just allocated in
|
||||
// BoundedObject.
|
||||
return set_bound_ptr(new BoundingLine(_origin, _origin + _direction));
|
||||
PT(BoundingVolume) CollisionRay::
|
||||
compute_internal_bounds() const {
|
||||
return new BoundingLine(_origin, _origin + _direction);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ PUBLISHED:
|
|||
INLINE bool set_from_lens(LensNode *camera, float px, float py);
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
protected:
|
||||
virtual void fill_viz_geom();
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSegment::Default Constructor
|
||||
// Access: Public
|
||||
|
|
@ -77,7 +78,7 @@ CollisionSegment(const CollisionSegment ©) :
|
|||
INLINE void CollisionSegment::
|
||||
set_point_a(const LPoint3f &a) {
|
||||
_a = a;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
// We don't assert here that a != b, on the assumption that you
|
||||
// might be about to change both at once, and you'll probably start
|
||||
|
|
@ -112,7 +113,7 @@ get_point_a() const {
|
|||
INLINE void CollisionSegment::
|
||||
set_point_b(const LPoint3f &b) {
|
||||
_b = b;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
nassertv(_a != _b);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,20 +116,20 @@ set_from_lens(LensNode *camera, const LPoint2f &point) {
|
|||
success = false;
|
||||
}
|
||||
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSegment::recompute_bound
|
||||
// Function: CollisionSegment::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionSegment::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundingVolume *bound = BoundedObject::recompute_bound(pipeline_stage);
|
||||
PT(BoundingVolume) CollisionSegment::
|
||||
compute_internal_bounds() const {
|
||||
PT(BoundingVolume) bound = CollisionSolid::compute_internal_bounds();
|
||||
|
||||
if (bound->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
GeometricBoundingVolume *gbound;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ PUBLISHED:
|
|||
INLINE bool set_from_lens(LensNode *camera, float px, float py);
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
protected:
|
||||
virtual void fill_viz_geom();
|
||||
|
|
|
|||
|
|
@ -135,6 +135,19 @@ get_respect_effective_normal() const {
|
|||
return (_flags & F_ignore_effective_normal) == 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::mark_internal_bounds_stale
|
||||
// Access: Protected
|
||||
// Description: Should be called by a derived class to mark the
|
||||
// internal bounding volume stale, so that
|
||||
// recompute_internal_bounds() will be called when the
|
||||
// bounding volume is next requested.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void CollisionSolid::
|
||||
mark_internal_bounds_stale() {
|
||||
_flags |= F_internal_bounds_stale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::mark_viz_stale
|
||||
// Access: Protected
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "collisionLine.h"
|
||||
#include "collisionRay.h"
|
||||
#include "collisionSegment.h"
|
||||
|
||||
#include "boundingSphere.h"
|
||||
#include "datagram.h"
|
||||
#include "datagramIterator.h"
|
||||
#include "bamReader.h"
|
||||
|
|
@ -43,7 +43,7 @@ TypeHandle CollisionSolid::_type_handle;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
CollisionSolid::
|
||||
CollisionSolid() {
|
||||
_flags = F_viz_geom_stale | F_tangible;
|
||||
_flags = F_viz_geom_stale | F_tangible | F_internal_bounds_stale;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -54,6 +54,7 @@ CollisionSolid() {
|
|||
CollisionSolid::
|
||||
CollisionSolid(const CollisionSolid ©) :
|
||||
_effective_normal(copy._effective_normal),
|
||||
_internal_bounds(copy._internal_bounds),
|
||||
_flags(copy._flags)
|
||||
{
|
||||
_flags |= F_viz_geom_stale;
|
||||
|
|
@ -68,6 +69,20 @@ CollisionSolid::
|
|||
~CollisionSolid() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::get_bounds
|
||||
// Access: Protected
|
||||
// Description: Returns the solid's bounding volume.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(BoundingVolume) CollisionSolid::
|
||||
get_bounds() const {
|
||||
if (_flags & F_internal_bounds_stale) {
|
||||
((CollisionSolid *)this)->_internal_bounds = compute_internal_bounds();
|
||||
((CollisionSolid *)this)->_flags &= ~F_internal_bounds_stale;
|
||||
}
|
||||
return _internal_bounds;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::test_intersection
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -96,7 +111,7 @@ xform(const LMatrix4f &mat) {
|
|||
}
|
||||
|
||||
mark_viz_stale();
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -148,6 +163,16 @@ write(ostream &out, int indent_level) const {
|
|||
indent(out, indent_level) << (*this) << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(BoundingVolume) CollisionSolid::
|
||||
compute_internal_bounds() const {
|
||||
return new BoundingSphere;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSolid::test_intersection_from_sphere
|
||||
// Access: Protected, Virtual
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include "config_collide.h"
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "boundedObject.h"
|
||||
#include "luse.h"
|
||||
#include "pointerTo.h"
|
||||
#include "renderState.h"
|
||||
|
|
@ -49,8 +48,7 @@ class CullTraverserData;
|
|||
// function calls handle the subset of the N*N
|
||||
// intersection tests that we care about.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA CollisionSolid :
|
||||
public TypedWritableReferenceCount, public BoundedObject {
|
||||
class EXPCL_PANDA CollisionSolid : public TypedWritableReferenceCount {
|
||||
public:
|
||||
CollisionSolid();
|
||||
CollisionSolid(const CollisionSolid ©);
|
||||
|
|
@ -71,6 +69,8 @@ PUBLISHED:
|
|||
INLINE void set_respect_effective_normal(bool respect_effective_normal);
|
||||
INLINE bool get_respect_effective_normal() const;
|
||||
|
||||
CPT(BoundingVolume) get_bounds() const;
|
||||
|
||||
public:
|
||||
virtual PT(CollisionEntry)
|
||||
test_intersection(const CollisionEntry &entry) const;
|
||||
|
|
@ -86,6 +86,9 @@ PUBLISHED:
|
|||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
protected:
|
||||
INLINE void mark_internal_bounds_stale();
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
virtual PT(CollisionEntry)
|
||||
test_intersection_from_sphere(const CollisionEntry &entry) const;
|
||||
virtual PT(CollisionEntry)
|
||||
|
|
@ -114,6 +117,7 @@ protected:
|
|||
|
||||
private:
|
||||
LVector3f _effective_normal;
|
||||
PT(BoundingVolume) _internal_bounds;
|
||||
|
||||
// Be careful reordering these bits, since they are written to a bam
|
||||
// file.
|
||||
|
|
@ -122,6 +126,7 @@ private:
|
|||
F_effective_normal = 0x02,
|
||||
F_viz_geom_stale = 0x04,
|
||||
F_ignore_effective_normal = 0x08,
|
||||
F_internal_bounds_stale = 0x10,
|
||||
};
|
||||
int _flags;
|
||||
|
||||
|
|
@ -137,10 +142,8 @@ public:
|
|||
}
|
||||
static void init_type() {
|
||||
TypedWritableReferenceCount::init_type();
|
||||
BoundedObject::init_type();
|
||||
register_type(_type_handle, "CollisionSolid",
|
||||
TypedWritableReferenceCount::get_class_type(),
|
||||
BoundedObject::get_class_type());
|
||||
TypedWritableReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ CollisionSphere(const CollisionSphere ©) :
|
|||
INLINE void CollisionSphere::
|
||||
set_center(const LPoint3f ¢er) {
|
||||
_center = center;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ get_center() const {
|
|||
INLINE void CollisionSphere::
|
||||
set_radius(float radius) {
|
||||
_radius = radius;
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ xform(const LMatrix4f &mat) {
|
|||
LVector3f radius_v = LVector3f(_radius, 0.0f, 0.0f) * mat;
|
||||
_radius = length(radius_v);
|
||||
mark_viz_stale();
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -99,19 +99,13 @@ output(ostream &out) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionSphere::recompute_bound
|
||||
// Function: CollisionSphere::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionSphere::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundingVolume *bound = BoundedObject::recompute_bound(pipeline_stage);
|
||||
nassertr(bound != (BoundingVolume*)0L, bound);
|
||||
nassertr(!_center.is_nan() && !cnan(_radius), bound);
|
||||
BoundingSphere sphere(_center, _radius);
|
||||
bound->extend_by(&sphere);
|
||||
|
||||
return bound;
|
||||
PT(BoundingVolume) CollisionSphere::
|
||||
compute_internal_bounds() const {
|
||||
return new BoundingSphere(_center, _radius);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ PUBLISHED:
|
|||
INLINE float get_radius() const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
virtual PT(CollisionEntry)
|
||||
test_intersection_from_sphere(const CollisionEntry &entry) const;
|
||||
|
|
|
|||
|
|
@ -519,7 +519,7 @@ r_traverse(CollisionLevelState &level_state) {
|
|||
if (node->is_exact_type(CollisionNode::get_class_type())) {
|
||||
CollisionNode *cnode;
|
||||
DCAST_INTO_V(cnode, node);
|
||||
const BoundingVolume *node_bv = cnode->get_bound();
|
||||
CPT(BoundingVolume) node_bv = cnode->get_bounds();
|
||||
const GeometricBoundingVolume *node_gbv = NULL;
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
DCAST_INTO_V(node_gbv, node_bv);
|
||||
|
|
@ -560,7 +560,7 @@ r_traverse(CollisionLevelState &level_state) {
|
|||
|
||||
GeomNode *gnode;
|
||||
DCAST_INTO_V(gnode, node);
|
||||
const BoundingVolume *node_bv = gnode->get_bound();
|
||||
CPT(BoundingVolume) node_bv = gnode->get_bounds();
|
||||
const GeometricBoundingVolume *node_gbv = NULL;
|
||||
if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
DCAST_INTO_V(node_gbv, node_bv);
|
||||
|
|
@ -642,7 +642,7 @@ compare_collider_to_node(CollisionEntry &entry,
|
|||
for (int s = 0; s < num_solids; ++s) {
|
||||
entry._into = cnode->get_solid(s);
|
||||
if (entry._from != entry._into) {
|
||||
const BoundingVolume *solid_bv = entry._into->get_bound();
|
||||
CPT(BoundingVolume) solid_bv = entry._into->get_bounds();
|
||||
const GeometricBoundingVolume *solid_gbv = NULL;
|
||||
if (num_solids > 1 &&
|
||||
solid_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
|
|
@ -684,7 +684,7 @@ compare_collider_to_geom_node(CollisionEntry &entry,
|
|||
entry._into = (CollisionSolid *)NULL;
|
||||
const Geom *geom = DCAST(Geom, gnode->get_geom(s));
|
||||
if (geom != (Geom *)NULL) {
|
||||
const BoundingVolume *geom_bv = geom->get_bound();
|
||||
CPT(BoundingVolume) geom_bv = geom->get_bounds();
|
||||
const GeometricBoundingVolume *geom_gbv = NULL;
|
||||
if (num_geoms > 1 &&
|
||||
geom_bv->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ set_radius(float radius) {
|
|||
|
||||
// We don't need to call recalc_internals(), since the radius
|
||||
// doesn't change either of those properties.
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
mark_viz_stale();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ output(ostream &out) const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: CollisionTube::recompute_bound
|
||||
// Function: CollisionTube::compute_internal_bounds
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BoundingVolume *CollisionTube::
|
||||
recompute_bound(int pipeline_stage) {
|
||||
BoundingVolume *bound = BoundedObject::recompute_bound(pipeline_stage);
|
||||
PT(BoundingVolume) CollisionTube::
|
||||
compute_internal_bounds() const {
|
||||
PT(BoundingVolume) bound = CollisionSolid::compute_internal_bounds();
|
||||
|
||||
if (bound->is_of_type(GeometricBoundingVolume::get_class_type())) {
|
||||
GeometricBoundingVolume *gbound;
|
||||
|
|
@ -458,7 +458,7 @@ recalc_internals() {
|
|||
_inv_mat.invert_from(_mat);
|
||||
|
||||
mark_viz_stale();
|
||||
mark_bound_stale();
|
||||
mark_internal_bounds_stale();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ PUBLISHED:
|
|||
INLINE float get_radius() const;
|
||||
|
||||
protected:
|
||||
virtual BoundingVolume *recompute_bound(int pipeline_stage);
|
||||
virtual PT(BoundingVolume) compute_internal_bounds() const;
|
||||
|
||||
protected:
|
||||
virtual PT(CollisionEntry)
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ CollisionVisualizer::
|
|||
CollisionVisualizer(const string &name) : PandaNode(name) {
|
||||
// We always want to render the CollisionVisualizer node itself
|
||||
// (even if it doesn't appear to have any geometry within it).
|
||||
set_bound(OmniBoundingVolume());
|
||||
set_internal_bounds(new OmniBoundingVolume());
|
||||
_viz_scale = 1.0f;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -254,8 +254,8 @@ define_output(const string &name, TypeHandle data_type) {
|
|||
// node has.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DataNode::
|
||||
parents_changed(int pipeline_stage) {
|
||||
PandaNode::parents_changed(pipeline_stage);
|
||||
parents_changed() {
|
||||
PandaNode::parents_changed();
|
||||
reconnect();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ protected:
|
|||
|
||||
protected:
|
||||
// Inherited from PandaNode
|
||||
virtual void parents_changed(int pipeline_stage);
|
||||
virtual void parents_changed();
|
||||
|
||||
// Local to DataNode
|
||||
virtual void do_transmit_data(const DataNodeTransmit &input,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
|
||||
#include "config_display.h"
|
||||
#include "displayRegion.h"
|
||||
#include "standardMunger.h"
|
||||
#include "graphicsStateGuardian.h"
|
||||
#include "graphicsPipe.h"
|
||||
|
|
@ -26,6 +27,7 @@
|
|||
#include "graphicsWindow.h"
|
||||
#include "graphicsDevice.h"
|
||||
#include "parasiteBuffer.h"
|
||||
#include "pandaSystem.h"
|
||||
|
||||
ConfigureDef(config_display);
|
||||
NotifyCategoryDef(display, "");
|
||||
|
|
@ -260,13 +262,19 @@ init_libdisplay() {
|
|||
return;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
StandardMunger::init_type();
|
||||
GraphicsStateGuardian::init_type();
|
||||
GraphicsPipe::init_type();
|
||||
GraphicsOutput::init_type();
|
||||
GraphicsWindow::init_type();
|
||||
|
||||
DisplayRegion::init_type();
|
||||
GraphicsBuffer::init_type();
|
||||
GraphicsDevice::init_type();
|
||||
GraphicsOutput::init_type();
|
||||
GraphicsPipe::init_type();
|
||||
GraphicsStateGuardian::init_type();
|
||||
GraphicsWindow::init_type();
|
||||
ParasiteBuffer::init_type();
|
||||
StandardMunger::init_type();
|
||||
|
||||
#if defined(HAVE_THREADS) && defined(DO_PIPELINING)
|
||||
PandaSystem *ps = PandaSystem::get_global_ptr();
|
||||
ps->add_system("pipelining");
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool DisplayRegion::
|
||||
operator < (const DisplayRegion &other) const {
|
||||
return _sort < other._sort;
|
||||
return get_sort() < other.get_sort();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -36,7 +36,8 @@ operator < (const DisplayRegion &other) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool DisplayRegion::
|
||||
is_active() const {
|
||||
return _active;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_active;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -47,7 +48,8 @@ is_active() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DisplayRegion::
|
||||
get_sort() const {
|
||||
return _sort;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_sort;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -63,7 +65,10 @@ get_sort() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DisplayRegion::
|
||||
set_cube_map_index(int cube_map_index) {
|
||||
_cube_map_index = cube_map_index;
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_cube_map_index = cube_map_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -76,7 +81,77 @@ set_cube_map_index(int cube_map_index) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DisplayRegion::
|
||||
get_cube_map_index() const {
|
||||
return _cube_map_index;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_cube_map_index;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::set_cull_result
|
||||
// Access: Public
|
||||
// Description: Stores the result of performing a cull operation on
|
||||
// this DisplayRegion. Normally, this will only be
|
||||
// called by the GraphicsEngine; you should not call
|
||||
// this directly.
|
||||
//
|
||||
// The stored result will automatically be applied back
|
||||
// to all upstream pipeline stages.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DisplayRegion::
|
||||
set_cull_result(CullResult *cull_result, SceneSetup *scene_setup) {
|
||||
CDCullWriter cdata(_cycler_cull, true);
|
||||
cdata->_cull_result = cull_result;
|
||||
cdata->_scene_setup = scene_setup;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::get_cull_result
|
||||
// Access: Public
|
||||
// Description: Returns the CullResult value that was stored on this
|
||||
// DisplayRegion, presumably by the last successful cull
|
||||
// operation. This method is for the benefit of the
|
||||
// GraphicsEngine; normally you shouldn't call this
|
||||
// directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CullResult *DisplayRegion::
|
||||
get_cull_result() const {
|
||||
CDCullReader cdata(_cycler_cull);
|
||||
return cdata->_cull_result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::get_scene_setup
|
||||
// Access: Public
|
||||
// Description: Returns the SceneSetup value that was stored on this
|
||||
// DisplayRegion, presumably by the last successful cull
|
||||
// operation. This method is for the benefit of the
|
||||
// GraphicsEngine; normally you shouldn't call this
|
||||
// directly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SceneSetup *DisplayRegion::
|
||||
get_scene_setup() const {
|
||||
CDCullReader cdata(_cycler_cull);
|
||||
return cdata->_scene_setup;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CDataCull::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DisplayRegion::CDataCull::
|
||||
CDataCull() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CDataCull::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DisplayRegion::CDataCull::
|
||||
CDataCull(const DisplayRegion::CDataCull ©) :
|
||||
_cull_result(copy._cull_result),
|
||||
_scene_setup(copy._scene_setup)
|
||||
{
|
||||
}
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const DisplayRegion &dr) {
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@
|
|||
#include "texture.h"
|
||||
#include "camera.h"
|
||||
#include "dcast.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "pnmImage.h"
|
||||
|
||||
TypeHandle DisplayRegion::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::Constructor
|
||||
|
|
@ -33,12 +33,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::
|
||||
DisplayRegion(GraphicsOutput *window) :
|
||||
_l(0.), _r(1.), _b(0.), _t(1.),
|
||||
_window(window),
|
||||
_camera_node((Camera *)NULL),
|
||||
_active(true),
|
||||
_sort(0),
|
||||
_cube_map_index(-1)
|
||||
_window(window)
|
||||
{
|
||||
_draw_buffer_type = window->get_draw_buffer_type();
|
||||
compute_pixels();
|
||||
|
|
@ -50,17 +45,11 @@ DisplayRegion(GraphicsOutput *window) :
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::
|
||||
DisplayRegion(GraphicsOutput *window, const float l,
|
||||
const float r, const float b, const float t) :
|
||||
_l(l), _r(r), _b(b), _t(t),
|
||||
_window(window),
|
||||
_camera_node((Camera *)NULL),
|
||||
_active(true),
|
||||
_sort(0),
|
||||
_cube_map_index(-1)
|
||||
DisplayRegion(GraphicsOutput *window, float l, float r, float b, float t) :
|
||||
_window(window)
|
||||
{
|
||||
_draw_buffer_type = window->get_draw_buffer_type();
|
||||
compute_pixels();
|
||||
set_dimensions(l, r, b, t);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -109,7 +98,8 @@ void DisplayRegion::
|
|||
cleanup() {
|
||||
set_camera(NodePath());
|
||||
|
||||
_cull_result = NULL;
|
||||
CDCullWriter cdata(_cycler_cull, true);
|
||||
cdata->_cull_result = NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -121,11 +111,11 @@ cleanup() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
get_dimensions(float &l, float &r, float &b, float &t) const {
|
||||
MutexHolder holder(_lock);
|
||||
l = _l;
|
||||
r = _r;
|
||||
b = _b;
|
||||
t = _t;
|
||||
CDReader cdata(_cycler);
|
||||
l = cdata->_l;
|
||||
r = cdata->_r;
|
||||
b = cdata->_b;
|
||||
t = cdata->_t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -137,8 +127,8 @@ get_dimensions(float &l, float &r, float &b, float &t) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float DisplayRegion::
|
||||
get_left() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _l;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_l;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -150,8 +140,8 @@ get_left() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float DisplayRegion::
|
||||
get_right() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _r;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_r;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -163,8 +153,8 @@ get_right() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float DisplayRegion::
|
||||
get_bottom() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _b;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_b;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -176,8 +166,8 @@ get_bottom() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
float DisplayRegion::
|
||||
get_top() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _t;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -191,14 +181,17 @@ get_top() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
set_dimensions(float l, float r, float b, float t) {
|
||||
MutexHolder holder(_lock);
|
||||
_l = l;
|
||||
_r = r;
|
||||
_b = b;
|
||||
_t = t;
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
cdata->_l = l;
|
||||
cdata->_r = r;
|
||||
cdata->_b = b;
|
||||
cdata->_t = t;
|
||||
|
||||
if (_window != (GraphicsOutput *)NULL && _window->has_size()) {
|
||||
do_compute_pixels(_window->get_x_size(), _window->get_y_size());
|
||||
do_compute_pixels(_window->get_x_size(), _window->get_y_size(), cdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +204,6 @@ set_dimensions(float l, float r, float b, float t) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
GraphicsOutput *DisplayRegion::
|
||||
get_window() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _window;
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +216,6 @@ get_window() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
GraphicsPipe *DisplayRegion::
|
||||
get_pipe() const {
|
||||
MutexHolder holder(_lock);
|
||||
return (_window != (GraphicsOutput *)NULL) ? _window->get_pipe() : NULL;
|
||||
}
|
||||
|
||||
|
|
@ -242,25 +233,32 @@ get_pipe() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
set_camera(const NodePath &camera) {
|
||||
MutexHolder holder(_lock);
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDWriter cdata(_cycler);
|
||||
|
||||
Camera *camera_node = (Camera *)NULL;
|
||||
if (!camera.is_empty()) {
|
||||
DCAST_INTO_V(camera_node, camera.node());
|
||||
}
|
||||
|
||||
if (camera_node != _camera_node) {
|
||||
if (_camera_node != (Camera *)NULL) {
|
||||
if (camera_node != cdata->_camera_node) {
|
||||
// Note that these operations on the DisplayRegion are not
|
||||
// pipelined: they operate across all pipeline stages. Since we
|
||||
// have already asserted we are running in pipeline stage 0, no
|
||||
// problem.
|
||||
if (cdata->_camera_node != (Camera *)NULL) {
|
||||
// We need to tell the old camera we're not using him anymore.
|
||||
_camera_node->remove_display_region(this);
|
||||
cdata->_camera_node->remove_display_region(this);
|
||||
}
|
||||
_camera_node = camera_node;
|
||||
if (_camera_node != (Camera *)NULL) {
|
||||
cdata->_camera_node = camera_node;
|
||||
if (cdata->_camera_node != (Camera *)NULL) {
|
||||
// Now tell the new camera we are using him.
|
||||
_camera_node->add_display_region(this);
|
||||
cdata->_camera_node->add_display_region(this);
|
||||
}
|
||||
}
|
||||
|
||||
_camera = camera;
|
||||
cdata->_camera = camera;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -272,8 +270,8 @@ set_camera(const NodePath &camera) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
NodePath DisplayRegion::
|
||||
get_camera() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _camera;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_camera;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -285,9 +283,13 @@ get_camera() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
set_active(bool active) {
|
||||
MutexHolder holder(_lock);
|
||||
if (active != _active) {
|
||||
_active = active;
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
if (active != cdata->_active) {
|
||||
CDWriter cdataw(_cycler, cdata);
|
||||
cdataw->_active = active;
|
||||
win_display_regions_changed();
|
||||
}
|
||||
}
|
||||
|
|
@ -302,9 +304,13 @@ set_active(bool active) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
set_sort(int sort) {
|
||||
MutexHolder holder(_lock);
|
||||
if (sort != _sort) {
|
||||
_sort = sort;
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDReader cdata(_cycler);
|
||||
|
||||
if (sort != cdata->_sort) {
|
||||
CDWriter cdataw(_cycler, cdata);
|
||||
cdataw->_sort = sort;
|
||||
win_display_regions_changed();
|
||||
}
|
||||
}
|
||||
|
|
@ -318,9 +324,13 @@ set_sort(int sort) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
compute_pixels() {
|
||||
MutexHolder holder(_lock);
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
|
||||
if (_window != (GraphicsOutput *)NULL) {
|
||||
do_compute_pixels(_window->get_x_size(), _window->get_y_size());
|
||||
CDWriter cdata(_cycler);
|
||||
do_compute_pixels(_window->get_x_size(), _window->get_y_size(),
|
||||
cdata);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -333,8 +343,10 @@ compute_pixels() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
compute_pixels(int x_size, int y_size) {
|
||||
MutexHolder holder(_lock);
|
||||
do_compute_pixels(x_size, y_size);
|
||||
int pipeline_stage = Thread::get_current_pipeline_stage();
|
||||
nassertv(pipeline_stage == 0);
|
||||
CDWriter cdata(_cycler);
|
||||
do_compute_pixels(x_size, y_size, cdata);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -345,11 +357,11 @@ compute_pixels(int x_size, int y_size) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
get_pixels(int &pl, int &pr, int &pb, int &pt) const {
|
||||
MutexHolder holder(_lock);
|
||||
pl = _pl;
|
||||
pr = _pr;
|
||||
pb = _pb;
|
||||
pt = _pt;
|
||||
CDReader cdata(_cycler);
|
||||
pl = cdata->_pl;
|
||||
pr = cdata->_pr;
|
||||
pb = cdata->_pb;
|
||||
pt = cdata->_pt;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -361,11 +373,11 @@ get_pixels(int &pl, int &pr, int &pb, int &pt) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
get_region_pixels(int &xo, int &yo, int &w, int &h) const {
|
||||
MutexHolder holder(_lock);
|
||||
xo = _pl;
|
||||
yo = _pb;
|
||||
w = _pr - _pl;
|
||||
h = _pt - _pb;
|
||||
CDReader cdata(_cycler);
|
||||
xo = cdata->_pl;
|
||||
yo = cdata->_pb;
|
||||
w = cdata->_pr - cdata->_pl;
|
||||
h = cdata->_pt - cdata->_pb;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -378,11 +390,11 @@ get_region_pixels(int &xo, int &yo, int &w, int &h) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
get_region_pixels_i(int &xo, int &yo, int &w, int &h) const {
|
||||
MutexHolder holder(_lock);
|
||||
xo = _pl;
|
||||
yo = _pti;
|
||||
w = _pr - _pl;
|
||||
h = _pbi - _pti;
|
||||
CDReader cdata(_cycler);
|
||||
xo = cdata->_pl;
|
||||
yo = cdata->_pti;
|
||||
w = cdata->_pr - cdata->_pl;
|
||||
h = cdata->_pbi - cdata->_pti;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -392,8 +404,8 @@ get_region_pixels_i(int &xo, int &yo, int &w, int &h) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
int DisplayRegion::
|
||||
get_pixel_width() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _pr - _pl;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_pr - cdata->_pl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -403,8 +415,8 @@ get_pixel_width() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
int DisplayRegion::
|
||||
get_pixel_height() const {
|
||||
MutexHolder holder(_lock);
|
||||
return _pt - _pb;
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_pt - cdata->_pb;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -414,9 +426,10 @@ get_pixel_height() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
output(ostream &out) const {
|
||||
MutexHolder holder(_lock);
|
||||
out << "DisplayRegion(" << _l << " " << _r << " " << _b << " " << _t
|
||||
<< ")=pixels(" << _pl << " " << _pr << " " << _pb << " " << _pt
|
||||
CDReader cdata(_cycler);
|
||||
out << "DisplayRegion(" << cdata->_l << " " << cdata->_r << " "
|
||||
<< cdata->_b << " " << cdata->_t << ")=pixels(" << cdata->_pl
|
||||
<< " " << cdata->_pr << " " << cdata->_pb << " " << cdata->_pt
|
||||
<< ")";
|
||||
}
|
||||
|
||||
|
|
@ -593,28 +606,88 @@ win_display_regions_changed() {
|
|||
// assumes that we already have the lock.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DisplayRegion::
|
||||
do_compute_pixels(int x_size, int y_size) {
|
||||
do_compute_pixels(int x_size, int y_size, CData *cdata) {
|
||||
if (display_cat.is_debug()) {
|
||||
display_cat.debug()
|
||||
<< "DisplayRegion::do_compute_pixels(" << x_size << ", " << y_size << ")\n";
|
||||
}
|
||||
|
||||
_pl = int((_l * x_size) + 0.5);
|
||||
_pr = int((_r * x_size) + 0.5);
|
||||
cdata->_pl = int((cdata->_l * x_size) + 0.5);
|
||||
cdata->_pr = int((cdata->_r * x_size) + 0.5);
|
||||
|
||||
nassertv(_window != (GraphicsOutput *)NULL);
|
||||
if (_window->get_inverted()) {
|
||||
// The window is inverted; compute the DisplayRegion accordingly.
|
||||
_pb = int(((1.0f - _t) * y_size) + 0.5);
|
||||
_pt = int(((1.0f - _b) * y_size) + 0.5);
|
||||
_pbi = int((_t * y_size) + 0.5);
|
||||
_pti = int((_b * y_size) + 0.5);
|
||||
cdata->_pb = int(((1.0f - cdata->_t) * y_size) + 0.5);
|
||||
cdata->_pt = int(((1.0f - cdata->_b) * y_size) + 0.5);
|
||||
cdata->_pbi = int((cdata->_t * y_size) + 0.5);
|
||||
cdata->_pti = int((cdata->_b * y_size) + 0.5);
|
||||
|
||||
} else {
|
||||
// The window is normal.
|
||||
_pb = int((_b * y_size) + 0.5);
|
||||
_pt = int((_t * y_size) + 0.5);
|
||||
_pbi = int(((1.0f - _b) * y_size) + 0.5);
|
||||
_pti = int(((1.0f - _t) * y_size) + 0.5);
|
||||
cdata->_pb = int((cdata->_b * y_size) + 0.5);
|
||||
cdata->_pt = int((cdata->_t * y_size) + 0.5);
|
||||
cdata->_pbi = int(((1.0f - cdata->_b) * y_size) + 0.5);
|
||||
cdata->_pti = int(((1.0f - cdata->_t) * y_size) + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::CData::
|
||||
CData() :
|
||||
_l(0.), _r(1.), _b(0.), _t(1.),
|
||||
_camera_node((Camera *)NULL),
|
||||
_active(true),
|
||||
_sort(0),
|
||||
_cube_map_index(-1)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CData::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DisplayRegion::CData::
|
||||
CData(const DisplayRegion::CData ©) :
|
||||
_l(copy._l),
|
||||
_r(copy._r),
|
||||
_b(copy._b),
|
||||
_t(copy._t),
|
||||
_pl(copy._pl),
|
||||
_pr(copy._pr),
|
||||
_pb(copy._pb),
|
||||
_pt(copy._pt),
|
||||
_pbi(copy._pbi),
|
||||
_pti(copy._pti),
|
||||
_camera(copy._camera),
|
||||
_camera_node(copy._camera_node),
|
||||
_active(copy._active),
|
||||
_sort(copy._sort),
|
||||
_cube_map_index(copy._cube_map_index)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *DisplayRegion::CData::
|
||||
make_copy() const {
|
||||
return new CData(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DisplayRegion::CDataCull::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *DisplayRegion::CDataCull::
|
||||
make_copy() const {
|
||||
return new CDataCull(*this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef DISPLAYREGION_H
|
||||
#define DISPLAYREGION_H
|
||||
|
||||
|
|
@ -24,8 +25,12 @@
|
|||
#include "referenceCount.h"
|
||||
#include "nodePath.h"
|
||||
#include "cullResult.h"
|
||||
#include "sceneSetup.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmutex.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
#include "pipelineCycler.h"
|
||||
#include "config_display.h"
|
||||
|
||||
#include "plist.h"
|
||||
|
|
@ -51,8 +56,7 @@ class EXPCL_PANDA DisplayRegion : public ReferenceCount, public DrawableRegion {
|
|||
protected:
|
||||
DisplayRegion(GraphicsOutput *window);
|
||||
DisplayRegion(GraphicsOutput *window,
|
||||
const float l, const float r,
|
||||
const float b, const float t);
|
||||
float l, float r, float b, float t);
|
||||
private:
|
||||
DisplayRegion(const DisplayRegion ©);
|
||||
void operator = (const DisplayRegion ©);
|
||||
|
|
@ -102,40 +106,95 @@ PUBLISHED:
|
|||
bool save_screenshot(const Filename &filename);
|
||||
bool get_screenshot(PNMImage &image);
|
||||
|
||||
public:
|
||||
INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup);
|
||||
INLINE CullResult *get_cull_result() const;
|
||||
INLINE SceneSetup *get_scene_setup() const;
|
||||
|
||||
private:
|
||||
class CData;
|
||||
|
||||
void win_display_regions_changed();
|
||||
void do_compute_pixels(int x_size, int y_size);
|
||||
Mutex _lock;
|
||||
|
||||
float _l;
|
||||
float _r;
|
||||
float _b;
|
||||
float _t;
|
||||
|
||||
int _pl;
|
||||
int _pr;
|
||||
int _pb;
|
||||
int _pt;
|
||||
int _pbi;
|
||||
int _pti;
|
||||
void do_compute_pixels(int x_size, int y_size, CData *cdata);
|
||||
|
||||
// The associated window is a permanent property of the
|
||||
// DisplayRegion. It doesn't need to be cycled.
|
||||
GraphicsOutput *_window;
|
||||
NodePath _camera;
|
||||
|
||||
// This needs to be a PT(Camera) so we prevent the Camera node from
|
||||
// destructing while we hold its pointer.
|
||||
PT(Camera) _camera_node;
|
||||
// This is the data that is associated with the DisplayRegion that
|
||||
// needs to be cycled every frame, but represents the parameters as
|
||||
// specified by the user, and which probably will not change that
|
||||
// often.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
CData();
|
||||
CData(const CData ©);
|
||||
|
||||
bool _active;
|
||||
int _sort;
|
||||
int _cube_map_index;
|
||||
virtual CycleData *make_copy() const;
|
||||
virtual TypeHandle get_parent_type() const {
|
||||
return DisplayRegion::get_class_type();
|
||||
}
|
||||
|
||||
// This is used to cache the culling result from last frame's
|
||||
// drawing into this display region. It should only be accessed or
|
||||
// modified by the GraphicsEngine, during the cull traversal.
|
||||
PT(CullResult) _cull_result;
|
||||
float _l;
|
||||
float _r;
|
||||
float _b;
|
||||
float _t;
|
||||
|
||||
int _pl;
|
||||
int _pr;
|
||||
int _pb;
|
||||
int _pt;
|
||||
int _pbi;
|
||||
int _pti;
|
||||
|
||||
NodePath _camera;
|
||||
Camera *_camera_node;
|
||||
|
||||
bool _active;
|
||||
int _sort;
|
||||
int _cube_map_index;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
// This is a special cycler created to hold the results from the
|
||||
// cull traversal, for (a) the draw traversal, and (b) the next
|
||||
// frame's cull traversal. It needs to be cycled, but it gets its
|
||||
// own cycler because it will certainly change every frame, so we
|
||||
// don't need to lump all the heavy data above in with this
|
||||
// lightweight cycler.
|
||||
class EXPCL_PANDA CDataCull : public CycleData {
|
||||
public:
|
||||
CDataCull();
|
||||
CDataCull(const CDataCull ©);
|
||||
|
||||
virtual CycleData *make_copy() const;
|
||||
virtual TypeHandle get_parent_type() const {
|
||||
return DisplayRegion::get_class_type();
|
||||
}
|
||||
|
||||
PT(CullResult) _cull_result;
|
||||
PT(SceneSetup) _scene_setup;
|
||||
};
|
||||
PipelineCycler<CDataCull> _cycler_cull;
|
||||
typedef CycleDataReader<CDataCull> CDCullReader;
|
||||
typedef CycleDataWriter<CDataCull> CDCullWriter;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
ReferenceCount::init_type();
|
||||
register_type(_type_handle, "DisplayRegion",
|
||||
ReferenceCount::get_class_type());
|
||||
}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class GraphicsEngine;
|
||||
friend class GraphicsOutput;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -149,13 +149,14 @@ get_frame_buffer_properties() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
set_threading_model(const GraphicsThreadingModel &threading_model) {
|
||||
if (!threading_model.is_single_threaded() &&
|
||||
!Thread::is_threading_supported()) {
|
||||
#ifndef THREADED_PIPELINE
|
||||
if (!threading_model.is_single_threaded()) {
|
||||
display_cat.warning()
|
||||
<< "Threading model " << threading_model
|
||||
<< " requested but threading not supported.\n";
|
||||
<< " requested but multithreaded render pipelines not enabled in build.\n";
|
||||
return;
|
||||
}
|
||||
#endif // THREADED_PIPELINE
|
||||
MutexHolder holder(_lock);
|
||||
_threading_model = threading_model;
|
||||
}
|
||||
|
|
@ -712,7 +713,7 @@ void GraphicsEngine::
|
|||
render_subframe(GraphicsOutput *win, DisplayRegion *dr,
|
||||
bool cull_sorting) {
|
||||
if (cull_sorting) {
|
||||
cull_bin_draw(win, dr);
|
||||
cull_to_bins(win, dr);
|
||||
} else {
|
||||
cull_and_draw_together(win, dr);
|
||||
}
|
||||
|
|
@ -740,7 +741,7 @@ add_callback(const string &thread_name,
|
|||
GraphicsEngine::CallbackTime callback_time,
|
||||
GraphicsEngine::CallbackFunction *func, void *data) {
|
||||
MutexHolder holder(_lock);
|
||||
WindowRenderer *wr = get_window_renderer(thread_name);
|
||||
WindowRenderer *wr = get_window_renderer(thread_name, 0);
|
||||
return wr->add_callback(callback_time, Callback(func, data));
|
||||
}
|
||||
|
||||
|
|
@ -757,11 +758,11 @@ add_callback(const string &thread_name,
|
|||
// removed).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GraphicsEngine::
|
||||
remove_callback(const string &thread_name,
|
||||
remove_callback(const string &thread_name,
|
||||
GraphicsEngine::CallbackTime callback_time,
|
||||
GraphicsEngine::CallbackFunction *func, void *data) {
|
||||
MutexHolder holder(_lock);
|
||||
WindowRenderer *wr = get_window_renderer(thread_name);
|
||||
WindowRenderer *wr = get_window_renderer(thread_name, 0);
|
||||
return wr->remove_callback(callback_time, Callback(func, data));
|
||||
}
|
||||
|
||||
|
|
@ -857,7 +858,7 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::cull_bin_draw
|
||||
// Function: GraphicsEngine::cull_to_bins
|
||||
// Access: Private
|
||||
// Description: This is called in the cull thread by individual
|
||||
// RenderThread objects during the frame rendering. It
|
||||
|
|
@ -865,12 +866,68 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr) {
|
|||
// drawing.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_bin_draw(const GraphicsEngine::Windows &wlist) {
|
||||
cull_to_bins(const GraphicsEngine::Windows &wlist) {
|
||||
Windows::const_iterator wi;
|
||||
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
if (win->is_active() && win->get_gsg()->is_active()) {
|
||||
int num_display_regions = win->get_num_active_display_regions();
|
||||
for (int i = 0; i < num_display_regions; ++i) {
|
||||
DisplayRegion *dr = win->get_active_display_region(i);
|
||||
if (dr != (DisplayRegion *)NULL) {
|
||||
cull_to_bins(win, dr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::cull_to_bins
|
||||
// Access: Private
|
||||
// Description: This variant of cull_to_bins() is called
|
||||
// by render_subframe(), as well as within the
|
||||
// implementation of cull_to_bins(), above.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_to_bins(GraphicsOutput *win, DisplayRegion *dr) {
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertv(gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
PT(CullResult) cull_result = dr->get_cull_result();
|
||||
if (cull_result != (CullResult *)NULL) {
|
||||
cull_result = cull_result->make_next();
|
||||
} else {
|
||||
cull_result = new CullResult(gsg);
|
||||
}
|
||||
|
||||
PT(SceneSetup) scene_setup = setup_scene(gsg, dr);
|
||||
if (scene_setup != (SceneSetup *)NULL) {
|
||||
BinCullHandler cull_handler(cull_result);
|
||||
do_cull(&cull_handler, scene_setup, gsg);
|
||||
|
||||
cull_result->finish_cull();
|
||||
|
||||
// Save the results for next frame.
|
||||
dr->set_cull_result(cull_result, scene_setup);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::draw_bins
|
||||
// Access: Private
|
||||
// Description: This is called in the draw thread by individual
|
||||
// RenderThread objects during the frame rendering. It
|
||||
// issues the graphics commands to draw the objects that
|
||||
// have been collected into bins by a previous call to
|
||||
// cull_to_bins().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
draw_bins(const GraphicsEngine::Windows &wlist) {
|
||||
Windows::const_iterator wi;
|
||||
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
if (win->is_active() && win->get_gsg()->is_active()) {
|
||||
// This should be done in the draw thread, not here.
|
||||
if (win->begin_frame(GraphicsOutput::FM_render)) {
|
||||
win->clear();
|
||||
|
||||
|
|
@ -878,7 +935,7 @@ cull_bin_draw(const GraphicsEngine::Windows &wlist) {
|
|||
for (int i = 0; i < num_display_regions; ++i) {
|
||||
DisplayRegion *dr = win->get_active_display_region(i);
|
||||
if (dr != (DisplayRegion *)NULL) {
|
||||
cull_bin_draw(win, dr);
|
||||
draw_bins(win, dr);
|
||||
}
|
||||
}
|
||||
win->end_frame(GraphicsOutput::FM_render);
|
||||
|
|
@ -901,36 +958,20 @@ cull_bin_draw(const GraphicsEngine::Windows &wlist) {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::cull_bin_draw
|
||||
// Function: GraphicsEngine::draw_bins
|
||||
// Access: Private
|
||||
// Description: This variant of cull_bin_draw() is called
|
||||
// by render_subframe(), as well as within the
|
||||
// implementation of cull_bin_draw(), above.
|
||||
// Description: This variant on draw_bins() is only called from
|
||||
// draw_bins(), above. It draws the cull result for a
|
||||
// particular DisplayRegion.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
cull_bin_draw(GraphicsOutput *win, DisplayRegion *dr) {
|
||||
draw_bins(GraphicsOutput *win, DisplayRegion *dr) {
|
||||
GraphicsStateGuardian *gsg = win->get_gsg();
|
||||
nassertv(gsg != (GraphicsStateGuardian *)NULL);
|
||||
|
||||
PT(CullResult) cull_result = dr->_cull_result;
|
||||
if (cull_result != (CullResult *)NULL) {
|
||||
cull_result = cull_result->make_next();
|
||||
} else {
|
||||
cull_result = new CullResult(gsg);
|
||||
}
|
||||
|
||||
PT(SceneSetup) scene_setup = setup_scene(gsg, dr);
|
||||
if (scene_setup != (SceneSetup *)NULL) {
|
||||
BinCullHandler cull_handler(cull_result);
|
||||
do_cull(&cull_handler, scene_setup, gsg);
|
||||
|
||||
cull_result->finish_cull();
|
||||
|
||||
// Save the results for next frame.
|
||||
dr->_cull_result = cull_result;
|
||||
|
||||
// Now draw.
|
||||
// This should get deferred into the next pipeline stage.
|
||||
PT(CullResult) cull_result = dr->get_cull_result();
|
||||
PT(SceneSetup) scene_setup = dr->get_scene_setup();
|
||||
if (cull_result != (CullResult *)NULL && scene_setup != (SceneSetup *)NULL) {
|
||||
do_draw(cull_result, scene_setup, win, dr);
|
||||
}
|
||||
}
|
||||
|
|
@ -1046,7 +1087,7 @@ do_flip_frame() {
|
|||
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
|
||||
RenderThread *thread = (*ti).second;
|
||||
thread->_cv_mutex.lock();
|
||||
|
||||
|
||||
while (thread->_thread_state != TS_wait) {
|
||||
thread->_cv_done.wait();
|
||||
}
|
||||
|
|
@ -1269,8 +1310,12 @@ do_add_window(GraphicsOutput *window, GraphicsStateGuardian *gsg,
|
|||
_windows_sorted = false;
|
||||
_windows.push_back(window);
|
||||
|
||||
WindowRenderer *cull = get_window_renderer(threading_model.get_cull_name());
|
||||
WindowRenderer *draw = get_window_renderer(threading_model.get_draw_name());
|
||||
WindowRenderer *cull =
|
||||
get_window_renderer(threading_model.get_cull_name(),
|
||||
threading_model.get_cull_stage());
|
||||
WindowRenderer *draw =
|
||||
get_window_renderer(threading_model.get_draw_name(),
|
||||
threading_model.get_draw_stage());
|
||||
draw->add_gsg(gsg);
|
||||
|
||||
if (threading_model.get_cull_sorting()) {
|
||||
|
|
@ -1438,11 +1483,15 @@ get_invert_polygon_state() {
|
|||
// Access: Private
|
||||
// Description: Returns the WindowRenderer with the given name.
|
||||
// Creates a new RenderThread if there is no such thread
|
||||
// already. You must already be holding the lock before
|
||||
// calling this method.
|
||||
// already. The pipeline_stage number specifies the
|
||||
// pipeline stage that will be assigned to the thread
|
||||
// (unless was previously given a higher stage).
|
||||
//
|
||||
// You must already be holding the lock before calling
|
||||
// this method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GraphicsEngine::WindowRenderer *GraphicsEngine::
|
||||
get_window_renderer(const string &name) {
|
||||
get_window_renderer(const string &name, int pipeline_stage) {
|
||||
nassertr(_lock.debug_is_locked(), NULL);
|
||||
|
||||
if (name.empty()) {
|
||||
|
|
@ -1455,8 +1504,8 @@ get_window_renderer(const string &name) {
|
|||
}
|
||||
|
||||
PT(RenderThread) thread = new RenderThread(name, this);
|
||||
thread->set_pipeline_stage(1);
|
||||
_pipeline->set_min_stages(2);
|
||||
thread->set_min_pipeline_stage(pipeline_stage);
|
||||
_pipeline->set_min_stages(pipeline_stage + 1);
|
||||
|
||||
thread->start(TP_normal, true, true);
|
||||
_threads[name] = thread;
|
||||
|
|
@ -1592,8 +1641,9 @@ do_frame(GraphicsEngine *engine) {
|
|||
|
||||
do_callbacks(CB_pre_frame);
|
||||
|
||||
engine->cull_bin_draw(_cull);
|
||||
engine->cull_to_bins(_cull);
|
||||
engine->cull_and_draw_together(_cdraw);
|
||||
engine->draw_bins(_draw);
|
||||
engine->process_events(_window);
|
||||
|
||||
// If any GSG's on the list have no more outstanding pointers, clean
|
||||
|
|
|
|||
|
|
@ -145,8 +145,10 @@ private:
|
|||
void cull_and_draw_together(const Windows &wlist);
|
||||
void cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr);
|
||||
|
||||
void cull_bin_draw(const Windows &wlist);
|
||||
void cull_bin_draw(GraphicsOutput *win, DisplayRegion *dr);
|
||||
void cull_to_bins(const Windows &wlist);
|
||||
void cull_to_bins(GraphicsOutput *win, DisplayRegion *dr);
|
||||
void draw_bins(const Windows &wlist);
|
||||
void draw_bins(GraphicsOutput *win, DisplayRegion *dr);
|
||||
void make_contexts(const Windows &wlist);
|
||||
|
||||
void process_events(const Windows &wlist);
|
||||
|
|
@ -222,7 +224,7 @@ private:
|
|||
ThreadState _thread_state;
|
||||
};
|
||||
|
||||
WindowRenderer *get_window_renderer(const string &name);
|
||||
WindowRenderer *get_window_renderer(const string &name, int pipeline_stage);
|
||||
|
||||
Pipeline *_pipeline;
|
||||
Windows _windows;
|
||||
|
|
|
|||
|
|
@ -814,7 +814,7 @@ static ShowBuffersCubeMapRegions cube_map_regions[6] = {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
GraphicsOutput *GraphicsOutput::
|
||||
make_cube_map(const string &name, int size, NodePath &camera_rig,
|
||||
DrawMask camera_mask, bool to_ram) {
|
||||
DrawMask camera_mask, bool to_ram) {
|
||||
if (!to_ram) {
|
||||
// Check the limits imposed by the GSG. (However, if we're
|
||||
// rendering the texture to RAM only, these limits may be
|
||||
|
|
|
|||
|
|
@ -872,7 +872,6 @@ begin_draw_primitives(const Geom *geom, const GeomMunger *munger,
|
|||
const GeomVertexData *data) {
|
||||
_munger = munger;
|
||||
_vertex_data = data;
|
||||
|
||||
nassertr(geom->check_valid(data), false);
|
||||
return _vertex_data->has_vertex();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,9 @@
|
|||
INLINE GraphicsThreadingModel::
|
||||
GraphicsThreadingModel(const GraphicsThreadingModel ©) :
|
||||
_cull_name(copy._cull_name),
|
||||
_cull_stage(copy._cull_stage),
|
||||
_draw_name(copy._draw_name),
|
||||
_draw_stage(copy._draw_stage),
|
||||
_cull_sorting(copy._cull_sorting)
|
||||
{
|
||||
}
|
||||
|
|
@ -38,7 +40,9 @@ GraphicsThreadingModel(const GraphicsThreadingModel ©) :
|
|||
INLINE void GraphicsThreadingModel::
|
||||
operator = (const GraphicsThreadingModel ©) {
|
||||
_cull_name = copy._cull_name;
|
||||
_cull_stage = copy._cull_stage;
|
||||
_draw_name = copy._draw_name;
|
||||
_draw_stage = copy._draw_stage;
|
||||
_cull_sorting = copy._cull_sorting;
|
||||
}
|
||||
|
||||
|
|
@ -53,6 +57,19 @@ get_cull_name() const {
|
|||
return _cull_name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsThreadingModel::get_cull_stage
|
||||
// Access: Published
|
||||
// Description: Returns the pipeline stage from which the cull thread
|
||||
// should access data. This will be 0 if the cull is
|
||||
// run in the same thread as app, or 1 if it is its own
|
||||
// thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int GraphicsThreadingModel::
|
||||
get_cull_stage() const {
|
||||
return _cull_stage;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsThreadingModel::get_draw_name
|
||||
// Access: Published
|
||||
|
|
@ -65,6 +82,20 @@ get_draw_name() const {
|
|||
return _draw_name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsThreadingModel::get_draw_stage
|
||||
// Access: Published
|
||||
// Description: Returns the pipeline stage from which the draw thread
|
||||
// should access data. This will be the same value as
|
||||
// get_cull_stage() if cull and draw are run in the same
|
||||
// thread, or one more than that value if draw should be
|
||||
// in its own thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int GraphicsThreadingModel::
|
||||
get_draw_stage() const {
|
||||
return _draw_stage;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsThreadingModel::get_cull_sorting
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -64,9 +64,20 @@ GraphicsThreadingModel(const string &model) {
|
|||
_cull_name = model.substr(start, slash - start);
|
||||
_draw_name = model.substr(slash + 1);
|
||||
}
|
||||
if (_cull_name.empty()) {
|
||||
_cull_stage = 0;
|
||||
} else {
|
||||
_cull_stage = 1;
|
||||
}
|
||||
if (!_cull_sorting || _draw_name.empty()) {
|
||||
_draw_name = _cull_name;
|
||||
}
|
||||
|
||||
if (_draw_name == _cull_name) {
|
||||
_draw_stage = _cull_stage;
|
||||
} else {
|
||||
_draw_stage = _cull_stage + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ PUBLISHED:
|
|||
|
||||
string get_model() const;
|
||||
INLINE const string &get_cull_name() const;
|
||||
INLINE int get_cull_stage() const;
|
||||
INLINE const string &get_draw_name() const;
|
||||
INLINE int get_draw_stage() const;
|
||||
INLINE bool get_cull_sorting() const;
|
||||
|
||||
INLINE bool is_single_threaded() const;
|
||||
|
|
@ -43,7 +45,9 @@ PUBLISHED:
|
|||
|
||||
private:
|
||||
string _cull_name;
|
||||
int _cull_stage;
|
||||
string _draw_name;
|
||||
int _draw_stage;
|
||||
bool _cull_sorting;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,6 @@
|
|||
#include "collisionPolygon.h"
|
||||
#include "parametricCurve.h"
|
||||
#include "nurbsCurve.h"
|
||||
#include "classicNurbsCurve.h"
|
||||
#include "nurbsCurveInterface.h"
|
||||
#include "nurbsCurveEvaluator.h"
|
||||
#include "nurbsSurfaceEvaluator.h"
|
||||
|
|
@ -665,10 +664,10 @@ make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_old_nurbs_curve
|
||||
// Access: Private
|
||||
// Description: This deprecated interface creates a NurbsCurve (or a
|
||||
// ClassicNurbsCurve) object for the EggNurbsCurve
|
||||
// entry. It will eventually be removed in favor of the
|
||||
// above, which creates a RopeNode.
|
||||
// Description: This deprecated interface creates a NurbsCurve object
|
||||
// for the EggNurbsCurve entry. It will eventually be
|
||||
// removed in favor of the above, which creates a
|
||||
// RopeNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggLoader::
|
||||
make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
|
||||
|
|
@ -677,12 +676,7 @@ make_old_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
|
|||
assert(!parent->is_geom_node());
|
||||
|
||||
PT(ParametricCurve) curve;
|
||||
|
||||
if (egg_load_classic_nurbs_curves) {
|
||||
curve = new ClassicNurbsCurve;
|
||||
} else {
|
||||
curve = new NurbsCurve;
|
||||
}
|
||||
curve = new NurbsCurve;
|
||||
|
||||
NurbsCurveInterface *nurbs = curve->get_nurbs_interface();
|
||||
nassertv(nurbs != (NurbsCurveInterface *)NULL);
|
||||
|
|
|
|||
|
|
@ -17,8 +17,11 @@
|
|||
bigEndian.h buffer.I buffer.h \
|
||||
checksumHashGenerator.I checksumHashGenerator.h circBuffer.I \
|
||||
circBuffer.h clockObject.I clockObject.h \
|
||||
conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
|
||||
conditionVar.I conditionVarImpl.h \
|
||||
conditionVar.h conditionVar.I \
|
||||
conditionVarDebug.h conditionVarDebug.I \
|
||||
conditionVarDirect.h conditionVarDirect.I \
|
||||
conditionVarDummyImpl.h conditionVarDummyImpl.I \
|
||||
conditionVarImpl.h \
|
||||
conditionVarNsprImpl.h conditionVarNsprImpl.I \
|
||||
conditionVarPosixImpl.h conditionVarPosixImpl.I \
|
||||
conditionVarWin32Impl.h conditionVarWin32Impl.I \
|
||||
|
|
@ -40,8 +43,11 @@
|
|||
memoryUsagePointerCounts.I memoryUsagePointerCounts.h \
|
||||
memoryUsagePointers.I memoryUsagePointers.h \
|
||||
multifile.I multifile.h \
|
||||
mutexDummyImpl.h mutexDummyImpl.I pmutex.h mutexHolder.h \
|
||||
mutexHolder.I pmutex.I mutexImpl.h \
|
||||
mutexDebug.h mutexDebug.I \
|
||||
mutexDirect.h mutexDirect.I \
|
||||
mutexDummyImpl.h mutexDummyImpl.I \
|
||||
mutexHolder.h mutexHolder.I \
|
||||
mutexImpl.h \
|
||||
mutexNsprImpl.h mutexNsprImpl.I \
|
||||
mutexPosixImpl.h mutexPosixImpl.I \
|
||||
mutexWin32Impl.h mutexWin32Impl.I \
|
||||
|
|
@ -51,6 +57,7 @@
|
|||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||
password_hash.h \
|
||||
patchfile.I patchfile.h \
|
||||
pmutex.h pmutex.I \
|
||||
pointerTo.I pointerTo.h \
|
||||
pointerToArray.I pointerToArray.h \
|
||||
pointerToBase.I pointerToBase.h \
|
||||
|
|
@ -60,6 +67,7 @@
|
|||
ramfile.I ramfile.h \
|
||||
referenceCount.I referenceCount.h \
|
||||
reMutex.I reMutex.h \
|
||||
reMutexDirect.h reMutexDirect.I \
|
||||
reMutexHolder.I reMutexHolder.h \
|
||||
reversedNumericData.I reversedNumericData.h \
|
||||
selectThreadImpl.h \
|
||||
|
|
@ -96,7 +104,10 @@
|
|||
atomicAdjustPosixImpl.cxx \
|
||||
atomicAdjustWin32Impl.cxx \
|
||||
buffer.cxx checksumHashGenerator.cxx clockObject.cxx \
|
||||
conditionVar.cxx conditionVarDummyImpl.cxx \
|
||||
conditionVar.cxx \
|
||||
conditionVarDebug.cxx \
|
||||
conditionVarDirect.cxx \
|
||||
conditionVarDummyImpl.cxx \
|
||||
conditionVarNsprImpl.cxx \
|
||||
conditionVarPosixImpl.cxx \
|
||||
conditionVarWin32Impl.cxx \
|
||||
|
|
@ -110,10 +121,14 @@
|
|||
mainThread.cxx \
|
||||
memoryInfo.cxx memoryUsage.cxx memoryUsagePointerCounts.cxx \
|
||||
memoryUsagePointers.cxx multifile.cxx \
|
||||
pmutex.cxx mutexHolder.cxx mutexDummyImpl.cxx \
|
||||
mutexDebug.cxx \
|
||||
mutexDirect.cxx \
|
||||
mutexHolder.cxx \
|
||||
mutexDummyImpl.cxx \
|
||||
mutexNsprImpl.cxx \
|
||||
mutexPosixImpl.cxx \
|
||||
mutexWin32Impl.cxx \
|
||||
pmutex.cxx \
|
||||
namable.cxx \
|
||||
nativeNumericData.cxx \
|
||||
ordered_vector.cxx \
|
||||
|
|
@ -128,6 +143,7 @@
|
|||
ramfile.cxx \
|
||||
referenceCount.cxx \
|
||||
reMutex.cxx \
|
||||
reMutexDirect.cxx \
|
||||
reMutexHolder.cxx \
|
||||
reversedNumericData.cxx \
|
||||
streamReader.cxx streamWriter.cxx \
|
||||
|
|
@ -162,8 +178,11 @@
|
|||
bigEndian.h buffer.I buffer.h checksumHashGenerator.I \
|
||||
checksumHashGenerator.h circBuffer.I circBuffer.h clockObject.I \
|
||||
clockObject.h \
|
||||
conditionVarDummyImpl.h conditionVarDummyImpl.I conditionVar.h \
|
||||
conditionVar.I conditionVarImpl.h \
|
||||
conditionVar.h conditionVar.I \
|
||||
conditionVarDebug.h conditionVarDebug.I \
|
||||
conditionVarDirect.h conditionVarDirect.I \
|
||||
conditionVarDummyImpl.h conditionVarDummyImpl.I \
|
||||
conditionVarImpl.h \
|
||||
conditionVarNsprImpl.h conditionVarNsprImpl.I \
|
||||
conditionVarPosixImpl.h conditionVarPosixImpl.I \
|
||||
conditionVarWin32Impl.h conditionVarWin32Impl.I \
|
||||
|
|
@ -183,8 +202,11 @@
|
|||
memoryUsage.h memoryUsagePointerCounts.I \
|
||||
memoryUsagePointerCounts.h memoryUsagePointers.I \
|
||||
memoryUsagePointers.h multifile.I multifile.h \
|
||||
mutexDummyImpl.h mutexDummyImpl.I pmutex.h mutexHolder.h \
|
||||
mutexHolder.I pmutex.I mutexImpl.h \
|
||||
mutexDebug.h mutexDebug.I \
|
||||
mutexDirect.h mutexDirect.I \
|
||||
mutexDummyImpl.h mutexDummyImpl.I \
|
||||
mutexHolder.h mutexHolder.I \
|
||||
mutexImpl.h \
|
||||
mutexNsprImpl.h mutexNsprImpl.I \
|
||||
mutexPosixImpl.h mutexPosixImpl.I \
|
||||
mutexWin32Impl.h mutexWin32Impl.I \
|
||||
|
|
@ -193,6 +215,7 @@
|
|||
ordered_vector.h ordered_vector.I ordered_vector.T \
|
||||
password_hash.h \
|
||||
patchfile.I patchfile.h \
|
||||
pmutex.h pmutex.I \
|
||||
pointerTo.I pointerTo.h \
|
||||
pointerToArray.I pointerToArray.h \
|
||||
pointerToBase.I pointerToBase.h \
|
||||
|
|
@ -202,6 +225,7 @@
|
|||
ramfile.I ramfile.h \
|
||||
referenceCount.I referenceCount.h \
|
||||
reMutex.I reMutex.h \
|
||||
reMutexDirect.h reMutexDirect.I \
|
||||
reMutexHolder.I reMutexHolder.h \
|
||||
reversedNumericData.I reversedNumericData.h \
|
||||
selectThreadImpl.h \
|
||||
|
|
|
|||
|
|
@ -49,3 +49,17 @@ INLINE PN_int32 AtomicAdjust::
|
|||
set(PN_int32 &var, PN_int32 new_value) {
|
||||
return AtomicAdjustImpl::set(var, new_value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AtomicAdjust::get
|
||||
// Access: Public, Static
|
||||
// Description: Atomically retrieves the snapshot value of the
|
||||
// indicated variable. This is the only guaranteed safe
|
||||
// way to retrieve the value that other threads might be
|
||||
// asynchronously setting, incrementing, or decrementing
|
||||
// (via other AtomicAjust methods).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_int32 AtomicAdjust::
|
||||
get(const PN_int32 &var) {
|
||||
return AtomicAdjustImpl::get(var);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ public:
|
|||
INLINE static PN_int32 inc(PN_int32 &var);
|
||||
INLINE static PN_int32 dec(PN_int32 &var);
|
||||
INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
|
||||
INLINE static PN_int32 get(const PN_int32 &var);
|
||||
};
|
||||
|
||||
#include "atomicAdjust.I"
|
||||
|
|
|
|||
|
|
@ -51,3 +51,17 @@ set(PN_int32 &var, PN_int32 new_value) {
|
|||
var = new_value;
|
||||
return orig_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AtomicAdjustDummyImpl::get
|
||||
// Access: Public, Static
|
||||
// Description: Atomically retrieves the snapshot value of the
|
||||
// indicated variable. This is the only guaranteed safe
|
||||
// way to retrieve the value that other threads might be
|
||||
// asynchronously setting, incrementing, or decrementing
|
||||
// (via other AtomicAjust methods).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_int32 AtomicAdjustDummyImpl::
|
||||
get(const PN_int32 &var) {
|
||||
return var;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public:
|
|||
INLINE static PN_int32 inc(PN_int32 &var);
|
||||
INLINE static PN_int32 dec(PN_int32 &var);
|
||||
INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
|
||||
INLINE static PN_int32 get(const PN_int32 &var);
|
||||
};
|
||||
|
||||
#include "atomicAdjustDummyImpl.I"
|
||||
|
|
|
|||
|
|
@ -49,3 +49,17 @@ INLINE PN_int32 AtomicAdjustNsprImpl::
|
|||
set(PN_int32 &var, PN_int32 new_value) {
|
||||
return PR_AtomicSet(&var, new_value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AtomicAdjustNsprImpl::get
|
||||
// Access: Public, Static
|
||||
// Description: Atomically retrieves the snapshot value of the
|
||||
// indicated variable. This is the only guaranteed safe
|
||||
// way to retrieve the value that other threads might be
|
||||
// asynchronously setting, incrementing, or decrementing
|
||||
// (via other AtomicAjust methods).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_int32 AtomicAdjustNsprImpl::
|
||||
get(const PN_int32 &var) {
|
||||
return var;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public:
|
|||
INLINE static PN_int32 inc(PN_int32 &var);
|
||||
INLINE static PN_int32 dec(PN_int32 &var);
|
||||
INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
|
||||
INLINE static PN_int32 get(const PN_int32 &var);
|
||||
};
|
||||
|
||||
#include "atomicAdjustNsprImpl.I"
|
||||
|
|
|
|||
|
|
@ -59,3 +59,20 @@ set(PN_int32 &var, PN_int32 new_value) {
|
|||
pthread_mutex_unlock(&_mutex);
|
||||
return orig_value;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AtomicAdjustPosixImpl::get
|
||||
// Access: Public, Static
|
||||
// Description: Atomically retrieves the snapshot value of the
|
||||
// indicated variable. This is the only guaranteed safe
|
||||
// way to retrieve the value that other threads might be
|
||||
// asynchronously setting, incrementing, or decrementing
|
||||
// (via other AtomicAjust methods).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_int32 AtomicAdjustPosixImpl::
|
||||
get(const PN_int32 &var) {
|
||||
pthread_mutex_lock(&_mutex);
|
||||
PN_int32 orig_value = var;
|
||||
pthread_mutex_unlock(&_mutex);
|
||||
return orig_value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ public:
|
|||
INLINE static PN_int32 inc(PN_int32 &var);
|
||||
INLINE static PN_int32 dec(PN_int32 &var);
|
||||
INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
|
||||
INLINE static PN_int32 get(const PN_int32 &var);
|
||||
|
||||
private:
|
||||
static pthread_mutex_t _mutex;
|
||||
|
|
|
|||
|
|
@ -49,3 +49,17 @@ INLINE PN_int32 AtomicAdjustWin32Impl::
|
|||
set(PN_int32 &var, PN_int32 new_value) {
|
||||
return InterlockedExchange((LONG *)&var, new_value);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: AtomicAdjustWin32Impl::get
|
||||
// Access: Public, Static
|
||||
// Description: Atomically retrieves the snapshot value of the
|
||||
// indicated variable. This is the only guaranteed safe
|
||||
// way to retrieve the value that other threads might be
|
||||
// asynchronously setting, incrementing, or decrementing
|
||||
// (via other AtomicAjust methods).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_int32 AtomicAdjustWin32Impl::
|
||||
get(const PN_int32 &var) {
|
||||
return var;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ public:
|
|||
INLINE static PN_int32 inc(PN_int32 &var);
|
||||
INLINE static PN_int32 dec(PN_int32 &var);
|
||||
INLINE static PN_int32 set(PN_int32 &var, PN_int32 new_value);
|
||||
INLINE static PN_int32 get(const PN_int32 &var);
|
||||
};
|
||||
|
||||
#include "atomicAdjustWin32Impl.I"
|
||||
|
|
|
|||
|
|
@ -29,8 +29,11 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVar::
|
||||
ConditionVar(Mutex &mutex) :
|
||||
_mutex(mutex),
|
||||
_impl(mutex._impl)
|
||||
#ifdef DEBUG_THREADS
|
||||
ConditionVarDebug(mutex)
|
||||
#else
|
||||
ConditionVarDirect(mutex)
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -50,8 +53,11 @@ INLINE ConditionVar::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVar::
|
||||
ConditionVar(const ConditionVar ©) :
|
||||
_mutex(copy._mutex),
|
||||
_impl(_mutex._impl)
|
||||
#ifdef DEBUG_THREADS
|
||||
ConditionVarDebug(copy.get_mutex())
|
||||
#else
|
||||
ConditionVarDirect(copy.get_mutex())
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
nassertv(false);
|
||||
}
|
||||
|
|
@ -73,67 +79,10 @@ operator = (const ConditionVar ©) {
|
|||
// variable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Mutex &ConditionVar::
|
||||
get_mutex() {
|
||||
return _mutex;
|
||||
}
|
||||
|
||||
#ifndef CHECK_REENTRANT_MUTEX
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVar::wait
|
||||
// Access: Public
|
||||
// Description: Waits on the condition. The caller must already be
|
||||
// holding the lock associated with the condition
|
||||
// variable before calling this function.
|
||||
//
|
||||
// wait() will release the lock, then go to sleep until
|
||||
// some other thread calls signal() on this condition
|
||||
// variable. At that time at least one thread waiting
|
||||
// on the same ConditionVar will grab the lock again,
|
||||
// and then return from wait().
|
||||
//
|
||||
// It is possible that wait() will return even if no one
|
||||
// has called signal(). It is the responsibility of the
|
||||
// calling process to verify the condition on return
|
||||
// from wait, and possibly loop back to wait again if
|
||||
// necessary.
|
||||
//
|
||||
// Note the semantics of a condition variable: the mutex
|
||||
// must be held before wait() is called, and it will
|
||||
// still be held when wait() returns. However, it will
|
||||
// be temporarily released during the wait() call
|
||||
// itself.
|
||||
//
|
||||
// This is defined as an inline method only when
|
||||
// CHECK_REENTRANT_MUTEX is not defined. If
|
||||
// CHECK_REENTRANT_MUTEX is defined, it is an
|
||||
// out-of-line method, just to avoid circular
|
||||
// dependencies on #include files.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVar::
|
||||
wait() {
|
||||
nassertv(_mutex.debug_is_locked());
|
||||
_impl.wait();
|
||||
}
|
||||
#endif // CHECK_REENTRANT_MUTEX
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVar::signal
|
||||
// Access: Public
|
||||
// Description: Informs one of the other threads who are currently
|
||||
// blocked on wait() that the relevant condition has
|
||||
// changed. If multiple threads are currently waiting,
|
||||
// at least one of them will be woken up, although there
|
||||
// is no way to predict which one.
|
||||
//
|
||||
// The caller must be holding the mutex associated with
|
||||
// the condition variable before making this call, which
|
||||
// will not release the mutex.
|
||||
//
|
||||
// If no threads are waiting, this is a no-op: the
|
||||
// signal is lost.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVar::
|
||||
signal() {
|
||||
nassertv(_mutex.debug_is_locked());
|
||||
_impl.signal();
|
||||
get_mutex() const {
|
||||
#ifdef DEBUG_THREADS
|
||||
return (Mutex &)ConditionVarDebug::get_mutex();
|
||||
#else
|
||||
return (Mutex &)ConditionVarDirect::get_mutex();
|
||||
#endif // DEBUG_THREADS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,45 +17,3 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "conditionVar.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVar::wait
|
||||
// Access: Public
|
||||
// Description: Waits on the condition. The caller must already be
|
||||
// holding the lock associated with the condition
|
||||
// variable before calling this function.
|
||||
//
|
||||
// wait() will release the lock, then go to sleep until
|
||||
// some other thread calls signal() on this condition
|
||||
// variable. At that time at least one thread waiting
|
||||
// on the same ConditionVar will grab the lock again,
|
||||
// and then return from wait().
|
||||
//
|
||||
// It is possible that wait() will return even if no one
|
||||
// has called signal(). It is the responsibility of the
|
||||
// calling process to verify the condition on return
|
||||
// from wait, and possibly loop back to wait again if
|
||||
// necessary.
|
||||
//
|
||||
// Note the semantics of a condition variable: the mutex
|
||||
// must be held before wait() is called, and it will
|
||||
// still be held when wait() returns. However, it will
|
||||
// be temporarily released during the wait() call
|
||||
// itself.
|
||||
//
|
||||
// This is defined as an inline method only when
|
||||
// CHECK_REENTRANT_MUTEX is not defined. If
|
||||
// CHECK_REENTRANT_MUTEX is defined, it is an
|
||||
// out-of-line method, just to avoid circular
|
||||
// dependencies on #include files.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ConditionVar::
|
||||
wait() {
|
||||
nassertv(_mutex.debug_is_locked());
|
||||
_impl.wait();
|
||||
|
||||
_mutex._locking_thread = Thread::get_current_thread();
|
||||
}
|
||||
#endif // CHECK_REENTRANT_MUTEX
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
#define CONDITIONVAR_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pmutex.h"
|
||||
#include "conditionVarImpl.h"
|
||||
#include "notify.h"
|
||||
#include "conditionVarDebug.h"
|
||||
#include "conditionVarDirect.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ConditionVar
|
||||
|
|
@ -35,8 +34,17 @@
|
|||
// A condition variable is associated with a single
|
||||
// mutex, and several condition variables may share the
|
||||
// same mutex.
|
||||
//
|
||||
// This class inherits its implementation either from
|
||||
// ConditionVarDebug or ConditionVarDirect, depending on
|
||||
// the definition of DEBUG_THREADS.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ConditionVar {
|
||||
#ifdef DEBUG_THREADS
|
||||
class EXPCL_PANDAEXPRESS ConditionVar : public ConditionVarDebug
|
||||
#else
|
||||
class EXPCL_PANDAEXPRESS ConditionVar : public ConditionVarDirect
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
public:
|
||||
INLINE ConditionVar(Mutex &mutex);
|
||||
INLINE ~ConditionVar();
|
||||
|
|
@ -45,18 +53,7 @@ private:
|
|||
INLINE void operator = (const ConditionVar ©);
|
||||
|
||||
public:
|
||||
INLINE Mutex &get_mutex();
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
void wait();
|
||||
#else // CHECK_REENTRANT_MUTEX
|
||||
INLINE void wait();
|
||||
#endif // CHECK_REENTRANT_MUTEX
|
||||
INLINE void signal();
|
||||
|
||||
private:
|
||||
Mutex &_mutex;
|
||||
ConditionVarImpl _impl;
|
||||
INLINE Mutex &get_mutex() const;
|
||||
};
|
||||
|
||||
#include "conditionVar.I"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
// Filename: conditionVarDebug.I
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: ConditionVarDebug::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy condition variables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVarDebug::
|
||||
ConditionVarDebug(const ConditionVarDebug ©) :
|
||||
_mutex(copy._mutex),
|
||||
_impl(_mutex._global_mutex)
|
||||
{
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy condition variables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVarDebug::
|
||||
operator = (const ConditionVarDebug ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::get_mutex
|
||||
// Access: Public
|
||||
// Description: Returns the mutex associated with this condition
|
||||
// variable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDebug &ConditionVarDebug::
|
||||
get_mutex() const {
|
||||
return _mutex;
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
// Filename: conditionVarDebug.cxx
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "conditionVarDebug.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::Constructor
|
||||
// Access: Public
|
||||
// Description: You must pass in a Mutex to the condition variable
|
||||
// constructor. This mutex may be shared by other
|
||||
// condition variables, if desired. It is the caller's
|
||||
// responsibility to ensure the Mutex object does not
|
||||
// destruct during the lifetime of the condition
|
||||
// variable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ConditionVarDebug::
|
||||
ConditionVarDebug(MutexDebug &mutex) :
|
||||
_mutex(mutex),
|
||||
_impl(mutex._global_mutex)
|
||||
{
|
||||
nassertv(!_mutex._allow_recursion);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ConditionVarDebug::
|
||||
~ConditionVarDebug() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::wait
|
||||
// Access: Public
|
||||
// Description: Waits on the condition. The caller must already be
|
||||
// holding the lock associated with the condition
|
||||
// variable before calling this function.
|
||||
//
|
||||
// wait() will release the lock, then go to sleep until
|
||||
// some other thread calls signal() on this condition
|
||||
// variable. At that time at least one thread waiting
|
||||
// on the same ConditionVarDebug will grab the lock again,
|
||||
// and then return from wait().
|
||||
//
|
||||
// It is possible that wait() will return even if no one
|
||||
// has called signal(). It is the responsibility of the
|
||||
// calling process to verify the condition on return
|
||||
// from wait, and possibly loop back to wait again if
|
||||
// necessary.
|
||||
//
|
||||
// Note the semantics of a condition variable: the mutex
|
||||
// must be held before wait() is called, and it will
|
||||
// still be held when wait() returns. However, it will
|
||||
// be temporarily released during the wait() call
|
||||
// itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ConditionVarDebug::
|
||||
wait() {
|
||||
_mutex._global_mutex.lock();
|
||||
|
||||
if (!_mutex.do_debug_is_locked()) {
|
||||
ostringstream ostr;
|
||||
ostr << *Thread::get_current_thread() << " attempted to wait on "
|
||||
<< *this << " without holding " << _mutex;
|
||||
nassert_raise(ostr.str());
|
||||
_mutex._global_mutex.release();
|
||||
return;
|
||||
}
|
||||
|
||||
_mutex.do_release();
|
||||
_impl.wait();
|
||||
_mutex.do_lock();
|
||||
|
||||
_mutex._global_mutex.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::signal
|
||||
// Access: Public
|
||||
// Description: Informs one of the other threads who are currently
|
||||
// blocked on wait() that the relevant condition has
|
||||
// changed. If multiple threads are currently waiting,
|
||||
// at least one of them will be woken up, although there
|
||||
// is no way to predict which one.
|
||||
//
|
||||
// The caller must be holding the mutex associated with
|
||||
// the condition variable before making this call, which
|
||||
// will not release the mutex.
|
||||
//
|
||||
// If no threads are waiting, this is a no-op: the
|
||||
// signal is lost.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ConditionVarDebug::
|
||||
signal() {
|
||||
_mutex._global_mutex.lock();
|
||||
if (!_mutex.do_debug_is_locked()) {
|
||||
ostringstream ostr;
|
||||
ostr << *Thread::get_current_thread() << " attempted to signal "
|
||||
<< *this << " without holding " << _mutex;
|
||||
nassert_raise(ostr.str());
|
||||
_mutex._global_mutex.release();
|
||||
return;
|
||||
}
|
||||
|
||||
_impl.signal();
|
||||
_mutex._global_mutex.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDebug::output
|
||||
// Access: Public, Virtual
|
||||
// Description: This method is declared virtual in ConditionVarDebug,
|
||||
// but non-virtual in ConditionVarDirect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ConditionVarDebug::
|
||||
output(ostream &out) const {
|
||||
out << "ConditionVar " << (void *)this;
|
||||
}
|
||||
|
||||
#endif // DEBUG_THREADS
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Filename: conditionVarDebug.h
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 CONDITIONVARDEBUG_H
|
||||
#define CONDITIONVARDEBUG_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pmutex.h"
|
||||
#include "conditionVarImpl.h"
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ConditionVarDebug
|
||||
// Description : A condition variable, usually used to communicate
|
||||
// information about changing state to a thread that is
|
||||
// waiting for something to happen. A condition
|
||||
// variable can be used to "wake up" a thread when some
|
||||
// arbitrary condition has changed.
|
||||
//
|
||||
// A condition variable is associated with a single
|
||||
// mutex, and several condition variables may share the
|
||||
// same mutex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ConditionVarDebug {
|
||||
public:
|
||||
ConditionVarDebug(MutexDebug &mutex);
|
||||
virtual ~ConditionVarDebug();
|
||||
private:
|
||||
INLINE ConditionVarDebug(const ConditionVarDebug ©);
|
||||
INLINE void operator = (const ConditionVarDebug ©);
|
||||
|
||||
public:
|
||||
INLINE MutexDebug &get_mutex() const;
|
||||
|
||||
void wait();
|
||||
void signal();
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
MutexDebug &_mutex;
|
||||
ConditionVarImpl _impl;
|
||||
};
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const ConditionVarDebug &cv) {
|
||||
cv.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "conditionVarDebug.I"
|
||||
|
||||
#endif // DEBUG_THREADS
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
// Filename: conditionVarDirect.I
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: ConditionVarDirect::Constructor
|
||||
// Access: Public
|
||||
// Description: You must pass in a Mutex to the condition variable
|
||||
// constructor. This mutex may be shared by other
|
||||
// condition variables, if desired. It is the caller's
|
||||
// responsibility to ensure the Mutex object does not
|
||||
// destruct during the lifetime of the condition
|
||||
// variable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVarDirect::
|
||||
ConditionVarDirect(MutexDirect &mutex) :
|
||||
_mutex(mutex),
|
||||
_impl(mutex._impl)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVarDirect::
|
||||
~ConditionVarDirect() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy condition variables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ConditionVarDirect::
|
||||
ConditionVarDirect(const ConditionVarDirect ©) :
|
||||
_mutex(copy._mutex),
|
||||
_impl(_mutex._impl)
|
||||
{
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy condition variables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVarDirect::
|
||||
operator = (const ConditionVarDirect ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::get_mutex
|
||||
// Access: Public
|
||||
// Description: Returns the mutex associated with this condition
|
||||
// variable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDirect &ConditionVarDirect::
|
||||
get_mutex() const {
|
||||
return _mutex;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::wait
|
||||
// Access: Public
|
||||
// Description: Waits on the condition. The caller must already be
|
||||
// holding the lock associated with the condition
|
||||
// variable before calling this function.
|
||||
//
|
||||
// wait() will release the lock, then go to sleep until
|
||||
// some other thread calls signal() on this condition
|
||||
// variable. At that time at least one thread waiting
|
||||
// on the same ConditionVarDirect will grab the lock again,
|
||||
// and then return from wait().
|
||||
//
|
||||
// It is possible that wait() will return even if no one
|
||||
// has called signal(). It is the responsibility of the
|
||||
// calling process to verify the condition on return
|
||||
// from wait, and possibly loop back to wait again if
|
||||
// necessary.
|
||||
//
|
||||
// Note the semantics of a condition variable: the mutex
|
||||
// must be held before wait() is called, and it will
|
||||
// still be held when wait() returns. However, it will
|
||||
// be temporarily released during the wait() call
|
||||
// itself.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVarDirect::
|
||||
wait() {
|
||||
_impl.wait();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::signal
|
||||
// Access: Public
|
||||
// Description: Informs one of the other threads who are currently
|
||||
// blocked on wait() that the relevant condition has
|
||||
// changed. If multiple threads are currently waiting,
|
||||
// at least one of them will be woken up, although there
|
||||
// is no way to predict which one.
|
||||
//
|
||||
// The caller must be holding the mutex associated with
|
||||
// the condition variable before making this call, which
|
||||
// will not release the mutex.
|
||||
//
|
||||
// If no threads are waiting, this is a no-op: the
|
||||
// signal is lost.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ConditionVarDirect::
|
||||
signal() {
|
||||
_impl.signal();
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Filename: conditionVarDirect.cxx
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "conditionVarDirect.h"
|
||||
|
||||
#ifndef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ConditionVarDirect::output
|
||||
// Access: Public
|
||||
// Description: This method is declared virtual in ConditionVarDebug,
|
||||
// but non-virtual in ConditionVarDirect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ConditionVarDirect::
|
||||
output(ostream &out) const {
|
||||
out << "ConditionVar " << (void *)this;
|
||||
}
|
||||
|
||||
#endif // !DEBUG_THREADS
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Filename: conditionVarDirect.h
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 CONDITIONVARDIRECT_H
|
||||
#define CONDITIONVARDIRECT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "mutexDirect.h"
|
||||
#include "conditionVarImpl.h"
|
||||
|
||||
#ifndef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ConditionVarDirect
|
||||
// Description : A condition variable, usually used to communicate
|
||||
// information about changing state to a thread that is
|
||||
// waiting for something to happen. A condition
|
||||
// variable can be used to "wake up" a thread when some
|
||||
// arbitrary condition has changed.
|
||||
//
|
||||
// A condition variable is associated with a single
|
||||
// mutex, and several condition variables may share the
|
||||
// same mutex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ConditionVarDirect {
|
||||
public:
|
||||
INLINE ConditionVarDirect(MutexDirect &mutex);
|
||||
INLINE ~ConditionVarDirect();
|
||||
private:
|
||||
INLINE ConditionVarDirect(const ConditionVarDirect ©);
|
||||
INLINE void operator = (const ConditionVarDirect ©);
|
||||
|
||||
public:
|
||||
INLINE MutexDirect &get_mutex() const;
|
||||
|
||||
INLINE void wait();
|
||||
INLINE void signal();
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
MutexDirect &_mutex;
|
||||
ConditionVarImpl _impl;
|
||||
};
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const ConditionVarDirect &cv) {
|
||||
cv.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "conditionVarDirect.I"
|
||||
|
||||
#endif // !DEBUG_THREADS
|
||||
|
||||
#endif
|
||||
|
|
@ -185,10 +185,15 @@ init_libexpress() {
|
|||
|
||||
init_system_type_handles();
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
PandaSystem *ps = PandaSystem::get_global_ptr();
|
||||
|
||||
#ifdef HAVE_ZLIB
|
||||
ps->add_system("zlib");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_THREADS
|
||||
ps->add_system("threads");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
#include "checksumHashGenerator.cxx"
|
||||
#include "clockObject.cxx"
|
||||
#include "conditionVar.cxx"
|
||||
#include "conditionVarDebug.cxx"
|
||||
#include "conditionVarDirect.cxx"
|
||||
#include "conditionVarDummyImpl.cxx"
|
||||
#include "conditionVarNsprImpl.cxx"
|
||||
#include "conditionVarPosixImpl.cxx"
|
||||
|
|
@ -29,6 +31,8 @@
|
|||
#include "memoryUsagePointerCounts.cxx"
|
||||
#include "memoryUsagePointers.cxx"
|
||||
#include "multifile.cxx"
|
||||
#include "mutexDebug.cxx"
|
||||
#include "mutexDirect.cxx"
|
||||
#include "mutexHolder.cxx"
|
||||
#include "mutexDummyImpl.cxx"
|
||||
#include "mutexNsprImpl.cxx"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
// Filename: mutexDebug.I
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: MutexDebug::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDebug::
|
||||
MutexDebug(bool allow_recursion) :
|
||||
_allow_recursion(allow_recursion),
|
||||
_locking_thread(NULL),
|
||||
_lock_count(0),
|
||||
_cvar(_global_mutex)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDebug::
|
||||
MutexDebug(const MutexDebug ©) : _cvar(_global_mutex) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDebug::
|
||||
operator = (const MutexDebug ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see MutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDebug::
|
||||
lock() const {
|
||||
_global_mutex.lock();
|
||||
((MutexDebug *)this)->do_lock();
|
||||
_global_mutex.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDebug::
|
||||
release() const {
|
||||
_global_mutex.lock();
|
||||
((MutexDebug *)this)->do_release();
|
||||
_global_mutex.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only intended
|
||||
// for use in debugging, hence the method name; in the
|
||||
// MutexDebug case, it always returns true, since
|
||||
// there's not a reliable way to determine this
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexDebug::
|
||||
debug_is_locked() const {
|
||||
_global_mutex.lock();
|
||||
bool is_locked = do_debug_is_locked();
|
||||
_global_mutex.release();
|
||||
return is_locked;
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
// Filename: mutexDebug.cxx
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "mutexDebug.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
MutexImpl MutexDebug::_global_mutex;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::Destructor
|
||||
// Access: Protected, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
MutexDebug::
|
||||
~MutexDebug() {
|
||||
nassertv(_locking_thread == NULL && _lock_count == 0);
|
||||
|
||||
// Put a distinctive, bogus lock count in upon destruction, so we'll
|
||||
// be more likely to notice a floating pointer.
|
||||
_lock_count = -100;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::output
|
||||
// Access: Public, Virtual
|
||||
// Description: This method is declared virtual in MutexDebug, but
|
||||
// non-virtual in MutexDirect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MutexDebug::
|
||||
output(ostream &out) const {
|
||||
if (_allow_recursion) {
|
||||
out << "ReMutex " << (void *)this;
|
||||
} else {
|
||||
out << "Mutex " << (void *)this;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::do_lock
|
||||
// Access: Private
|
||||
// Description: The private implementation of lock() assumes that
|
||||
// _global_mutex is held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MutexDebug::
|
||||
do_lock() {
|
||||
// If this assertion is triggered, you tried to lock a
|
||||
// recently-destructed mutex.
|
||||
nassertv(_lock_count != -100);
|
||||
|
||||
Thread *this_thread = Thread::get_current_thread();
|
||||
|
||||
if (_locking_thread == (Thread *)NULL) {
|
||||
// The mutex is not already locked by anyone. Lock it.
|
||||
_locking_thread = this_thread;
|
||||
++_lock_count;
|
||||
nassertv(_lock_count == 1);
|
||||
|
||||
} else if (_locking_thread == this_thread) {
|
||||
// The mutex is already locked by this thread. Increment the lock
|
||||
// count.
|
||||
nassertv(_lock_count >= 0);
|
||||
if (!_allow_recursion && _lock_count == 0) {
|
||||
ostringstream ostr;
|
||||
ostr << *_locking_thread << " attempted to re-lock non-reentrant "
|
||||
<< *this;
|
||||
nassert_raise(ostr.str());
|
||||
return;
|
||||
}
|
||||
++_lock_count;
|
||||
|
||||
} else {
|
||||
// The mutex is locked by some other thread. Check for deadlock?
|
||||
MutexDebug *next_mutex = this;
|
||||
|
||||
while (next_mutex != NULL) {
|
||||
if (next_mutex->_locking_thread == this_thread) {
|
||||
// Whoops, the thread is blocked on me! Deadlock!
|
||||
report_deadlock(this_thread);
|
||||
nassert_raise("Deadlock");
|
||||
_global_mutex.release();
|
||||
return;
|
||||
}
|
||||
Thread *next_thread = next_mutex->_locking_thread;
|
||||
if (next_thread == NULL) {
|
||||
// Looks like this mutex isn't actually locked, which means
|
||||
// the last thread isn't really blocked--it just hasn't woken
|
||||
// up yet to discover that. In any case, no deadlock.
|
||||
break;
|
||||
}
|
||||
|
||||
// The last thread is blocked on this "next thread"'s mutex, but
|
||||
// what mutex is the next thread blocked on?
|
||||
next_mutex = next_thread->_blocked_on_mutex;
|
||||
}
|
||||
|
||||
// OK, no deadlock detected. Carry on.
|
||||
this_thread->_blocked_on_mutex = this;
|
||||
|
||||
// Go to sleep on the condition variable until it's unlocked.
|
||||
|
||||
if (thread_cat.is_spam()) {
|
||||
thread_cat.spam()
|
||||
<< *this_thread << " blocking on " << *this << "\n";
|
||||
}
|
||||
while (_locking_thread != (Thread *)NULL) {
|
||||
_cvar.wait();
|
||||
}
|
||||
if (thread_cat.is_spam()) {
|
||||
thread_cat.spam()
|
||||
<< *this_thread << " awake\n";
|
||||
}
|
||||
|
||||
this_thread->_blocked_on_mutex = NULL;
|
||||
|
||||
_locking_thread = this_thread;
|
||||
++_lock_count;
|
||||
nassertv(_lock_count == 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::do_release
|
||||
// Access: Private
|
||||
// Description: The private implementation of lock() assumes that
|
||||
// _global_mutex is held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MutexDebug::
|
||||
do_release() {
|
||||
// If this assertion is triggered, you tried to release a
|
||||
// recently-destructed mutex.
|
||||
nassertv(_lock_count != -100);
|
||||
|
||||
Thread *this_thread = Thread::get_current_thread();
|
||||
|
||||
if (_locking_thread != this_thread) {
|
||||
ostringstream ostr;
|
||||
ostr << *this_thread << " attempted to release "
|
||||
<< *this << " which it does not own";
|
||||
nassert_raise(ostr.str());
|
||||
_global_mutex.release();
|
||||
return;
|
||||
}
|
||||
|
||||
nassertv(_lock_count > 0);
|
||||
|
||||
--_lock_count;
|
||||
if (_lock_count == 0) {
|
||||
// That was the last lock held by this thread. Release the lock.
|
||||
_locking_thread = (Thread *)NULL;
|
||||
_cvar.signal();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::do_debug_is_locked
|
||||
// Access: Private
|
||||
// Description: The private implementation of debug_is_locked()
|
||||
// assumes that _global_mutex is held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool MutexDebug::
|
||||
do_debug_is_locked() const {
|
||||
return (_locking_thread == Thread::get_current_thread());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDebug::report_deadlock
|
||||
// Access: Private
|
||||
// Description: Reports a detected deadlock situation. _global_mutex
|
||||
// should be already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MutexDebug::
|
||||
report_deadlock(Thread *this_thread) {
|
||||
thread_cat.error()
|
||||
<< "\n\n"
|
||||
<< "****************************************************************\n"
|
||||
<< "***** Deadlock detected! *****\n"
|
||||
<< "****************************************************************\n"
|
||||
<< "\n";
|
||||
|
||||
thread_cat.error()
|
||||
<< *this_thread << " attempted to lock " << *this
|
||||
<< " which is held by " << *_locking_thread << "\n";
|
||||
|
||||
MutexDebug *next_mutex = this;
|
||||
Thread *next_thread = next_mutex->_locking_thread;
|
||||
next_mutex = next_thread->_blocked_on_mutex;
|
||||
while (next_mutex != NULL) {
|
||||
thread_cat.error()
|
||||
<< *next_thread << " is blocked waiting on "
|
||||
<< *next_mutex << " which is held by "
|
||||
<< *next_mutex->_locking_thread << "\n";
|
||||
next_thread = next_mutex->_locking_thread;
|
||||
next_mutex = next_thread->_blocked_on_mutex;
|
||||
}
|
||||
|
||||
thread_cat.error()
|
||||
<< "Deadlock!\n";
|
||||
}
|
||||
|
||||
#endif // DEBUG_THREADS
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// Filename: mutexDebug.h
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 MUTEXDEBUG_H
|
||||
#define MUTEXDEBUG_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "mutexImpl.h"
|
||||
#include "conditionVarImpl.h"
|
||||
|
||||
class Thread;
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexDebug
|
||||
// Description : This class implements a standard mutex the hard way,
|
||||
// by doing everything by hand. This does allow fancy
|
||||
// things like deadlock detection, however.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS MutexDebug {
|
||||
protected:
|
||||
INLINE MutexDebug(bool allow_recursion);
|
||||
virtual ~MutexDebug();
|
||||
private:
|
||||
INLINE MutexDebug(const MutexDebug ©);
|
||||
INLINE void operator = (const MutexDebug ©);
|
||||
|
||||
public:
|
||||
INLINE void lock() const;
|
||||
INLINE void release() const;
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
void do_lock();
|
||||
void do_release();
|
||||
bool do_debug_is_locked() const;
|
||||
|
||||
void report_deadlock(Thread *this_thread);
|
||||
|
||||
private:
|
||||
bool _allow_recursion;
|
||||
Thread *_locking_thread;
|
||||
int _lock_count;
|
||||
ConditionVarImpl _cvar;
|
||||
|
||||
static MutexImpl _global_mutex;
|
||||
|
||||
friend class ConditionVarDebug;
|
||||
};
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const MutexDebug &m) {
|
||||
m.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "mutexDebug.I"
|
||||
|
||||
#endif // DEBUG_THREADS
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
// Filename: mutexDirect.I
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: MutexDirect::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDirect::
|
||||
MutexDirect() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDirect::
|
||||
~MutexDirect() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDirect::
|
||||
MutexDirect(const MutexDirect ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDirect::
|
||||
operator = (const MutexDirect ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see MutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDirect::
|
||||
lock() const {
|
||||
((MutexDirect *)this)->_impl.lock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDirect::
|
||||
release() const {
|
||||
((MutexDirect *)this)->_impl.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only intended
|
||||
// for use in debugging, hence the method name; in the
|
||||
// MutexDirect case, it always returns true, since
|
||||
// there's not a reliable way to determine this
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexDirect::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// Filename: mutexDirect.cxx
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "mutexDirect.h"
|
||||
|
||||
#ifndef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexDirect::output
|
||||
// Access: Public
|
||||
// Description: This method is declared virtual in MutexDebug, but
|
||||
// non-virtual in MutexDirect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void MutexDirect::
|
||||
output(ostream &out) const {
|
||||
out << "Mutex " << (void *)this;
|
||||
}
|
||||
|
||||
#endif // !DEBUG_THREADS
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// Filename: mutexDirect.h
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 MUTEXDIRECT_H
|
||||
#define MUTEXDIRECT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "mutexImpl.h"
|
||||
|
||||
class Thread;
|
||||
|
||||
#ifndef DEBUG_THREADS
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexDirect
|
||||
// Description : This class implements a standard mutex by making
|
||||
// direct calls to the underlying implementation layer.
|
||||
// It doesn't perform any debugging operations.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS MutexDirect {
|
||||
protected:
|
||||
INLINE MutexDirect();
|
||||
INLINE ~MutexDirect();
|
||||
private:
|
||||
INLINE MutexDirect(const MutexDirect ©);
|
||||
INLINE void operator = (const MutexDirect ©);
|
||||
|
||||
public:
|
||||
INLINE void lock() const;
|
||||
INLINE void release() const;
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
MutexImpl _impl;
|
||||
|
||||
friend class ConditionVarDirect;
|
||||
};
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const MutexDirect &m) {
|
||||
m.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "mutexDirect.I"
|
||||
|
||||
#endif // !DEBUG_THREADS
|
||||
|
||||
#endif
|
||||
|
|
@ -24,9 +24,6 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDummyImpl::
|
||||
MutexDummyImpl() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
_lock_count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -36,9 +33,6 @@ MutexDummyImpl() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE MutexDummyImpl::
|
||||
~MutexDummyImpl() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
nassertv(_lock_count == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -48,10 +42,6 @@ INLINE MutexDummyImpl::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDummyImpl::
|
||||
lock() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
_lock_count++;
|
||||
nassertv(_lock_count == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -61,8 +51,4 @@ lock() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void MutexDummyImpl::
|
||||
release() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
_lock_count--;
|
||||
nassertv(_lock_count == 0);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@
|
|||
// Class : MutexDummyImpl
|
||||
// Description : A fake mutex implementation for single-threaded
|
||||
// applications that don't need any synchronization
|
||||
// control. This does nothing but assert that the same
|
||||
// process does not try to grab the mutex twice.
|
||||
// control. This does nothing at all.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS MutexDummyImpl {
|
||||
public:
|
||||
|
|
@ -40,11 +39,6 @@ public:
|
|||
|
||||
INLINE void lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
int _lock_count;
|
||||
#endif
|
||||
};
|
||||
|
||||
#include "mutexDummyImpl.I"
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
|
||||
#include "mutexDummyImpl.h"
|
||||
typedef MutexDummyImpl MutexImpl;
|
||||
#undef HAVE_REMUTEXIMPL
|
||||
typedef MutexDummyImpl ReMutexImpl;
|
||||
#define HAVE_REMUTEXIMPL 1
|
||||
|
||||
#elif defined(THREAD_WIN32_IMPL)
|
||||
|
||||
|
|
@ -46,7 +47,7 @@ typedef ReMutexPosixImpl ReMutexImpl;
|
|||
|
||||
#include "mutexNsprImpl.h"
|
||||
typedef MutexNsprImpl MutexImpl;
|
||||
#undef HAVE_REMUTEXIMPL
|
||||
#undef HAVE_REMUTEXIMPL // NSPR doesn't provide a reentrant mutex.
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,18 @@ lock() {
|
|||
PR_Lock(_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexNsprImpl::try_lock
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexNsprImpl::
|
||||
try_lock() {
|
||||
// NSPR doesn't define a try_lock function. Too bad. We just
|
||||
// report that it would always block (since we don't know).
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexNsprImpl::release
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include <prlock.h>
|
||||
|
||||
#undef MUTEX_DEFINES_TRYLOCK
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexNsprImpl
|
||||
// Description : Uses NSPR to implement a mutex.
|
||||
|
|
@ -38,6 +40,7 @@ public:
|
|||
INLINE ~MutexNsprImpl();
|
||||
|
||||
INLINE void lock();
|
||||
INLINE bool try_lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -54,6 +54,18 @@ lock() {
|
|||
nassertv(result == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexPosixImpl::try_lock
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexPosixImpl::
|
||||
try_lock() {
|
||||
int result = pthread_mutex_trylock(&_lock);
|
||||
nassertr(result == 0 || result == EBUSY, false);
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexPosixImpl::release
|
||||
// Access: Public
|
||||
|
|
@ -102,6 +114,18 @@ lock() {
|
|||
nassertv(result == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexPosixImpl::try_lock
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutexPosixImpl::
|
||||
try_lock() {
|
||||
int result = pthread_mutex_trylock(&_lock);
|
||||
nassertr(result == 0 || result == EBUSY, false);
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexPosixImpl::release
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -27,6 +27,9 @@
|
|||
#include "notify.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define MUTEX_DEFINES_TRYLOCK 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexPosixImpl
|
||||
|
|
@ -38,6 +41,7 @@ public:
|
|||
INLINE ~MutexPosixImpl();
|
||||
|
||||
INLINE void lock();
|
||||
INLINE bool try_lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
|
|
@ -55,6 +59,7 @@ public:
|
|||
INLINE ~ReMutexPosixImpl();
|
||||
|
||||
INLINE void lock();
|
||||
INLINE bool try_lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -47,6 +47,16 @@ lock() {
|
|||
EnterCriticalSection(&_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexWin32Impl::try_lock
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool MutexWin32Impl::
|
||||
try_lock() {
|
||||
return TryEnterCriticalSection(&_lock);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: MutexWin32Impl::release
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
|
||||
#include <windows.h>
|
||||
|
||||
#define MUTEX_DEFINES_TRYLOCK 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : MutexWin32Impl
|
||||
// Description : Uses Windows native calls to implement a mutex.
|
||||
|
|
@ -38,6 +40,7 @@ public:
|
|||
INLINE ~MutexWin32Impl();
|
||||
|
||||
INLINE void lock();
|
||||
INLINE bool try_lock();
|
||||
INLINE void release();
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@
|
|||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Mutex::
|
||||
Mutex() {
|
||||
#ifdef DEBUG_THREADS
|
||||
Mutex() : MutexDebug(false)
|
||||
#else
|
||||
Mutex()
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -41,7 +46,12 @@ INLINE Mutex::
|
|||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE Mutex::
|
||||
Mutex(const Mutex ©) {
|
||||
#ifdef DEBUG_THREADS
|
||||
Mutex(const Mutex ©) : MutexDebug(false)
|
||||
#else
|
||||
Mutex(const Mutex ©)
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
|
|
@ -54,73 +64,3 @@ INLINE void Mutex::
|
|||
operator = (const Mutex ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see MutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Mutex::
|
||||
lock() const {
|
||||
#ifndef CHECK_REENTRANT_MUTEX
|
||||
// In the production case, just lock the thing immediately. Don't
|
||||
// bother with the out-of-line do_lock() method, since we won't be
|
||||
// performing any checks anyway.
|
||||
((MutexImpl &)_impl).lock();
|
||||
|
||||
#else
|
||||
// In development mode, call the out-of-line do_lock() method, which
|
||||
// might perform an additional check or two.
|
||||
((Mutex *)this)->do_lock();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void Mutex::
|
||||
release() const {
|
||||
#ifndef CHECK_REENTRANT_MUTEX
|
||||
// In the production case, just release the thing immediately.
|
||||
// Don't bother with the out-of-line do_release() method, since we
|
||||
// won't be performing any checks anyway.
|
||||
((MutexImpl &)_impl).release();
|
||||
|
||||
#else
|
||||
// In development mode, call the out-of-line do_release() method,
|
||||
// which might perform an additional check or two.
|
||||
((Mutex *)this)->do_release();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef CHECK_REENTRANT_MUTEX
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only
|
||||
// meaningful if CHECK_REENTRANT_MUTEX is defined;
|
||||
// otherwise, it always returns true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Mutex::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
#endif // CHECK_REENTRANT_MUTEX
|
||||
|
|
|
|||
|
|
@ -19,49 +19,4 @@
|
|||
#include "pmutex.h"
|
||||
#include "thread.h"
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only
|
||||
// meaningful if CHECK_REENTRANT_MUTEX is defined;
|
||||
// otherwise, it always returns true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Mutex::
|
||||
debug_is_locked() const {
|
||||
return (_locking_thread == Thread::get_current_thread());
|
||||
}
|
||||
#endif // CHECK_REENTRANT_MUTEX
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::do_lock
|
||||
// Access: Private
|
||||
// Description: The private implementation of lock().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Mutex::
|
||||
do_lock() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
nassertv(_locking_thread != Thread::get_current_thread());
|
||||
#endif
|
||||
_impl.lock();
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
_locking_thread = Thread::get_current_thread();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Mutex::do_release
|
||||
// Access: Private
|
||||
// Description: The private implementation of release().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Mutex::
|
||||
do_release() {
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
nassertv(_locking_thread == Thread::get_current_thread());
|
||||
_locking_thread = (Thread *)NULL;
|
||||
#endif
|
||||
|
||||
_impl.release();
|
||||
}
|
||||
Mutex Mutex::_notify_mutex;
|
||||
|
|
|
|||
|
|
@ -20,9 +20,8 @@
|
|||
#define PMUTEX_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "mutexImpl.h"
|
||||
|
||||
class Thread;
|
||||
#include "mutexDebug.h"
|
||||
#include "mutexDirect.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Mutex
|
||||
|
|
@ -37,13 +36,18 @@ class Thread;
|
|||
// work on all platforms; on some platforms, a thread
|
||||
// can deadlock itself by attempting to lock the same
|
||||
// mutex twice. If your code requires a reentrant
|
||||
// mutex, use the ReMutex class instead. When this code
|
||||
// is compiled with CHECK_REENTRANT_MUTEX true, then it
|
||||
// will enable assertion checks to ensure that a
|
||||
// particular thread doesn't try to lock the same mutex
|
||||
// twice.
|
||||
// mutex, use the ReMutex class instead.
|
||||
//
|
||||
// This class inherits its implementation either from
|
||||
// MutexDebug or MutexDirect, depending on the
|
||||
// definition of DEBUG_THREADS.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS Mutex {
|
||||
#ifdef DEBUG_THREADS
|
||||
class EXPCL_PANDAEXPRESS Mutex : public MutexDebug
|
||||
#else
|
||||
class EXPCL_PANDAEXPRESS Mutex : public MutexDirect
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
public:
|
||||
INLINE Mutex();
|
||||
INLINE ~Mutex();
|
||||
|
|
@ -52,29 +56,9 @@ private:
|
|||
INLINE void operator = (const Mutex ©);
|
||||
|
||||
public:
|
||||
INLINE void lock() const;
|
||||
INLINE void release() const;
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
bool debug_is_locked() const;
|
||||
#else
|
||||
INLINE bool debug_is_locked() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void do_lock();
|
||||
void do_release();
|
||||
|
||||
private:
|
||||
MutexImpl _impl;
|
||||
|
||||
#ifdef CHECK_REENTRANT_MUTEX
|
||||
// Make sure that ordinary mutexes are not locked reentrantly
|
||||
// (that's what a ReMutex is for).
|
||||
Thread *_locking_thread;
|
||||
#endif
|
||||
|
||||
friend class ConditionVar;
|
||||
// This is a global mutex set aside for the purpose of protecting
|
||||
// Notify messages from being interleaved between threads.
|
||||
static Mutex _notify_mutex;
|
||||
};
|
||||
|
||||
#include "pmutex.I"
|
||||
|
|
|
|||
|
|
@ -17,17 +17,18 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
// In this branch, the ReMutex class is implemented as a thin wrapper
|
||||
// around the native ReMutexImpl class.
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex() {
|
||||
#ifdef DEBUG_THREADS
|
||||
ReMutex() : MutexDebug(true)
|
||||
#else
|
||||
ReMutex()
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -45,7 +46,12 @@ INLINE ReMutex::
|
|||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex(const ReMutex ©) {
|
||||
#ifdef DEBUG_THREADS
|
||||
ReMutex(const ReMutex ©) : MutexDebug(true)
|
||||
#else
|
||||
ReMutex(const ReMutex ©)
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
|
|
@ -58,239 +64,3 @@ INLINE void ReMutex::
|
|||
operator = (const ReMutex ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see MutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
lock() const {
|
||||
((MutexImpl &)_impl).lock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
release() const {
|
||||
((MutexImpl &)_impl).release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only
|
||||
// meaningful if CHECK_REENTRANT_MUTEX is defined;
|
||||
// otherwise, it always returns true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutex::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#elif !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
|
||||
|
||||
// In this branch, the ReMutex object is implemented as a heavy
|
||||
// wrapper around the Mutex and ConditionVar classes, to impose
|
||||
// reentrant semantics where the underlying MutexImpl doesn't provide
|
||||
// them.
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex() : _cvar(_mutex) {
|
||||
_locking_thread = NULL;
|
||||
_lock_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
~ReMutex() {
|
||||
nassertv(_locking_thread == NULL && _lock_count == 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex(const ReMutex ©) : _cvar(_mutex) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
operator = (const ReMutex ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see ReMutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
lock() const {
|
||||
((ReMutex *)this)->do_lock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
release() const {
|
||||
((ReMutex *)this)->do_release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if *this thread* already holds the lock,
|
||||
// false if no one holds the lock or the lock is held by
|
||||
// some other thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutex::
|
||||
debug_is_locked() const {
|
||||
MutexHolder holder(_mutex);
|
||||
return (_locking_thread == Thread::get_current_thread());
|
||||
}
|
||||
|
||||
#else // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
|
||||
|
||||
// In this branch, the mutex is stubbed out to do nothing.
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
~ReMutex() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutex::
|
||||
ReMutex(const ReMutex ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy mutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
operator = (const ReMutex ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the mutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the mutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see ReMutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
lock() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::release
|
||||
// Access: Public
|
||||
// Description: Releases the mutex. It is an error to call this if
|
||||
// the mutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const mutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutex::
|
||||
release() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// Mutex, false otherwise. This method is only
|
||||
// meaningful if CHECK_REENTRANT_MUTEX is defined;
|
||||
// otherwise, it always returns true.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutex::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
|
||||
|
||||
|
|
|
|||
|
|
@ -17,69 +17,3 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "reMutex.h"
|
||||
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
|
||||
// Most of the methods in this class are stubbed out in the
|
||||
// THREAD_DUMMY_IMPL case, especially when CHECK_REENTRANT_MUTEX is
|
||||
// not defined. In this case, we're not performing any actual locking
|
||||
// or verification, so there's no need to do anything at all here.
|
||||
|
||||
#if !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::do_lock
|
||||
// Access: Private
|
||||
// Description: The private implementation of lock().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ReMutex::
|
||||
do_lock() {
|
||||
MutexHolder holder(_mutex);
|
||||
|
||||
if (_locking_thread == (Thread *)NULL) {
|
||||
// The mutex is not already locked by anyone. Lock it.
|
||||
_locking_thread = Thread::get_current_thread();
|
||||
++_lock_count;
|
||||
nassertv(_lock_count == 1);
|
||||
|
||||
} else if (_locking_thread == Thread::get_current_thread()) {
|
||||
// The mutex is already locked by this thread. Increment the lock
|
||||
// count.
|
||||
++_lock_count;
|
||||
|
||||
} else {
|
||||
// The mutex is locked by some other thread. Go to sleep on the
|
||||
// condition variable until it's unlocked.
|
||||
while (_locking_thread != (Thread *)NULL) {
|
||||
_cvar.wait();
|
||||
}
|
||||
_locking_thread = Thread::get_current_thread();
|
||||
++_lock_count;
|
||||
nassertv(_lock_count == 1);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutex::do_release
|
||||
// Access: Private
|
||||
// Description: The private implementation of release().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ReMutex::
|
||||
do_release() {
|
||||
MutexHolder holder(_mutex);
|
||||
|
||||
nassertv(_locking_thread == Thread::get_current_thread());
|
||||
nassertv(_lock_count > 0);
|
||||
|
||||
--_lock_count;
|
||||
if (_lock_count == 0) {
|
||||
// That was the last lock held by this thread. Release the lock.
|
||||
_locking_thread = (Thread *)NULL;
|
||||
_cvar.signal();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
|
||||
|
||||
#endif // !HAVE_REMUTEXIMPL
|
||||
|
||||
|
|
|
|||
|
|
@ -20,10 +20,8 @@
|
|||
#define REMUTEX_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "pmutex.h"
|
||||
#include "conditionVar.h"
|
||||
#include "mutexHolder.h"
|
||||
#include "thread.h"
|
||||
#include "mutexDebug.h"
|
||||
#include "reMutexDirect.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ReMutex
|
||||
|
|
@ -31,36 +29,23 @@
|
|||
// more than once by the thread that already holds it,
|
||||
// without deadlock. The thread must eventually release
|
||||
// the mutex the same number of times it locked it.
|
||||
//
|
||||
// This class inherits its implementation either from
|
||||
// MutexDebug or ReMutexDirect, depending on the
|
||||
// definition of DEBUG_THREADS.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ReMutex {
|
||||
#ifdef DEBUG_THREADS
|
||||
class EXPCL_PANDAEXPRESS ReMutex : public MutexDebug
|
||||
#else
|
||||
class EXPCL_PANDAEXPRESS ReMutex : public ReMutexDirect
|
||||
#endif // DEBUG_THREADS
|
||||
{
|
||||
public:
|
||||
INLINE ReMutex();
|
||||
INLINE ~ReMutex();
|
||||
private:
|
||||
INLINE ReMutex(const ReMutex ©);
|
||||
INLINE void operator = (const ReMutex ©);
|
||||
|
||||
public:
|
||||
INLINE void lock() const;
|
||||
INLINE void release() const;
|
||||
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
private:
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
// If the native Mutex implementation provides a reentrant flavor,
|
||||
// just use that.
|
||||
ReMutexImpl _impl;
|
||||
|
||||
#elif !defined(THREAD_DUMMY_IMPL) || defined(CHECK_REENTRANT_MUTEX)
|
||||
void do_lock();
|
||||
void do_release();
|
||||
|
||||
Mutex _mutex;
|
||||
ConditionVar _cvar;
|
||||
Thread *_locking_thread;
|
||||
int _lock_count;
|
||||
#endif // !THREAD_DUMMY_IMPL || CHECK_REENTRANT_MUTEX
|
||||
};
|
||||
|
||||
#include "reMutex.I"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
// Filename: reMutexDirect.I
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: ReMutexDirect::Constructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutexDirect::
|
||||
ReMutexDirect() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::Destructor
|
||||
// Access: Protected
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutexDirect::
|
||||
~ReMutexDirect() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::Copy Constructor
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy reMutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ReMutexDirect::
|
||||
ReMutexDirect(const ReMutexDirect ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::Copy Assignment Operator
|
||||
// Access: Private
|
||||
// Description: Do not attempt to copy reMutexes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutexDirect::
|
||||
operator = (const ReMutexDirect ©) {
|
||||
nassertv(false);
|
||||
}
|
||||
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the reMutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the reMutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const reMutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see ReMutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutexDirect::
|
||||
lock() const {
|
||||
((ReMutexDirect *)this)->_impl.lock();
|
||||
}
|
||||
#endif // HAVE_REMUTEXIMPL
|
||||
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::release
|
||||
// Access: Public
|
||||
// Description: Releases the reMutex. It is an error to call this if
|
||||
// the reMutex was not already locked.
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const reMutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void ReMutexDirect::
|
||||
release() const {
|
||||
((ReMutexDirect *)this)->_impl.release();
|
||||
}
|
||||
#endif // HAVE_REMUTEXIMPL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::debug_is_locked
|
||||
// Access: Public
|
||||
// Description: Returns true if the current thread has locked the
|
||||
// ReMutex, false otherwise. This method is only intended
|
||||
// for use in debugging, hence the method name; in the
|
||||
// ReMutexDirect case, it always returns true, since
|
||||
// there's not a reliable way to determine this
|
||||
// otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool ReMutexDirect::
|
||||
debug_is_locked() const {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
// Filename: reMutexDirect.cxx
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "reMutexDirect.h"
|
||||
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
MutexImpl ReMutexDirect::_global_lock;
|
||||
#endif // !HAVE_REMUTEXIMPL
|
||||
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::lock
|
||||
// Access: Public
|
||||
// Description: Grabs the reMutex if it is available. If it is not
|
||||
// available, blocks until it becomes available, then
|
||||
// grabs it. In either case, the function does not
|
||||
// return until the reMutex is held; you should then call
|
||||
// unlock().
|
||||
//
|
||||
// This method is considered const so that you can lock
|
||||
// and unlock const reMutexes, mainly to allow thread-safe
|
||||
// access to otherwise const data.
|
||||
//
|
||||
// Also see ReMutexHolder.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ReMutexDirect::
|
||||
lock() const {
|
||||
_global_mutex.lock();
|
||||
|
||||
if (_locking_thread == (Thread *)NULL) {
|
||||
// The mutex is not already locked by anyone. Lock it.
|
||||
_locking_thread = Thread::get_current_thread();
|
||||
++_lock_count;
|
||||
nassertd(_lock_count == 1) {
|
||||
}
|
||||
|
||||
} else if (_locking_thread == Thread::get_current_thread()) {
|
||||
// The mutex is already locked by this thread. Increment the lock
|
||||
// count.
|
||||
++_lock_count;
|
||||
nassertd(_lock_count > 0) {
|
||||
}
|
||||
|
||||
} else {
|
||||
// The mutex is locked by some other thread. Go to sleep on the
|
||||
// condition variable until it's unlocked.
|
||||
while (_locking_thread != (Thread *)NULL) {
|
||||
_cvar.wait();
|
||||
}
|
||||
|
||||
_locking_thread = Thread::get_current_thread();
|
||||
++_lock_count;
|
||||
nassertd(_lock_count == 1) {
|
||||
}
|
||||
}
|
||||
_global_mutex.release();
|
||||
}
|
||||
#endif // !HAVE_REMUTEXIMPL
|
||||
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::release
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ReMutexDirect::
|
||||
release() {
|
||||
_global_mutex.lock();
|
||||
|
||||
if (_locking_thread != Thread::get_current_thread()) {
|
||||
ostringstream ostr;
|
||||
ostr << *_locking_thread << " attempted to release "
|
||||
<< *this << " which it does not own";
|
||||
nassert_raise(ostr.str());
|
||||
_global_mutex.release();
|
||||
return;
|
||||
}
|
||||
|
||||
nassertd(_lock_count > 0) {
|
||||
}
|
||||
|
||||
--_lock_count;
|
||||
if (_lock_count == 0) {
|
||||
// That was the last lock held by this thread. Release the lock.
|
||||
_locking_thread = (Thread *)NULL;
|
||||
_cvar.signal();
|
||||
}
|
||||
_global_mutex.release();
|
||||
}
|
||||
#endif // !HAVE_REMUTEXIMPL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: ReMutexDirect::output
|
||||
// Access: Public
|
||||
// Description: This method is declared virtual in MutexDebug, but
|
||||
// non-virtual in ReMutexDirect.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ReMutexDirect::
|
||||
output(ostream &out) const {
|
||||
out << "ReMutex " << (void *)this;
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// Filename: reMutexDirect.h
|
||||
// Created by: drose (13Feb06)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 REMUTEXDIRECT_H
|
||||
#define REMUTEXDIRECT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "mutexImpl.h"
|
||||
#include "conditionVarImpl.h"
|
||||
|
||||
class Thread;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ReMutexDirect
|
||||
// Description : This class implements a standard reMutex by making
|
||||
// direct calls to the underlying implementation layer.
|
||||
// It doesn't perform any debugging operations.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ReMutexDirect {
|
||||
protected:
|
||||
INLINE ReMutexDirect();
|
||||
INLINE ~ReMutexDirect();
|
||||
private:
|
||||
INLINE ReMutexDirect(const ReMutexDirect ©);
|
||||
INLINE void operator = (const ReMutexDirect ©);
|
||||
|
||||
public:
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
INLINE void lock() const;
|
||||
INLINE void release() const;
|
||||
#else
|
||||
void lock() const;
|
||||
void release() const;
|
||||
#endif
|
||||
|
||||
INLINE bool debug_is_locked() const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
private:
|
||||
#ifdef HAVE_REMUTEXIMPL
|
||||
ReMutexImpl _impl;
|
||||
|
||||
#else
|
||||
// If we don't have a reentrant mutex, we have to hand-roll one.
|
||||
Thread *_locking_thread;
|
||||
int _lock_count;
|
||||
ConditionVarImpl _cvar;
|
||||
|
||||
static MutexImpl _global_lock;
|
||||
#endif // HAVE_REMUTEXIMPL
|
||||
};
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const ReMutexDirect &m) {
|
||||
m.output(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
#include "reMutexDirect.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -165,7 +165,7 @@ get_ref_count() const {
|
|||
#ifndef NDEBUG
|
||||
test_ref_count_integrity();
|
||||
#endif
|
||||
return _ref_count;
|
||||
return AtomicAdjust::get(_ref_count);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -55,5 +55,11 @@
|
|||
|
||||
#endif
|
||||
|
||||
// Let's also factor out some of the other configuration variables.
|
||||
#if defined(DO_PIPELINING) && defined(HAVE_THREADS)
|
||||
#define THREADED_PIPELINE 1
|
||||
#else
|
||||
#undef THREADED_PIPELINE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,9 +33,7 @@
|
|||
static int last_rand = 0;
|
||||
#endif /* __WIN32__ */
|
||||
|
||||
Mutex print_mutex;
|
||||
|
||||
#define PRINTMSG(x) { MutexHolder l(print_mutex); x; }
|
||||
#define PRINTMSG(x) { MutexHolder l(Mutex::_notify_mutex); x; }
|
||||
|
||||
Mutex rand_mutex;
|
||||
|
||||
|
|
@ -53,7 +51,16 @@ static double random_f(double max)
|
|||
// afford luxuries like 2 chopsticks per person.
|
||||
#define N_DINERS 5
|
||||
|
||||
Mutex chopsticks[N_DINERS];
|
||||
class ChopstickMutex : public Mutex {
|
||||
public:
|
||||
void output(ostream &out) const {
|
||||
out << "chopstick " << _n;
|
||||
}
|
||||
int _n;
|
||||
};
|
||||
|
||||
|
||||
ChopstickMutex chopsticks[N_DINERS];
|
||||
|
||||
// At most n philosophers are allowed into the room, others would have to
|
||||
// wait at the door. This restriction demonstrates the use of condition
|
||||
|
|
@ -81,17 +88,20 @@ private:
|
|||
int r = l+1;
|
||||
if (r == N_DINERS)
|
||||
r = 0;
|
||||
/*
|
||||
if (l & 1) {
|
||||
int t = l;
|
||||
l = r;
|
||||
r = t;
|
||||
}
|
||||
*/
|
||||
PRINTMSG(cerr << "Philosopher #" << _id << " has entered the room."
|
||||
<< endl);
|
||||
int count = (int)random_f(10.0) + 1;
|
||||
while (--count) {
|
||||
chopsticks[l].lock();
|
||||
chopsticks[r].lock();
|
||||
Thread::sleep(1);
|
||||
chopsticks[l].lock();
|
||||
PRINTMSG(cerr << "Philosopher #" << _id
|
||||
<< " is eating spaghetti now." << endl);
|
||||
Thread::sleep(random_f(3.0));
|
||||
|
|
@ -115,12 +125,19 @@ public:
|
|||
philosopher(const int id) : Thread("philosopher", "a") {
|
||||
_id = id;
|
||||
}
|
||||
|
||||
virtual void output(ostream &out) const {
|
||||
out << "philosopher " << _id;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
int i;
|
||||
room_mutex.lock();
|
||||
for (i=0; i<N_DINERS; ++i) {
|
||||
chopsticks[i]._n = i;
|
||||
}
|
||||
for (i=0; i<N_DINERS; ++i) {
|
||||
phils[i] = new philosopher(i);
|
||||
phils[i]->start(TP_normal, false, false);
|
||||
|
|
|
|||
|
|
@ -44,6 +44,10 @@ Thread(const string &name, const string &sync_name) :
|
|||
_started = false;
|
||||
_pstats_index = -1;
|
||||
_pipeline_stage = 0;
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
_blocked_on_mutex = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -31,6 +31,9 @@ TypeHandle Thread::_type_handle;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
Thread::
|
||||
~Thread() {
|
||||
#ifdef DEBUG_THREADS
|
||||
nassertv(_blocked_on_mutex == NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@
|
|||
#include "threadImpl.h"
|
||||
#include "notify.h"
|
||||
|
||||
class Mutex;
|
||||
class ReMutex;
|
||||
class MutexDebug;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : Thread
|
||||
// Description : A thread; that is, a lightweight process. This is an
|
||||
|
|
@ -87,12 +91,18 @@ private:
|
|||
|
||||
protected:
|
||||
bool _started;
|
||||
|
||||
private:
|
||||
string _name;
|
||||
string _sync_name;
|
||||
ThreadImpl _impl;
|
||||
int _pstats_index;
|
||||
int _pipeline_stage;
|
||||
|
||||
#ifdef DEBUG_THREADS
|
||||
MutexDebug *_blocked_on_mutex;
|
||||
#endif
|
||||
|
||||
private:
|
||||
static Thread *_main_thread;
|
||||
static Thread *_external_thread;
|
||||
|
|
@ -114,6 +124,8 @@ public:
|
|||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class MutexDebug;
|
||||
|
||||
friend class ThreadDummyImpl;
|
||||
friend class ThreadWin32Impl;
|
||||
friend class ThreadPosixImpl;
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
|
||||
#include "pointerTo.h"
|
||||
#include "config_express.h"
|
||||
#include "mutexHolder.h"
|
||||
|
||||
PRUintn ThreadNsprImpl::_pt_ptr_index = 0;
|
||||
bool ThreadNsprImpl::_got_pt_ptr_index = false;
|
||||
|
|
@ -89,11 +88,15 @@ ThreadNsprImpl::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool ThreadNsprImpl::
|
||||
start(ThreadPriority priority, bool global, bool joinable) {
|
||||
MutexHolder holder(_mutex);
|
||||
_mutex.lock();
|
||||
if (thread_cat.is_debug()) {
|
||||
thread_cat.debug() << "Starting thread " << _parent_obj->get_name() << "\n";
|
||||
}
|
||||
nassertr(_thread == (PRThread *)NULL, false);
|
||||
nassertd(_thread == (PRThread *)NULL) {
|
||||
_mutex.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
_joinable = joinable;
|
||||
|
||||
if (!_got_pt_ptr_index) {
|
||||
|
|
@ -107,10 +110,6 @@ start(ThreadPriority priority, bool global, bool joinable) {
|
|||
nspr_pri = PR_PRIORITY_LOW;
|
||||
break;
|
||||
|
||||
case TP_normal:
|
||||
nspr_pri = PR_PRIORITY_NORMAL;
|
||||
break;
|
||||
|
||||
case TP_high:
|
||||
nspr_pri = PR_PRIORITY_HIGH;
|
||||
break;
|
||||
|
|
@ -119,8 +118,8 @@ start(ThreadPriority priority, bool global, bool joinable) {
|
|||
nspr_pri = PR_PRIORITY_URGENT;
|
||||
break;
|
||||
|
||||
case TP_normal:
|
||||
default:
|
||||
nassertr(false, false);
|
||||
nspr_pri = PR_PRIORITY_NORMAL;
|
||||
}
|
||||
|
||||
|
|
@ -140,10 +139,12 @@ start(ThreadPriority priority, bool global, bool joinable) {
|
|||
// reference count we incremented above, and return false to
|
||||
// indicate failure.
|
||||
unref_delete(_parent_obj);
|
||||
_mutex.release();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Thread was successfully started.
|
||||
_mutex.release();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -172,11 +173,12 @@ interrupt() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void ThreadNsprImpl::
|
||||
join() {
|
||||
MutexHolder holder(_mutex);
|
||||
_mutex.lock();
|
||||
if (_joinable && _thread != (PRThread *)NULL) {
|
||||
PR_JoinThread(_thread);
|
||||
_thread = (PRThread *)NULL;
|
||||
}
|
||||
_mutex.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
#include "notify.h"
|
||||
#include "threadPriority.h"
|
||||
#include "pmutex.h"
|
||||
#include "mutexNsprImpl.h"
|
||||
|
||||
#include <prthread.h>
|
||||
#include <prinit.h>
|
||||
|
|
@ -57,7 +57,7 @@ private:
|
|||
static void root_func(void *data);
|
||||
static void init_pt_ptr_index();
|
||||
|
||||
Mutex _mutex;
|
||||
MutexNsprImpl _mutex;
|
||||
Thread *_parent_obj;
|
||||
PRThread *_thread;
|
||||
bool _joinable;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue