Browse Source

Merge branch 'release/1.10.x'

rdb 3 years ago
parent
commit
e1b4083d6d

+ 6 - 7
direct/src/showbase/GarbageReport.py

@@ -8,9 +8,8 @@ from direct.showbase.PythonUtil import itype, deeptype, fastRepr
 from direct.showbase.Job import Job
 from direct.showbase.Job import Job
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.JobManagerGlobal import jobMgr
 from direct.showbase.MessengerGlobal import messenger
 from direct.showbase.MessengerGlobal import messenger
-import direct.showbase.DConfig as config
+from panda3d.core import ConfigVariableBool
 import gc
 import gc
-import types
 
 
 GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
 GarbageCycleCountAnnounceEvent = 'announceGarbageCycleDesc2num'
 
 
@@ -213,7 +212,7 @@ class GarbageReport(Job):
                     startIndex = 0
                     startIndex = 0
                     # + 1 to include a reference back to the first object
                     # + 1 to include a reference back to the first object
                     endIndex = numObjs + 1
                     endIndex = numObjs + 1
-                    if type(objs[-1]) is types.InstanceType and type(objs[0]) is dict:
+                    if type(objs[0]) is dict and hasattr(objs[-1], '__dict__'):
                         startIndex -= 1
                         startIndex -= 1
                         endIndex -= 1
                         endIndex -= 1
 
 
@@ -222,7 +221,7 @@ class GarbageReport(Job):
                             numToSkip -= 1
                             numToSkip -= 1
                             continue
                             continue
                         obj = objs[index]
                         obj = objs[index]
-                        if type(obj) is types.InstanceType:
+                        if hasattr(obj, '__dict__'):
                             if not objAlreadyRepresented:
                             if not objAlreadyRepresented:
                                 cycleBySyntax += '%s' % obj.__class__.__name__
                                 cycleBySyntax += '%s' % obj.__class__.__name__
                             cycleBySyntax += '.'
                             cycleBySyntax += '.'
@@ -307,7 +306,7 @@ class GarbageReport(Job):
             while n > 0:
             while n > 0:
                 yield None
                 yield None
                 digits += 1
                 digits += 1
-                n /= 10
+                n = n // 10
             digits = digits
             digits = digits
             format = '%0' + '%s' % digits + 'i:%s \t%s'
             format = '%0' + '%s' % digits + 'i:%s \t%s'
 
 
@@ -562,7 +561,7 @@ class _CFGLGlobals:
 def checkForGarbageLeaks():
 def checkForGarbageLeaks():
     gc.collect()
     gc.collect()
     numGarbage = len(gc.garbage)
     numGarbage = len(gc.garbage)
-    if numGarbage > 0 and config.GetBool('auto-garbage-logging', 0):
+    if numGarbage > 0 and ConfigVariableBool('auto-garbage-logging', False):
         if numGarbage != _CFGLGlobals.LastNumGarbage:
         if numGarbage != _CFGLGlobals.LastNumGarbage:
             print("")
             print("")
             gr = GarbageReport('found garbage', threaded=False, collect=False)
             gr = GarbageReport('found garbage', threaded=False, collect=False)
@@ -572,7 +571,7 @@ def checkForGarbageLeaks():
             messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
             messenger.send(GarbageCycleCountAnnounceEvent, [gr.getDesc2numDict()])
             gr.destroy()
             gr.destroy()
         notify = directNotify.newCategory("GarbageDetect")
         notify = directNotify.newCategory("GarbageDetect")
-        if config.GetBool('allow-garbage-cycles', 1):
+        if ConfigVariableBool('allow-garbage-cycles', True):
             func = notify.warning
             func = notify.warning
         else:
         else:
             func = notify.error
             func = notify.error

+ 2 - 0
dtool/src/prc/CMakeLists.txt

