Merge branch 'master' into cmake
This commit is contained in:
commit
e917c54433
|
|
@ -61,7 +61,14 @@ class DirectFrame(DirectGuiWidget):
|
|||
def destroy(self):
|
||||
DirectGuiWidget.destroy(self)
|
||||
|
||||
def setText(self):
|
||||
def clearText(self):
|
||||
self['text'] = None
|
||||
self.setText()
|
||||
|
||||
def setText(self, text=None):
|
||||
if text is not None:
|
||||
self['text'] = text
|
||||
|
||||
# Determine if user passed in single string or a sequence
|
||||
if self['text'] == None:
|
||||
textList = (None,) * self['numStates']
|
||||
|
|
@ -100,7 +107,14 @@ class DirectFrame(DirectGuiWidget):
|
|||
sort = DGG.TEXT_SORT_INDEX,
|
||||
)
|
||||
|
||||
def setGeom(self):
|
||||
def clearGeom(self):
|
||||
self['geom'] = None
|
||||
self.setGeom()
|
||||
|
||||
def setGeom(self, geom=None):
|
||||
if geom is not None:
|
||||
self['geom'] = geom
|
||||
|
||||
# Determine argument type
|
||||
geom = self['geom']
|
||||
|
||||
|
|
@ -142,7 +156,14 @@ class DirectFrame(DirectGuiWidget):
|
|||
geom = geom, scale = 1,
|
||||
sort = DGG.GEOM_SORT_INDEX)
|
||||
|
||||
def setImage(self):
|
||||
def clearImage(self):
|
||||
self['image'] = None
|
||||
self.setImage()
|
||||
|
||||
def setImage(self, image=None):
|
||||
if image is not None:
|
||||
self['image'] = image
|
||||
|
||||
# Determine argument type
|
||||
arg = self['image']
|
||||
if arg == None:
|
||||
|
|
|
|||
|
|
@ -934,8 +934,8 @@ class Loader(DirectObject):
|
|||
just as in loadModel(); otherwise, the loading happens before
|
||||
loadSound() returns."""
|
||||
|
||||
if not isinstance(soundPath, (MovieAudio, tuple, list, set)):
|
||||
# We were given a single sound pathname.
|
||||
if not isinstance(soundPath, (tuple, list, set)):
|
||||
# We were given a single sound pathname or a MovieAudio instance.
|
||||
soundList = [soundPath]
|
||||
gotList = False
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@
|
|||
// interrogate pass (CPPPARSER isn't defined), this maps to public.
|
||||
#define PUBLISHED __published
|
||||
|
||||
#define PHAVE_ATOMIC 1
|
||||
|
||||
typedef int ios_openmode;
|
||||
typedef int ios_fmtflags;
|
||||
typedef int ios_iostate;
|
||||
|
|
@ -93,6 +95,23 @@ typedef std::ios::iostate ios_iostate;
|
|||
typedef std::ios::seekdir ios_seekdir;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALWAYS_INLINE __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
#define ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
#else
|
||||
#define ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#ifdef FORCE_INLINING
|
||||
// If FORCE_INLINING is defined, we use the keyword __forceinline, which tells
|
||||
// MS VC++ to override its internal benefit heuristic and inline the fn if it
|
||||
// is technically possible to do so.
|
||||
#define INLINE ALWAYS_INLINE
|
||||
#else
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
// Apple has an outdated libstdc++. Not all is lost, though, as we can fill
|
||||
// in some important missing functions.
|
||||
#if defined(__GLIBCXX__) && __GLIBCXX__ <= 20070719
|
||||
|
|
@ -115,24 +134,38 @@ namespace std {
|
|||
}
|
||||
|
||||
template<class T> struct owner_less;
|
||||
|
||||
typedef enum memory_order {
|
||||
memory_order_relaxed,
|
||||
memory_order_consume,
|
||||
memory_order_acquire,
|
||||
memory_order_release,
|
||||
memory_order_acq_rel,
|
||||
memory_order_seq_cst,
|
||||
} memory_order;
|
||||
|
||||
#define ATOMIC_FLAG_INIT { 0 }
|
||||
class atomic_flag {
|
||||
bool _flag;
|
||||
|
||||
public:
|
||||
atomic_flag() noexcept = default;
|
||||
ALWAYS_INLINE constexpr atomic_flag(bool flag) noexcept : _flag(flag) {}
|
||||
atomic_flag(const atomic_flag &) = delete;
|
||||
~atomic_flag() noexcept = default;
|
||||
atomic_flag &operator = (const atomic_flag&) = delete;
|
||||
|
||||
ALWAYS_INLINE bool test_and_set(memory_order order = memory_order_seq_cst) noexcept {
|
||||
return __atomic_test_and_set(&_flag, order);
|
||||
}
|
||||
ALWAYS_INLINE void clear(memory_order order = memory_order_seq_cst) noexcept {
|
||||
__atomic_clear(&_flag, order);
|
||||
}
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALWAYS_INLINE __forceinline
|
||||
#elif defined(__GNUC__)
|
||||
#define ALWAYS_INLINE __attribute__((always_inline)) inline
|
||||
#else
|
||||
#define ALWAYS_INLINE inline
|
||||
#endif
|
||||
|
||||
#ifdef FORCE_INLINING
|
||||
// If FORCE_INLINING is defined, we use the keyword __forceinline, which tells
|
||||
// MS VC++ to override its internal benefit heuristic and inline the fn if it
|
||||
// is technically possible to do so.
|
||||
#define INLINE ALWAYS_INLINE
|
||||
#else
|
||||
#define INLINE inline
|
||||
// Expect that we have access to the <atomic> header.
|
||||
#define PHAVE_ATOMIC 1
|
||||
#endif
|
||||
|
||||
// Determine the availability of C++11 features.
|
||||
|
|
|
|||
|
|
@ -11,13 +11,6 @@
|
|||
* @date 2006-04-11
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
constexpr MutexSpinlockImpl::
|
||||
MutexSpinlockImpl() : _lock(0) {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
|
@ -33,7 +26,7 @@ lock() {
|
|||
*/
|
||||
INLINE bool MutexSpinlockImpl::
|
||||
try_lock() {
|
||||
return (AtomicAdjust::compare_and_exchange(_lock, 0, 1) == 0);
|
||||
return !_flag.test_and_set(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -41,5 +34,5 @@ try_lock() {
|
|||
*/
|
||||
INLINE void MutexSpinlockImpl::
|
||||
unlock() {
|
||||
AtomicAdjust::set(_lock, 0);
|
||||
_flag.clear(std::memory_order_release);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,21 @@
|
|||
|
||||
#include "mutexSpinlockImpl.h"
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64) || defined(_M_IX86) || defined(_M_X64)
|
||||
#include <emmintrin.h>
|
||||
#define PAUSE() _mm_pause()
|
||||
#else
|
||||
#define PAUSE()
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void MutexSpinlockImpl::
|
||||
do_lock() {
|
||||
while (AtomicAdjust::compare_and_exchange(_lock, 0, 1) != 0) {
|
||||
// Loop until we changed the flag from 0 to 1 (and it wasn't already 1).
|
||||
while (_flag.test_and_set(std::memory_order_acquire)) {
|
||||
PAUSE();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@
|
|||
|
||||
#ifdef MUTEX_SPINLOCK
|
||||
|
||||
#include "atomicAdjust.h"
|
||||
#ifdef PHAVE_ATOMIC
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Uses a simple user-space spinlock to implement a mutex. It is usually not
|
||||
|
|
@ -29,7 +31,7 @@
|
|||
*/
|
||||
class EXPCL_DTOOL_DTOOLBASE MutexSpinlockImpl {
|
||||
public:
|
||||
constexpr MutexSpinlockImpl();
|
||||
constexpr MutexSpinlockImpl() noexcept = default;
|
||||
MutexSpinlockImpl(const MutexSpinlockImpl ©) = delete;
|
||||
|
||||
MutexSpinlockImpl &operator = (const MutexSpinlockImpl ©) = delete;
|
||||
|
|
@ -42,7 +44,7 @@ public:
|
|||
private:
|
||||
void do_lock();
|
||||
|
||||
TVOLATILE AtomicAdjust::Integer _lock;
|
||||
std::atomic_flag _flag = ATOMIC_FLAG_INIT;
|
||||
};
|
||||
|
||||
#include "mutexSpinlockImpl.I"
|
||||
|
|
|
|||
|
|
@ -254,14 +254,13 @@ call_function(ostream &out, int indent_level, bool convert_result,
|
|||
&parser);
|
||||
out << " = " << call << ";\n";
|
||||
|
||||
// MOVE() expands to std::move() when we are compiling with a compiler
|
||||
// that supports rvalue references. It basically turns an lvalue into
|
||||
// Use of the C++11 std::move function basically turns an lvalue into
|
||||
// an rvalue, allowing a move constructor to be called instead of a
|
||||
// copy constructor (since we won't be using the return value any
|
||||
// more), which is usually more efficient if it exists. If it
|
||||
// doesn't, it shouldn't do any harm.
|
||||
string new_str =
|
||||
_return_type->prepare_return_expr(out, indent_level, "MOVE(result)");
|
||||
_return_type->prepare_return_expr(out, indent_level, "std::move(result)");
|
||||
return_expr = _return_type->get_return_expr(new_str);
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -5491,7 +5491,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
|
||||
// Use move constructor when available for functions that take an
|
||||
// actual PointerTo. This eliminates an unref()ref() pair.
|
||||
pexpr_string = "MOVE(" + param_name + "_this)";
|
||||
pexpr_string = "std::move(" + param_name + "_this)";
|
||||
|
||||
} else {
|
||||
// This is a move-assignable type, such as TypeHandle or LVecBase4.
|
||||
|
|
@ -6156,7 +6156,7 @@ write_function_instance(ostream &out, FunctionRemap *remap,
|
|||
indent(out, indent_level) << "return true;\n";
|
||||
|
||||
} else if (TypeManager::is_reference_count(remap->_cpptype)) {
|
||||
indent(out, indent_level) << "coerced = MOVE(" << return_expr << ");\n";
|
||||
indent(out, indent_level) << "coerced = std::move(" << return_expr << ");\n";
|
||||
indent(out, indent_level) << "return true;\n";
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -516,7 +516,7 @@ main(int argc, char **argv) {
|
|||
cerr << "Error parsing file: '" << argv[i] << "'\n";
|
||||
exit(1);
|
||||
}
|
||||
builder.add_source_file(filename);
|
||||
builder.add_source_file(filename.to_os_generic());
|
||||
}
|
||||
|
||||
// Now that we've parsed all the source code, change the way things are
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ pass_parameter(std::ostream &out, const std::string &variable_name) {
|
|||
if (variable_name.size() > 1 && variable_name[0] == '&') {
|
||||
// Prevent generating something like *¶m Also, if this is really some
|
||||
// local type, we can presumably just move it?
|
||||
out << "MOVE(" << variable_name.substr(1) << ")";
|
||||
out << "std::move(" << variable_name.substr(1) << ")";
|
||||
} else {
|
||||
out << "*" << variable_name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ pass_parameter(std::ostream &out, const std::string &variable_name) {
|
|||
// this parameter is an rvalue reference, but CPPParser can't know that,
|
||||
// and it might have an overload that takes an rvalue reference. It
|
||||
// shouldn't hurt either way.
|
||||
out << "MOVE(" << variable_name.substr(1) << ")";
|
||||
out << "std::move(" << variable_name.substr(1) << ")";
|
||||
} else {
|
||||
out << "*" << variable_name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2271,6 +2271,7 @@ DTOOL_CONFIG=[
|
|||
("OS_SIMPLE_THREADS", '1', '1'),
|
||||
("DEBUG_THREADS", 'UNDEF', 'UNDEF'),
|
||||
("HAVE_POSIX_THREADS", 'UNDEF', '1'),
|
||||
("MUTEX_SPINLOCK", 'UNDEF', 'UNDEF'),
|
||||
("HAVE_AUDIO", '1', '1'),
|
||||
("NOTIFY_DEBUG", 'UNDEF', 'UNDEF'),
|
||||
("DO_PSTATS", 'UNDEF', 'UNDEF'),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ default_platform = get_platform()
|
|||
|
||||
if default_platform.startswith("linux-"):
|
||||
# Is this manylinux1?
|
||||
if os.path.isfile("/lib/libc-2.5.so") and os.path.isdir("/opt/python"):
|
||||
if (os.path.isfile("/lib/libc-2.5.so") or os.path.isfile("/lib64/libc-2.5.so")) and os.path.isdir("/opt/python"):
|
||||
default_platform = default_platform.replace("linux", "manylinux1")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -248,8 +248,8 @@ inline std::ostream &operator <<(std::ostream &out, const PartBundle &bundle) {
|
|||
return out;
|
||||
}
|
||||
|
||||
std::ostream &operator <<(std::ostream &out, PartBundle::BlendType blend_type);
|
||||
std::istream &operator >>(std::istream &in, PartBundle::BlendType &blend_type);
|
||||
EXPCL_PANDA_CHAN std::ostream &operator <<(std::ostream &out, PartBundle::BlendType blend_type);
|
||||
EXPCL_PANDA_CHAN std::istream &operator >>(std::istream &in, PartBundle::BlendType &blend_type);
|
||||
|
||||
#include "partBundle.I"
|
||||
|
||||
|
|
|
|||
|
|
@ -3463,7 +3463,7 @@ do_issue_material() {
|
|||
cur_material.Emissive = *(D3DCOLORVALUE *)(color.get_data());
|
||||
cur_material.Power = material->get_shininess();
|
||||
|
||||
if (material->has_diffuse()) {
|
||||
if (material->has_diffuse() || material->has_base_color()) {
|
||||
// If the material specifies an diffuse color, use it.
|
||||
set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||
} else {
|
||||
|
|
@ -3476,7 +3476,7 @@ do_issue_material() {
|
|||
set_render_state(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
|
||||
}
|
||||
}
|
||||
if (material->has_ambient()) {
|
||||
if (material->has_ambient() || material->has_base_color()) {
|
||||
// If the material specifies an ambient color, use it.
|
||||
set_render_state(D3DRS_AMBIENTMATERIALSOURCE, D3DMCS_MATERIAL);
|
||||
} else {
|
||||
|
|
@ -3490,7 +3490,7 @@ do_issue_material() {
|
|||
}
|
||||
}
|
||||
|
||||
if (material->has_specular()) {
|
||||
if (material->has_specular() || material->has_base_color()) {
|
||||
set_render_state(D3DRS_SPECULARENABLE, TRUE);
|
||||
} else {
|
||||
set_render_state(D3DRS_SPECULARENABLE, FALSE);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
* connectivity, and generates a set of EggTriangleStrips that represent the
|
||||
* same geometry.
|
||||
*/
|
||||
class EggMesher {
|
||||
class EXPCL_PANDA_EGG EggMesher {
|
||||
public:
|
||||
EggMesher();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class EggMesherStrip;
|
|||
* connected triangles. The edge is actually represented as a pair of vertex
|
||||
* indices into the same vertex pool.
|
||||
*/
|
||||
class EggMesherEdge {
|
||||
class EXPCL_PANDA_EGG EggMesherEdge {
|
||||
public:
|
||||
INLINE EggMesherEdge(int vi_a, int vi_b);
|
||||
INLINE EggMesherEdge(const EggMesherEdge ©);
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ class EggMesher;
|
|||
* This class is used by EggMesher::find_fans() to attempt to make an
|
||||
* EggTriangleFan out of the polygons connected to the indicated vertex.
|
||||
*/
|
||||
class EggMesherFanMaker {
|
||||
class EXPCL_PANDA_EGG EggMesherFanMaker {
|
||||
public:
|
||||
typedef plist<const EggMesherEdge *> Edges;
|
||||
typedef plist<EggMesherStrip *> Strips;
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class EggMesherEdge;
|
|||
* mesher. It might also represent a single polygon such as a triangle or
|
||||
* quad, since that's how strips generally start out.
|
||||
*/
|
||||
class EggMesherStrip {
|
||||
class EXPCL_PANDA_EGG EggMesherStrip {
|
||||
public:
|
||||
enum PrimType {
|
||||
PT_poly,
|
||||
|
|
|
|||
|
|
@ -677,7 +677,15 @@ transform(const LMatrix4d &mat) {
|
|||
typedef pvector<EggVertex *> Verts;
|
||||
Verts verts;
|
||||
verts.reserve(size());
|
||||
|
||||
// Work around MSVC 2017 compiler bug, see GitHub issue #379
|
||||
#ifdef _MSC_VER
|
||||
for (const IndexVertices::value_type &v : _index_vertices) {
|
||||
verts.push_back(v.second);
|
||||
}
|
||||
#else
|
||||
std::copy(begin(), end(), std::back_inserter(verts));
|
||||
#endif
|
||||
|
||||
Verts::const_iterator vi;
|
||||
for (vi = verts.begin(); vi != verts.end(); ++vi) {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ class EggLoader;
|
|||
* It is used to collect similar polygons together for a Geom, as well as to
|
||||
* group related LOD children together under a single LOD node.
|
||||
*/
|
||||
class EggBinner : public EggBinMaker {
|
||||
class EXPCL_PANDA_EGG2PG EggBinner : public EggBinMaker {
|
||||
public:
|
||||
// The BinNumber serves to identify why a particular EggBin was created.
|
||||
enum BinNumber {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ class CharacterMaker;
|
|||
*
|
||||
* This class isn't exported from this package.
|
||||
*/
|
||||
class EggLoader {
|
||||
class EXPCL_PANDA_EGG2PG EggLoader {
|
||||
public:
|
||||
EggLoader();
|
||||
EggLoader(const EggData *data);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ class EggMaterial;
|
|||
* should be assigned to each primitive. It is assigned to EggPrimitive
|
||||
* objects via the EggBinner.
|
||||
*/
|
||||
class EggRenderState : public EggUserData {
|
||||
class EXPCL_PANDA_EGG2PG EggRenderState : public EggUserData {
|
||||
public:
|
||||
INLINE EggRenderState(EggLoader &loader);
|
||||
INLINE void add_attrib(const RenderAttrib *attrib);
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ class EggVertex;
|
|||
* complete (some Panda or egg constructs are not fully supported by this
|
||||
* class).
|
||||
*/
|
||||
class EggSaver {
|
||||
class EXPCL_PANDA_EGG2PG EggSaver {
|
||||
PUBLISHED:
|
||||
EggSaver(EggData *data = nullptr);
|
||||
|
||||
|
|
|
|||
|
|
@ -7627,7 +7627,7 @@ do_issue_material() {
|
|||
call_glMaterialfv(face, GL_EMISSION, material->get_emission());
|
||||
glMaterialf(face, GL_SHININESS, max(min(material->get_shininess(), (PN_stdfloat)128), (PN_stdfloat)0));
|
||||
|
||||
if (material->has_ambient() && material->has_diffuse()) {
|
||||
if ((material->has_ambient() && material->has_diffuse()) || material->has_base_color()) {
|
||||
// The material has both an ambient and diffuse specified. This means we
|
||||
// do not need glMaterialColor().
|
||||
glDisable(GL_COLOR_MATERIAL);
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ void Material::
|
|||
write(std::ostream &out, int indent_level) const {
|
||||
indent(out, indent_level) << "Material " << get_name() << "\n";
|
||||
if (has_base_color()) {
|
||||
indent(out, indent_level + 2) << "base_color = " << get_ambient() << "\n";
|
||||
indent(out, indent_level + 2) << "base_color = " << get_base_color() << "\n";
|
||||
}
|
||||
if (has_ambient()) {
|
||||
indent(out, indent_level + 2) << "ambient = " << get_ambient() << "\n";
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class MovieAudioCursor;
|
|||
*/
|
||||
class EXPCL_PANDA_MOVIES MovieAudio : public TypedWritableReferenceCount, public Namable {
|
||||
PUBLISHED:
|
||||
MovieAudio(const std::string &name = "Blank Audio");
|
||||
explicit MovieAudio(const std::string &name = "Blank Audio");
|
||||
virtual ~MovieAudio();
|
||||
virtual PT(MovieAudioCursor) open();
|
||||
static PT(MovieAudio) get(const Filename &name);
|
||||
|
|
|
|||
|
|
@ -258,6 +258,11 @@ analyze_renderstate(ShaderKey &key, const RenderState *rs) {
|
|||
// states to be rehashed.
|
||||
mat->mark_used_by_auto_shader();
|
||||
key._material_flags = mat->get_flags();
|
||||
|
||||
if ((key._material_flags & Material::F_base_color) != 0) {
|
||||
key._material_flags |= (Material::F_diffuse | Material::F_specular | Material::F_ambient);
|
||||
key._material_flags &= ~Material::F_base_color;
|
||||
}
|
||||
}
|
||||
|
||||
// Break out the lights by type.
|
||||
|
|
|
|||
|
|
@ -147,8 +147,8 @@ void PGItem::
|
|||
transform_changed() {
|
||||
LightReMutexHolder holder(_lock);
|
||||
PandaNode::transform_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_transform_changed(this);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_transform_changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -161,8 +161,8 @@ void PGItem::
|
|||
draw_mask_changed() {
|
||||
LightReMutexHolder holder(_lock);
|
||||
PandaNode::draw_mask_changed();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_draw_mask_changed(this);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_draw_mask_changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -530,8 +530,8 @@ enter_region(const MouseWatcherParameter ¶m) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_enter(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_enter(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -554,8 +554,8 @@ exit_region(const MouseWatcherParameter ¶m) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_exit(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_exit(this, param);
|
||||
}
|
||||
|
||||
// pgui_cat.info() << get_name() << "::exit()" << endl;
|
||||
|
|
@ -580,8 +580,8 @@ within_region(const MouseWatcherParameter ¶m) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_within(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_within(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -602,8 +602,8 @@ without_region(const MouseWatcherParameter ¶m) {
|
|||
play_sound(event);
|
||||
throw_event(event, EventParameter(ep));
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_without(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_without(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -623,8 +623,8 @@ focus_in() {
|
|||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_focus_in(this);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_focus_in(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -644,8 +644,8 @@ focus_out() {
|
|||
play_sound(event);
|
||||
throw_event(event);
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_focus_out(this);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_focus_out(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -673,8 +673,8 @@ press(const MouseWatcherParameter ¶m, bool background) {
|
|||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_press(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_press(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -697,8 +697,8 @@ release(const MouseWatcherParameter ¶m, bool background) {
|
|||
throw_event(event, EventParameter(ep));
|
||||
}
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_release(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_release(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -757,8 +757,8 @@ move(const MouseWatcherParameter ¶m) {
|
|||
<< *this << "::move(" << param << ")\n";
|
||||
}
|
||||
|
||||
if (has_notify()) {
|
||||
get_notify()->item_move(this, param);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_move(this, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1169,9 +1169,10 @@ mouse_to_local(const LPoint2 &mouse_point) const {
|
|||
*/
|
||||
void PGItem::
|
||||
frame_changed() {
|
||||
LightReMutexHolder holder(_lock);
|
||||
mark_frames_stale();
|
||||
if (has_notify()) {
|
||||
get_notify()->item_frame_changed(this);
|
||||
if (_notify != nullptr) {
|
||||
_notify->item_frame_changed(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,18 @@ TypeHandle PGScrollFrame::_type_handle;
|
|||
*
|
||||
*/
|
||||
PGScrollFrame::
|
||||
PGScrollFrame(const std::string &name) : PGVirtualFrame(name)
|
||||
PGScrollFrame(const std::string &name) :
|
||||
PGVirtualFrame(name),
|
||||
_needs_remanage(false),
|
||||
_needs_recompute_clip(false),
|
||||
_has_virtual_frame(false),
|
||||
_virtual_frame(0.0f, 0.0f, 0.0f, 0.0f),
|
||||
_manage_pieces(false),
|
||||
_auto_hide(false)
|
||||
{
|
||||
set_cull_callback();
|
||||
_canvas_computed.test_and_set();
|
||||
|
||||
_needs_remanage = false;
|
||||
_needs_recompute_canvas = false;
|
||||
_needs_recompute_clip = false;
|
||||
_has_virtual_frame = false;
|
||||
_virtual_frame.set(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
_manage_pieces = false;
|
||||
_auto_hide = false;
|
||||
_horizontal_slider = nullptr;
|
||||
_vertical_slider = nullptr;
|
||||
set_cull_callback();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -55,8 +54,8 @@ PGScrollFrame(const PGScrollFrame ©) :
|
|||
_auto_hide(copy._auto_hide)
|
||||
{
|
||||
_needs_remanage = false;
|
||||
_needs_recompute_canvas = true;
|
||||
_needs_recompute_clip = true;
|
||||
_canvas_computed.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -97,7 +96,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|||
if (_needs_recompute_clip) {
|
||||
recompute_clip();
|
||||
}
|
||||
if (_needs_recompute_canvas) {
|
||||
if (!_canvas_computed.test_and_set()) {
|
||||
recompute_canvas();
|
||||
}
|
||||
return PGVirtualFrame::cull_callback(trav, data);
|
||||
|
|
@ -257,7 +256,7 @@ remanage() {
|
|||
// Showing or hiding one of the scroll bars might have set this flag again
|
||||
// indirectly; we clear it again to avoid a feedback loop.
|
||||
_needs_remanage = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Are either or both of the scroll bars hidden?
|
||||
if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
|
||||
|
|
@ -329,19 +328,20 @@ item_draw_mask_changed(PGItem *) {
|
|||
*/
|
||||
void PGScrollFrame::
|
||||
slider_bar_adjust(PGSliderBar *) {
|
||||
LightReMutexHolder holder(_lock);
|
||||
_needs_recompute_canvas = true;
|
||||
// Indicate that recompute_canvas() needs to be called.
|
||||
_canvas_computed.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recomputes the clipping window of the PGScrollFrame, based on the position
|
||||
* of the slider bars.
|
||||
*
|
||||
* Assumes the lock is held.
|
||||
*/
|
||||
void PGScrollFrame::
|
||||
recompute_clip() {
|
||||
LightReMutexHolder holder(_lock);
|
||||
_needs_recompute_clip = false;
|
||||
_needs_recompute_canvas = true;
|
||||
_canvas_computed.clear();
|
||||
|
||||
// Figure out how to remove the scroll bars from the clip region.
|
||||
LVecBase4 clip = get_frame_style(get_state()).get_internal_frame(get_frame());
|
||||
|
|
@ -361,34 +361,40 @@ recompute_clip() {
|
|||
/**
|
||||
* Recomputes the portion of the virtual canvas that is visible within the
|
||||
* PGScrollFrame, based on the values of the slider bars.
|
||||
*
|
||||
* Assumes the lock is held.
|
||||
*/
|
||||
void PGScrollFrame::
|
||||
recompute_canvas() {
|
||||
LightReMutexHolder holder(_lock);
|
||||
_needs_recompute_canvas = false;
|
||||
const LVecBase4 &clip = _has_clip_frame ? _clip_frame : get_frame();
|
||||
|
||||
const LVecBase4 &clip = get_clip_frame();
|
||||
// Set this to true before we sample the slider bar ratios.
|
||||
// If slider_bar_adjust happens to get called while we do this, no big deal,
|
||||
// this method will just be called again next frame.
|
||||
_canvas_computed.test_and_set();
|
||||
|
||||
PN_stdfloat x = interpolate_canvas(clip[0], clip[1],
|
||||
_virtual_frame[0], _virtual_frame[1],
|
||||
_horizontal_slider);
|
||||
PN_stdfloat cx, cy;
|
||||
cx = interpolate_canvas(clip[0], clip[1],
|
||||
_virtual_frame[0], _virtual_frame[1],
|
||||
_horizontal_slider);
|
||||
|
||||
PN_stdfloat y = interpolate_canvas(clip[3], clip[2],
|
||||
_virtual_frame[3], _virtual_frame[2],
|
||||
_vertical_slider);
|
||||
cy = interpolate_canvas(clip[3], clip[2],
|
||||
_virtual_frame[3], _virtual_frame[2],
|
||||
_vertical_slider);
|
||||
|
||||
get_canvas_node()->set_transform(TransformState::make_pos(LVector3::rfu(x, 0, y)));
|
||||
_canvas_node->set_transform(TransformState::make_pos(LVector3::rfu(cx, 0, cy)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the linear translation that should be applied to the virtual
|
||||
* canvas node, based on the corresponding slider bar's position.
|
||||
*
|
||||
* Assumes the lock is held.
|
||||
*/
|
||||
PN_stdfloat PGScrollFrame::
|
||||
interpolate_canvas(PN_stdfloat clip_min, PN_stdfloat clip_max,
|
||||
PN_stdfloat canvas_min, PN_stdfloat canvas_max,
|
||||
PGSliderBar *slider_bar) {
|
||||
LightReMutexHolder holder(_lock);
|
||||
PN_stdfloat t = 0.0f;
|
||||
if (slider_bar != nullptr) {
|
||||
t = slider_bar->get_ratio();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@
|
|||
#include "pgSliderBarNotify.h"
|
||||
#include "pgSliderBar.h"
|
||||
|
||||
#ifdef PHAVE_ATOMIC
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This is a special kind of frame that pretends to be much larger than it
|
||||
* actually is. You can scroll through the frame, as if you're looking
|
||||
|
|
@ -92,7 +96,7 @@ private:
|
|||
private:
|
||||
bool _needs_remanage;
|
||||
bool _needs_recompute_clip;
|
||||
bool _needs_recompute_canvas;
|
||||
std::atomic_flag _canvas_computed;
|
||||
|
||||
bool _has_virtual_frame;
|
||||
LVecBase4 _virtual_frame;
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ protected:
|
|||
private:
|
||||
void setup_child_nodes();
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool _has_clip_frame;
|
||||
LVecBase4 _clip_frame;
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@
|
|||
#ifdef MUTEX_SPINLOCK
|
||||
|
||||
#include "conditionVarSpinlockImpl.h"
|
||||
#include "trueClock.h"
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64) || defined(_M_IX86) || defined(_M_X64)
|
||||
#include <emmintrin.h>
|
||||
#define PAUSE() _mm_pause()
|
||||
#else
|
||||
#define PAUSE()
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -23,12 +31,31 @@
|
|||
void ConditionVarSpinlockImpl::
|
||||
wait() {
|
||||
AtomicAdjust::Integer current = _event;
|
||||
_mutex.release();
|
||||
_mutex.unlock();
|
||||
|
||||
while (AtomicAdjust::get(_event) == current) {
|
||||
PAUSE();
|
||||
}
|
||||
|
||||
_mutex.acquire();
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void ConditionVarSpinlockImpl::
|
||||
wait(double timeout) {
|
||||
TrueClock *clock = TrueClock::get_global_ptr();
|
||||
double end_time = clock->get_short_time() + timeout;
|
||||
|
||||
AtomicAdjust::Integer current = _event;
|
||||
_mutex.unlock();
|
||||
|
||||
while (AtomicAdjust::get(_event) == current && clock->get_short_time() < end_time) {
|
||||
PAUSE();
|
||||
}
|
||||
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
#endif // MUTEX_SPINLOCK
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ public:
|
|||
INLINE ~ConditionVarSpinlockImpl();
|
||||
|
||||
void wait();
|
||||
void wait(double timeout);
|
||||
INLINE void notify();
|
||||
INLINE void notify_all();
|
||||
|
||||
|
|
|
|||
|
|
@ -11,21 +11,6 @@
|
|||
* @date 2008-10-08
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE LightReMutexDirect::
|
||||
LightReMutexDirect()
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
: _cvar_impl(_lock_impl)
|
||||
#endif
|
||||
{
|
||||
#ifndef HAVE_REMUTEXIMPL
|
||||
_locking_thread = nullptr;
|
||||
_lock_count = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for acquire() to match C++11 semantics.
|
||||
* @see acquire()
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ class Thread;
|
|||
*/
|
||||
class EXPCL_PANDA_PIPELINE LightReMutexDirect {
|
||||
protected:
|
||||
INLINE LightReMutexDirect();
|
||||
LightReMutexDirect() = default;
|
||||
LightReMutexDirect(const LightReMutexDirect ©) = delete;
|
||||
~LightReMutexDirect() = default;
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ PUBLISHED:
|
|||
|
||||
private:
|
||||
#ifdef HAVE_REMUTEXTRUEIMPL
|
||||
mutable ReMutexImpl _impl;
|
||||
mutable ReMutexTrueImpl _impl;
|
||||
|
||||
#else
|
||||
// If we don't have a reentrant mutex, use the one we hand-rolled in
|
||||
|
|
|
|||
|
|
@ -43,6 +43,13 @@ typedef MutexImpl MutexTrueImpl;
|
|||
#if HAVE_REMUTEXIMPL
|
||||
typedef ReMutexImpl ReMutexTrueImpl;
|
||||
#define HAVE_REMUTEXTRUEIMPL 1
|
||||
|
||||
#elif MUTEX_SPINLOCK
|
||||
// This is defined here because it needs code from pipeline.
|
||||
#include "reMutexSpinlockImpl.h"
|
||||
typedef ReMutexSpinlockImpl ReMutexTrueImpl;
|
||||
#define HAVE_REMUTEXTRUEIMPL 1
|
||||
|
||||
#else
|
||||
#undef HAVE_REMUTEXTRUEIMPL
|
||||
#endif // HAVE_REMUTEXIMPL
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
#include "reMutex.cxx"
|
||||
#include "reMutexDirect.cxx"
|
||||
#include "reMutexHolder.cxx"
|
||||
#include "reMutexSpinlockImpl.cxx"
|
||||
#include "thread.cxx"
|
||||
#include "threadDummyImpl.cxx"
|
||||
#include "threadPosixImpl.cxx"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,11 @@ ReMutexDirect()
|
|||
INLINE void ReMutexDirect::
|
||||
lock() {
|
||||
TAU_PROFILE("void ReMutexDirect::acquire()", " ", TAU_USER);
|
||||
#ifdef HAVE_REMUTEXTRUEIMPL
|
||||
_impl.lock();
|
||||
#else
|
||||
((ReMutexDirect *)this)->do_lock();
|
||||
#endif // HAVE_REMUTEXTRUEIMPL
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +47,11 @@ lock() {
|
|||
INLINE bool ReMutexDirect::
|
||||
try_lock() {
|
||||
TAU_PROFILE("void ReMutexDirect::try_acquire()", " ", TAU_USER);
|
||||
#ifdef HAVE_REMUTEXTRUEIMPL
|
||||
return _impl.try_lock();
|
||||
#else
|
||||
return ((ReMutexDirect *)this)->do_try_lock();
|
||||
#endif // HAVE_REMUTEXTRUEIMPL
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -53,7 +61,11 @@ try_lock() {
|
|||
INLINE void ReMutexDirect::
|
||||
unlock() {
|
||||
TAU_PROFILE("void ReMutexDirect::unlock()", " ", TAU_USER);
|
||||
#ifdef HAVE_REMUTEXTRUEIMPL
|
||||
_impl.unlock();
|
||||
#else
|
||||
((ReMutexDirect *)this)->do_unlock();
|
||||
#endif // HAVE_REMUTEXTRUEIMPL
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -141,11 +141,11 @@ do_elevate_lock() {
|
|||
* mutex).
|
||||
*/
|
||||
void ReMutexDirect::
|
||||
do_unlock() {
|
||||
do_unlock(Thread *current_thread) {
|
||||
_lock_impl.lock();
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (_locking_thread != Thread::get_current_thread()) {
|
||||
if (_locking_thread != current_thread) {
|
||||
std::ostringstream ostr;
|
||||
ostr << *_locking_thread << " attempted to release "
|
||||
<< *this << " which it does not own";
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ PUBLISHED:
|
|||
|
||||
private:
|
||||
#ifdef HAVE_REMUTEXTRUEIMPL
|
||||
mutable ReMutexImpl _impl;
|
||||
mutable ReMutexTrueImpl _impl;
|
||||
|
||||
#else
|
||||
// If we don't have a reentrant mutex, we have to hand-roll one.
|
||||
|
|
@ -68,7 +68,7 @@ private:
|
|||
INLINE bool do_try_lock();
|
||||
bool do_try_lock(Thread *current_thread);
|
||||
void do_elevate_lock();
|
||||
void do_unlock();
|
||||
void do_unlock(Thread *current_thread = Thread::get_current_thread());
|
||||
|
||||
Thread *_locking_thread;
|
||||
int _lock_count;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file reMutexSpinlockImpl.I
|
||||
* @author rdb
|
||||
* @date 2018-09-03
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE void ReMutexSpinlockImpl::
|
||||
unlock() {
|
||||
assert(_counter > 0);
|
||||
if (!--_counter) {
|
||||
AtomicAdjust::set_ptr(_locking_thread, nullptr);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file reMutexSpinlockImpl.cxx
|
||||
* @author rdb
|
||||
* @date 2018-09-03
|
||||
*/
|
||||
|
||||
#include "selectThreadImpl.h"
|
||||
|
||||
#ifdef MUTEX_SPINLOCK
|
||||
|
||||
#include "reMutexSpinlockImpl.h"
|
||||
#include "thread.h"
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64) || defined(_M_IX86) || defined(_M_X64)
|
||||
#include <emmintrin.h>
|
||||
#define PAUSE() _mm_pause()
|
||||
#else
|
||||
#define PAUSE()
|
||||
#endif
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void ReMutexSpinlockImpl::
|
||||
lock() {
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
Thread *locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread);
|
||||
while (locking_thread != nullptr && locking_thread != current_thread) {
|
||||
PAUSE();
|
||||
locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread);
|
||||
}
|
||||
++_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool ReMutexSpinlockImpl::
|
||||
try_lock() {
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
Thread *locking_thread = (Thread *)AtomicAdjust::compare_and_exchange_ptr(_locking_thread, nullptr, current_thread);
|
||||
if (locking_thread == nullptr || locking_thread == current_thread) {
|
||||
++_counter;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // MUTEX_SPINLOCK
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* PANDA 3D SOFTWARE
|
||||
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
||||
*
|
||||
* All use of this software is subject to the terms of the revised BSD
|
||||
* license. You should have received a copy of this license along
|
||||
* with this source code in a file named "LICENSE."
|
||||
*
|
||||
* @file reMutexSpinlockImpl.h
|
||||
* @author rdb
|
||||
* @date 2018-09-03
|
||||
*/
|
||||
|
||||
#ifndef REMUTEXSPINLOCKIMPL_H
|
||||
#define REMUTEXSPINLOCKIMPL_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
#include "selectThreadImpl.h"
|
||||
|
||||
#ifdef MUTEX_SPINLOCK
|
||||
|
||||
#include "atomicAdjust.h"
|
||||
|
||||
class Thread;
|
||||
|
||||
/**
|
||||
* Uses a simple user-space spinlock to implement a mutex. It is usually not
|
||||
* a good idea to use this implementation, unless you are building Panda for a
|
||||
* specific application on a specific SMP machine, and you are confident that
|
||||
* you have at least as many CPU's as you have threads.
|
||||
*/
|
||||
class EXPCL_PANDA_PIPELINE ReMutexSpinlockImpl {
|
||||
public:
|
||||
constexpr ReMutexSpinlockImpl() noexcept = default;
|
||||
ReMutexSpinlockImpl(const ReMutexSpinlockImpl ©) = delete;
|
||||
|
||||
ReMutexSpinlockImpl &operator = (const ReMutexSpinlockImpl ©) = delete;
|
||||
|
||||
public:
|
||||
void lock();
|
||||
bool try_lock();
|
||||
INLINE void unlock();
|
||||
|
||||
private:
|
||||
AtomicAdjust::Pointer _locking_thread = nullptr;
|
||||
unsigned int _counter = 0;
|
||||
};
|
||||
|
||||
|
||||
#include "reMutexSpinlockImpl.I"
|
||||
|
||||
#endif // MUTEX_SPINLOCK
|
||||
|
||||
#endif
|
||||
|
|
@ -1056,7 +1056,9 @@ add_collector(PStatClient::Collector *collector) {
|
|||
// the lock.
|
||||
int new_collectors_size = (_collectors_size == 0) ? 128 : _collectors_size * 2;
|
||||
CollectorPointer *new_collectors = new CollectorPointer[new_collectors_size];
|
||||
memcpy(new_collectors, _collectors, _num_collectors * sizeof(CollectorPointer));
|
||||
if (_collectors != nullptr) {
|
||||
memcpy(new_collectors, _collectors, _num_collectors * sizeof(CollectorPointer));
|
||||
}
|
||||
AtomicAdjust::set_ptr(_collectors, new_collectors);
|
||||
AtomicAdjust::set(_collectors_size, new_collectors_size);
|
||||
|
||||
|
|
@ -1091,7 +1093,9 @@ add_thread(PStatClient::InternalThread *thread) {
|
|||
// the lock.
|
||||
int new_threads_size = (_threads_size == 0) ? 128 : _threads_size * 2;
|
||||
ThreadPointer *new_threads = new ThreadPointer[new_threads_size];
|
||||
memcpy(new_threads, _threads, _num_threads * sizeof(ThreadPointer));
|
||||
if (_threads != nullptr) {
|
||||
memcpy(new_threads, _threads, _num_threads * sizeof(ThreadPointer));
|
||||
}
|
||||
// We assume that assignment to a pointer and to an int are each atomic.
|
||||
AtomicAdjust::set_ptr(_threads, new_threads);
|
||||
AtomicAdjust::set(_threads_size, new_threads_size);
|
||||
|
|
|
|||
|
|
@ -137,15 +137,6 @@ output(std::ostream &out) const {
|
|||
out << get_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a special zero-valued ButtonHandle that is used to indicate no
|
||||
* button.
|
||||
*/
|
||||
INLINE ButtonHandle ButtonHandle::
|
||||
none() {
|
||||
return _none;
|
||||
}
|
||||
|
||||
/**
|
||||
* ButtonHandle::none() evaluates to false, everything else evaluates to true.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -14,9 +14,6 @@
|
|||
#include "buttonHandle.h"
|
||||
#include "buttonRegistry.h"
|
||||
|
||||
// This is initialized to zero by static initialization.
|
||||
ButtonHandle ButtonHandle::_none;
|
||||
|
||||
TypeHandle ButtonHandle::_type_handle;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ PUBLISHED:
|
|||
|
||||
constexpr int get_index() const;
|
||||
INLINE void output(std::ostream &out) const;
|
||||
INLINE static ButtonHandle none();
|
||||
constexpr static ButtonHandle none() { return ButtonHandle(0); }
|
||||
|
||||
INLINE operator bool () const;
|
||||
|
||||
|
|
@ -65,7 +65,6 @@ PUBLISHED:
|
|||
|
||||
private:
|
||||
int _index;
|
||||
static ButtonHandle _none;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
|
|
|||
|
|
@ -2951,7 +2951,7 @@ setup_material(GLMaterial *gl_material, const Material *material) {
|
|||
|
||||
_color_material_flags = CMF_ambient | CMF_diffuse;
|
||||
|
||||
if (material->has_ambient()) {
|
||||
if (material->has_ambient() || material->has_base_color()) {
|
||||
const LColor &ambient = material->get_ambient();
|
||||
gl_material->ambient.v[0] = ambient[0];
|
||||
gl_material->ambient.v[1] = ambient[1];
|
||||
|
|
@ -2961,7 +2961,7 @@ setup_material(GLMaterial *gl_material, const Material *material) {
|
|||
_color_material_flags &= ~CMF_ambient;
|
||||
}
|
||||
|
||||
if (material->has_diffuse()) {
|
||||
if (material->has_diffuse() || material->has_base_color()) {
|
||||
const LColor &diffuse = material->get_diffuse();
|
||||
gl_material->diffuse.v[0] = diffuse[0];
|
||||
gl_material->diffuse.v[1] = diffuse[1];
|
||||
|
|
|
|||
|
|
@ -0,0 +1,60 @@
|
|||
from panda3d.core import Mutex, ReMutex
|
||||
|
||||
|
||||
def test_mutex_acquire_release():
|
||||
m = Mutex()
|
||||
m.acquire()
|
||||
|
||||
# Assert that the lock is truly held now
|
||||
assert m.debug_is_locked()
|
||||
|
||||
# Release the lock
|
||||
m.release()
|
||||
|
||||
# Make sure the lock is properly released
|
||||
assert m.try_acquire()
|
||||
|
||||
# Clean up
|
||||
m.release()
|
||||
|
||||
|
||||
def test_mutex_try_acquire():
|
||||
m = Mutex()
|
||||
|
||||
# Trying to acquire the lock should succeed
|
||||
assert m.try_acquire()
|
||||
|
||||
# Assert that the lock is truly held now
|
||||
assert m.debug_is_locked()
|
||||
|
||||
# Clean up
|
||||
m.release()
|
||||
|
||||
|
||||
def test_remutex_acquire_release():
|
||||
m = ReMutex()
|
||||
m.acquire()
|
||||
m.acquire()
|
||||
m.release()
|
||||
m.release()
|
||||
|
||||
|
||||
def test_remutex_try_acquire():
|
||||
m = ReMutex()
|
||||
|
||||
# Trying to acquire the lock should succeed
|
||||
assert m.try_acquire()
|
||||
|
||||
# Should report being locked
|
||||
assert m.debug_is_locked()
|
||||
|
||||
# Trying a second time should succeed
|
||||
assert m.try_acquire()
|
||||
|
||||
# Should still report being locked
|
||||
assert m.debug_is_locked()
|
||||
|
||||
# Clean up
|
||||
m.release()
|
||||
m.release()
|
||||
|
||||
Loading…
Reference in New Issue