@@ -76,6 +76,8 @@ endif()
 set(P3PRC_IGATEEXT
 set(P3PRC_IGATEEXT
   configVariable_ext.cxx
   configVariable_ext.cxx
   configVariable_ext.h
   configVariable_ext.h
+  notify_ext.cxx
+  notify_ext.h
   streamReader_ext.cxx
   streamReader_ext.cxx
   streamReader_ext.h
   streamReader_ext.h
   streamWriter_ext.cxx
   streamWriter_ext.cxx

+ 48 - 0
dtool/src/prc/notify_ext.cxx

@@ -0,0 +1,48 @@
+/**
+ * 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 notify_ext.cxx
+ * @author rdb
+ * @date 2022-12-09
+ */
+
+#include "notify_ext.h"
+
+#ifdef HAVE_PYTHON
+
+/**
+ * Changes the ostream that all subsequent Notify messages will be written to.
+ * If the previous ostream was set with delete_later = true, this will delete
+ * the previous ostream.  If ostream_ptr is None, this resets the default to
+ * cerr.
+ */
+void Extension<Notify>::
+set_ostream_ptr(PyObject *ostream_ptr, bool delete_later) {
+  extern struct Dtool_PyTypedObject Dtool_std_ostream;
+
+  if (ostream_ptr == Py_None) {
+    _this->set_ostream_ptr(nullptr, false);
+    return;
+  }
+
+  std::ostream *ptr = (std::ostream *)DTOOL_Call_GetPointerThisClass(ostream_ptr, &Dtool_std_ostream, 1, "Notify.set_ostream_ptr", false, true);
+  if (ptr == nullptr) {
+    return;
+  }
+
+  // Since we now have a reference to this class on the C++ end, make sure
+  // that the ostream isn't being destructed when its Python wrapper expires.
+  // Note that this may cause a memory leak if delete_later is not set, but
+  // since these pointers are usually set once for the rest of time, this is
+  // considered less of a problem than having the Python object destroy the
+  // object while C++ is still using it.  See GitHub #1371.
+  ((Dtool_PyInstDef *)ostream_ptr)->_memory_rules = false;
+  _this->set_ostream_ptr(ptr, delete_later);
+}
+
+#endif  // HAVE_PYTHON

+ 37 - 0
dtool/src/prc/notify_ext.h

@@ -0,0 +1,37 @@
+/**
+ * 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 notify_ext.h
+ * @author rdb
+ * @date 2022-12-09
+ */
+
+#ifndef NOTIFY_EXT_H
+#define NOTIFY_EXT_H
+
+#include "dtoolbase.h"
+
+#ifdef HAVE_PYTHON
+
+#include "extension.h"
+#include "pnotify.h"
+#include "py_panda.h"
+
+/**
+ * This class defines the extension methods for Notify, which are called
+ * instead of any C++ methods with the same prototype.
+ */
+template<>
+class Extension<Notify> : public ExtensionBase<Notify> {
+public:
+  void set_ostream_ptr(PyObject *ostream_ptr, bool delete_later);
+};
+
+#endif  // HAVE_PYTHON
+
+#endif  // NOTIFY_EXT_H

+ 1 - 0
dtool/src/prc/p3prc_ext_composite.cxx

@@ -1,3 +1,4 @@
 #include "configVariable_ext.cxx"
 #include "configVariable_ext.cxx"
+#include "notify_ext.cxx"
 #include "streamReader_ext.cxx"
 #include "streamReader_ext.cxx"
 #include "streamWriter_ext.cxx"
 #include "streamWriter_ext.cxx"

+ 4 - 0
dtool/src/prc/pnotify.h

@@ -35,7 +35,11 @@ PUBLISHED:
   Notify();
   Notify();
   ~Notify();
   ~Notify();
 
 
+#if defined(CPPPARSER) && defined(HAVE_PYTHON)
+  EXTEND void set_ostream_ptr(PyObject *ostream_ptr, bool delete_later);
+#else
   void set_ostream_ptr(std::ostream *ostream_ptr, bool delete_later);
   void set_ostream_ptr(std::ostream *ostream_ptr, bool delete_later);
+#endif
   std::ostream *get_ostream_ptr() const;
   std::ostream *get_ostream_ptr() const;
 
 
   typedef bool AssertHandler(const char *expression, int line,
   typedef bool AssertHandler(const char *expression, int line,

+ 10 - 45
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -43,35 +43,12 @@
 #import <OpenGL/OpenGL.h>
 #import <OpenGL/OpenGL.h>
 #import <Carbon/Carbon.h>
 #import <Carbon/Carbon.h>
 
 
-#include <sys/sysctl.h>
-
 TypeHandle CocoaGraphicsWindow::_type_handle;
 TypeHandle CocoaGraphicsWindow::_type_handle;
 
 
 #ifndef MAC_OS_X_VERSION_10_15
 #ifndef MAC_OS_X_VERSION_10_15
 #define NSAppKitVersionNumber10_14 1671
 #define NSAppKitVersionNumber10_14 1671
 #endif
 #endif
 
 
-/**
- * Returns true if this is an arm64-based mac.
- */
-static int is_arm64_mac() {
-#ifdef __aarch64__
-  return 1;
-#elif defined(__x86_64__)
-  // Running in Rosetta 2?
-  static int ret = -1;
-  if (ret < 0) {
-    size_t size = sizeof(ret);
-    if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) == -1) {
-      ret = 0;
-    }
-  }
-  return ret;
-#else
-  return 0;
-#endif
-}
-
 /**
 /**
  *
  *
  */
  */
@@ -209,29 +186,17 @@ begin_frame(FrameMode mode, Thread *current_thread) {
   cocoagsg->lock_context();
   cocoagsg->lock_context();
 
 
   // Set the drawable.
   // Set the drawable.
-  if (_properties.get_fullscreen() && !is_arm64_mac()) {
-    // Fullscreen.  Note that this call doesn't work with the newer
-    // Metal-based OpenGL drivers.
-    CGLError err = CGLSetFullScreenOnDisplay((CGLContextObj) [cocoagsg->_context CGLContextObj], CGDisplayIDToOpenGLDisplayMask(_display));
-    if (err != kCGLNoError) {
-      cocoadisplay_cat.error()
-        << "Failed call to CGLSetFullScreenOnDisplay with display mask "
-        << CGDisplayIDToOpenGLDisplayMask(_display) << ": " << CGLErrorString(err) << "\n";
-      return false;
-    }
-  } else {
-    // Although not recommended, it is technically possible to use the same
-    // context with multiple different-sized windows.  If that happens, the
-    // context needs to be updated accordingly.
-    if ([cocoagsg->_context view] != _view) {
-      // XXX I'm not 100% sure that changing the view requires it to update.
-      _context_needs_update = true;
-      [cocoagsg->_context setView:_view];
+  // Although not recommended, it is technically possible to use the same
+  // context with multiple different-sized windows.  If that happens, the
+  // context needs to be updated accordingly.
+  if ([cocoagsg->_context view] != _view) {
+    // XXX I'm not 100% sure that changing the view requires it to update.
+    _context_needs_update = true;
+    [cocoagsg->_context setView:_view];
 
 
-      if (cocoadisplay_cat.is_spam()) {
-        cocoadisplay_cat.spam()
-          << "Switching context to view " << _view << "\n";
-      }
+    if (cocoadisplay_cat.is_spam()) {
+      cocoadisplay_cat.spam()
+        << "Switching context to view " << _view << "\n";
     }
     }
   }
   }
 
 

+ 4 - 3
panda/src/express/datagram.cxx

@@ -113,8 +113,8 @@ pad_bytes(size_t size) {
   // Now append the data.
   // Now append the data.
 
 
   // It is very important that we *don't* do this reserve() operation.  See
   // It is very important that we *don't* do this reserve() operation.  See
-  // the further comments in append_data(), below.  _data.reserve(_data.size()
-  // + size);
+  // the further comments in append_data(), below.
+  //_data.reserve(_data.size() + size);
 
 
   while (size > 0) {
   while (size > 0) {
     _data.push_back('\0');
     _data.push_back('\0');
@@ -146,7 +146,8 @@ append_data(const void *data, size_t size) {
   // actually slows it down on Windows, which takes the reserve() request as a
   // actually slows it down on Windows, which takes the reserve() request as a
   // fixed size the array should be set to (!) instead of as a minimum size to
   // fixed size the array should be set to (!) instead of as a minimum size to
   // guarantee.  This forces the array to reallocate itself with *every* call
   // guarantee.  This forces the array to reallocate itself with *every* call
-  // to append_data!  _data.reserve(_data.size() + size);
+  // to append_data!
+  //_data.reserve(_data.size() + size);
 
 
   _data.v().insert(_data.v().end(), (const unsigned char *)data,
   _data.v().insert(_data.v().end(), (const unsigned char *)data,
                    (const unsigned char *)data + size);
                    (const unsigned char *)data + size);

+ 1 - 1
panda/src/pgraph/pandaNode.h

@@ -287,7 +287,7 @@ PUBLISHED:
   // bounding volumes.
   // bounding volumes.
   void set_bounds_type(BoundingVolume::BoundsType bounds_type);
   void set_bounds_type(BoundingVolume::BoundsType bounds_type);
   BoundingVolume::BoundsType get_bounds_type() const;
   BoundingVolume::BoundsType get_bounds_type() const;
-  MAKE_PROPERTY(bounds_type, get_bounds_type);
+  MAKE_PROPERTY(bounds_type, get_bounds_type, set_bounds_type);
 
 
   void set_bounds(const BoundingVolume *volume);
   void set_bounds(const BoundingVolume *volume);
   INLINE void clear_bounds();
   INLINE void clear_bounds();

+ 2 - 1
panda/src/pstatclient/config_pstatclient.cxx

@@ -33,7 +33,8 @@ ConfigVariableDouble pstats_max_rate
 ("pstats-max-rate", 1000.0,
 ("pstats-max-rate", 1000.0,
  PRC_DESC("The maximum number of packets per second, per thread, to send "
  PRC_DESC("The maximum number of packets per second, per thread, to send "
           "to the remote PStats server.  A packet is defined as a single "
           "to the remote PStats server.  A packet is defined as a single "
-          "UDP packet, or each 1024 bytes of a TCP message."));
+          "UDP packet, or each 1024 bytes of a TCP message.  Set this to a "
+          "negative number to disable the limit."));
 
 
 ConfigVariableBool pstats_threaded_write
 ConfigVariableBool pstats_threaded_write
 ("pstats-threaded-write", true,
 ("pstats-threaded-write", true,

+ 8 - 0
panda/src/pstatclient/pStatClientControlMessage.cxx

@@ -61,6 +61,10 @@ encode(Datagram &datagram) const {
     }
     }
     break;
     break;
 
 
+  case T_expire_thread:
+    datagram.add_uint16(_first_thread_index);
+    break;
+
   default:
   default:
     pstats_cat.error()
     pstats_cat.error()
       << "Invalid PStatClientControlMessage::Type " << (int)_type << "\n";
       << "Invalid PStatClientControlMessage::Type " << (int)_type << "\n";
@@ -117,6 +121,10 @@ decode(const Datagram &datagram, PStatClientVersion *version) {
     }
     }
     break;
     break;
 
 
+  case T_expire_thread:
+    _first_thread_index = source.get_uint16();
+    break;
+
   case T_datagram:
   case T_datagram:
     // Not, strictly speaking, a control message.
     // Not, strictly speaking, a control message.
     return false;
     return false;

+ 1 - 0
panda/src/pstatclient/pStatClientControlMessage.h

@@ -39,6 +39,7 @@ public:
     T_hello,
     T_hello,
     T_define_collectors,
     T_define_collectors,
     T_define_threads,
     T_define_threads,
+    T_expire_thread,
     T_invalid
     T_invalid
   };
   };
 
 

+ 81 - 23
panda/src/pstatclient/pStatFrameData.cxx

@@ -34,7 +34,6 @@ sort_time() {
  */
  */
 bool PStatFrameData::
 bool PStatFrameData::
 write_datagram(Datagram &destination, PStatClient *client) const {
 write_datagram(Datagram &destination, PStatClient *client) const {
-  Data::const_iterator di;
   if (_time_data.size() >= 65536 || _level_data.size() >= 65536) {
   if (_time_data.size() >= 65536 || _level_data.size() >= 65536) {
     pstats_cat.info()
     pstats_cat.info()
       << "Dropping frame with " << _time_data.size()
       << "Dropping frame with " << _time_data.size()
@@ -43,16 +42,62 @@ write_datagram(Datagram &destination, PStatClient *client) const {
     return false;
     return false;
   }
   }
 
 
+#if !defined(WORDS_BIGENDIAN) || defined(__GNUC__)
+  // Hand-roll this, significantly more efficient for many data points
+  size_t size = (_time_data.size() + _level_data.size()) * 6 + 4;
+  PTA_uchar array = destination.modify_array();
+  size_t offset = array.size();
+  array.resize(offset + size);
+  unsigned char *data = &array[0] + offset;
+
+  uint16_t *ptr = (uint16_t *)data;
+
+#ifdef WORDS_BIGENDIAN
+  *ptr++ = __builtin_bswap16(_time_data.size());
+
+  for (const DataPoint &dp : _time_data) {
+    *ptr++ = __builtin_bswap16(dp._index);
+    PN_float32 v = (PN_float32)dp._value;
+    *(uint32_t *)ptr = __builtin_bswap32(reinterpret_cast<uint32_t &>(v));
+    ptr += 2;
+  }
+
+  *ptr++ = __builtin_bswap16(_level_data.size());
+  for (const DataPoint &dp : _level_data) {
+    *ptr++ = __builtin_bswap16(dp._index);
+    PN_float32 v = (PN_float32)dp._value;
+    *(uint32_t *)ptr = __builtin_bswap32(reinterpret_cast<uint32_t &>(v));
+    ptr += 2;
+  }
+#else
+  *ptr++ = _time_data.size();
+
+  for (const DataPoint &dp : _time_data) {
+    *ptr++ = dp._index;
+    *(PN_float32 *)ptr = dp._value;
+    ptr += 2;
+  }
+
+  *ptr++ = _level_data.size();
+  for (const DataPoint &dp : _level_data) {
+    *ptr++ = dp._index;
+    *(PN_float32 *)ptr = dp._value;
+    ptr += 2;
+  }
+#endif
+
+#else
   destination.add_uint16(_time_data.size());
   destination.add_uint16(_time_data.size());
-  for (di = _time_data.begin(); di != _time_data.end(); ++di) {
-    destination.add_uint16((*di)._index);
-    destination.add_float32((*di)._value);
+  for (const DataPoint &dp : _time_data) {
+    destination.add_uint16(dp._index);
+    destination.add_float32(dp._value);
   }
   }
   destination.add_uint16(_level_data.size());
   destination.add_uint16(_level_data.size());
-  for (di = _level_data.begin(); di != _level_data.end(); ++di) {
-    destination.add_uint16((*di)._index);
-    destination.add_float32((*di)._value);
+  for (const DataPoint &dp : _level_data) {
+    destination.add_uint16(dp._index);
+    destination.add_float32(dp._value);
   }
   }
+#endif
 
 
   return true;
   return true;
 }
 }
@@ -61,25 +106,38 @@ write_datagram(Datagram &destination, PStatClient *client) const {
  * Extracts the FrameData definition from the datagram.
  * Extracts the FrameData definition from the datagram.
  */
  */
 void PStatFrameData::
 void PStatFrameData::
-read_datagram(DatagramIterator &source, PStatClientVersion *) {
+read_datagram(DatagramIterator &source, PStatClientVersion *version) {
   clear();
   clear();
 
 
-  int i;
-  int time_size = source.get_uint16();
-  for (i = 0; i < time_size; i++) {
-    nassertv(source.get_remaining_size() > 0);
-    DataPoint dp;
-    dp._index = source.get_uint16();
-    dp._value = source.get_float32();
-    _time_data.push_back(dp);
+  {
+    size_t time_size;
+    if (version->is_at_least(3, 2)) {
+      time_size = source.get_uint32();
+    } else {
+      time_size = source.get_uint16();
+    }
+    _time_data.resize(time_size);
+    for (DataPoint &dp : _time_data) {
+      nassertv(source.get_remaining_size() > 0);
+      dp._index = source.get_uint16();
+      dp._value = source.get_float32();
+    }
   }
   }
-  int level_size = source.get_uint16();
-  for (i = 0; i < level_size; i++) {
-    nassertv(source.get_remaining_size() > 0);
-    DataPoint dp;
-    dp._index = source.get_uint16();
-    dp._value = source.get_float32();
-    _level_data.push_back(dp);
+
+  {
+    size_t level_size;
+    if (version->is_at_least(3, 2)) {
+      level_size = source.get_uint32();
+    } else {
+      level_size = source.get_uint16();
+    }
+    _level_data.resize(level_size);
+    for (DataPoint &dp : _level_data) {
+      nassertv(source.get_remaining_size() > 0);
+      dp._index = source.get_uint16();
+      dp._value = source.get_float32();
+    }
   }
   }
+
   //nassertv(source.get_remaining_size() == 0);
   //nassertv(source.get_remaining_size() == 0);
 }
 }

+ 1 - 0
panda/src/pstatclient/pStatProperties.cxx

@@ -31,6 +31,7 @@ static const int current_pstat_minor_version = 0;
 // Incremented to 2.1 on 5/21/01 to add support for TCP frame data.
 // Incremented to 2.1 on 5/21/01 to add support for TCP frame data.
 // Incremented to 3.0 on 4/28/05 to bump TCP headers to 32 bits.
 // Incremented to 3.0 on 4/28/05 to bump TCP headers to 32 bits.
 // Incremented to 3.1 on 11/29/22 to support nested start/stop pairs.
 // Incremented to 3.1 on 11/29/22 to support nested start/stop pairs.
+// Incremented to 3.2 on 12/10/22 to use 32-bit data counts, T_expire_thread.
 
 
 /**
 /**
  * Returns the current major version number of the PStats protocol.  This is
  * Returns the current major version number of the PStats protocol.  This is

+ 5 - 1
pandatool/src/pstatserver/pStatReader.cxx

@@ -195,7 +195,7 @@ handle_client_control_message(const PStatClientControlMessage &message) {
       if (message._major_version != server_major_version ||
       if (message._major_version != server_major_version ||
           (message._major_version == server_major_version &&
           (message._major_version == server_major_version &&
            message._minor_version > server_minor_version &&
            message._minor_version > server_minor_version &&
-           (message._major_version != 3 || message._minor_version != 1))) {
+           (message._major_version != 3 || message._minor_version > 2))) {
         _monitor->bad_version(message._client_hostname, message._client_progname,
         _monitor->bad_version(message._client_hostname, message._client_progname,
                               message._client_pid,
                               message._client_pid,
                               message._major_version, message._minor_version,
                               message._major_version, message._minor_version,
@@ -228,6 +228,10 @@ handle_client_control_message(const PStatClientControlMessage &message) {
     }
     }
     break;
     break;
 
 
+  case PStatClientControlMessage::T_expire_thread:
+    // Ignore for now.
+    break;
+
   default:
   default:
     nout << "Invalid control message received from client.\n";
     nout << "Invalid control message received from client.\n";
   }
   }