2
0
Эх сурвалжийг харах

Merge branch 'master' into cmake

Sam Edwards 8 жил өмнө
parent
commit
76a7c84330
93 өөрчлөгдсөн 1553 нэмэгдсэн , 1055 устгасан
  1. 2 2
      dtool/src/dtoolbase/deletedChain.h
  2. 39 0
      dtool/src/dtoolbase/dtoolbase.h
  3. 2 2
      dtool/src/dtoolbase/memoryBase.h
  4. 12 67
      dtool/src/dtoolbase/memoryHook.I
  5. 105 5
      dtool/src/dtoolbase/memoryHook.cxx
  6. 0 21
      dtool/src/dtoolbase/memoryHook.h
  7. 5 25
      dtool/src/dtoolbase/pallocator.T
  8. 4 2
      dtool/src/dtoolbase/pallocator.h
  9. 80 6
      dtool/src/dtoolbase/typeHandle.cxx
  10. 47 25
      dtool/src/dtoolbase/typeHandle.h
  11. 13 0
      dtool/src/dtoolbase/typeRegistry.I
  12. 1 14
      dtool/src/dtoolbase/typeRegistry.cxx
  13. 1 1
      dtool/src/dtoolbase/typeRegistry.h
  14. 4 4
      dtool/src/dtoolutil/executionEnvironment.cxx
  15. 52 11
      dtool/src/dtoolutil/globPattern.cxx
  16. 13 0
      dtool/src/dtoolutil/pandaSystem.cxx
  17. 2 0
      dtool/src/dtoolutil/pandaSystem.h
  18. 1 1
      dtool/src/interrogate/interfaceMakerPythonNative.cxx
  19. 7 1
      dtool/src/interrogatedb/py_panda.h
  20. 1 2
      dtool/src/parser-inc/openssl/evp.h
  21. 8 7
      dtool/src/parser-inc/openssl/ssl.h
  22. 1 3
      dtool/src/parser-inc/openssl/x509.h
  23. 1 0
      dtool/src/prc/encryptStreamBuf.cxx
  24. 1 1
      dtool/src/prc/encryptStreamBuf.h
  25. 4 0
      dtool/src/prc/prcKeyRegistry.cxx
  26. 1 3
      dtool/src/prc/prcKeyRegistry.h
  27. 1 3
      makepanda/makepanda.py
  28. 18 1
      panda/src/cull/cullBinBackToFront.cxx
  29. 18 1
      panda/src/cull/cullBinFixed.cxx
  30. 18 1
      panda/src/cull/cullBinFrontToBack.cxx
  31. 18 1
      panda/src/cull/cullBinStateSorted.cxx
  32. 18 1
      panda/src/cull/cullBinUnsorted.cxx
  33. 6 0
      panda/src/display/displayRegion.cxx
  34. 67 95
      panda/src/display/graphicsEngine.cxx
  35. 5 4
      panda/src/display/graphicsEngine.h
  36. 1 4
      panda/src/display/graphicsPipe.cxx
  37. 8 0
      panda/src/display/graphicsStateGuardian.I
  38. 3 0
      panda/src/display/graphicsStateGuardian.cxx
  39. 3 0
      panda/src/display/graphicsStateGuardian.h
  40. 0 8
      panda/src/downloader/bioPtr.I
  41. 12 1
      panda/src/downloader/bioPtr.cxx
  42. 3 7
      panda/src/downloader/bioPtr.h
  43. 0 6
      panda/src/downloader/bioStreamBuf.h
  44. 0 6
      panda/src/downloader/bioStreamPtr.h
  45. 2 0
      panda/src/downloader/httpChannel.cxx
  46. 2 6
      panda/src/downloader/httpChannel.h
  47. 64 62
      panda/src/downloader/httpClient.cxx
  48. 5 7
      panda/src/downloader/httpClient.h
  49. 1 2
      panda/src/dxgsg9/dxIndexBufferContext9.cxx
  50. 8 4
      panda/src/egg2pg/eggSaver.cxx
  51. 2 37
      panda/src/express/multifile.cxx
  52. 5 2
      panda/src/express/multifile.h
  53. 12 7
      panda/src/glstuff/glCgShaderContext_src.cxx
  54. 19 26
      panda/src/glstuff/glGraphicsBuffer_src.cxx
  55. 28 1
      panda/src/glstuff/glGraphicsStateGuardian_src.I
  56. 310 216
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  57. 6 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  58. 43 19
      panda/src/gobj/geom.I
  59. 35 33
      panda/src/gobj/geom.cxx
  60. 4 2
      panda/src/gobj/geom.h
  61. 2 2
      panda/src/gobj/geomCacheEntry.cxx
  62. 60 36
      panda/src/gobj/geomPrimitive.I
  63. 16 13
      panda/src/gobj/geomPrimitive.cxx
  64. 9 6
      panda/src/gobj/geomPrimitive.h
  65. 67 18
      panda/src/gobj/geomVertexArrayData.I
  66. 15 8
      panda/src/gobj/geomVertexArrayData.h
  67. 59 41
      panda/src/gobj/geomVertexData.I
  68. 20 37
      panda/src/gobj/geomVertexData.cxx
  69. 9 10
      panda/src/gobj/geomVertexData.h
  70. 1 1
      panda/src/gobj/geomVertexWriter.cxx
  71. 1 1
      panda/src/gobj/geomVertexWriter.h
  72. 11 20
      panda/src/gobj/vertexDataBuffer.cxx
  73. 2 2
      panda/src/gobj/vertexDataBuffer.h
  74. 33 28
      panda/src/grutil/meshDrawer.cxx
  75. 1 1
      panda/src/grutil/shaderTerrainMesh.cxx
  76. 1 1
      panda/src/linmath/lsimpleMatrix.h
  77. 3 1
      panda/src/parametrics/hermiteCurve.h
  78. 1 1
      panda/src/pgraph/cullTraverserData.cxx
  79. 20 5
      panda/src/pgraph/cullableObject.I
  80. 7 5
      panda/src/pgraph/cullableObject.h
  81. 2 2
      panda/src/pgraph/geomNode.cxx
  82. 5 7
      panda/src/pgraph/geomTransformer.cxx
  83. 2 4
      panda/src/pgraph/pandaNode.h
  84. 4 4
      panda/src/pgraph/workingNodePath.I
  85. 4 4
      panda/src/pgraphnodes/shaderGenerator.h
  86. 9 0
      panda/src/pipeline/thread.I
  87. 18 6
      panda/src/putil/copyOnWritePointer.I
  88. 1 3
      panda/src/putil/copyOnWritePointer.cxx
  89. 4 4
      panda/src/putil/copyOnWritePointer.h
  90. 4 4
      panda/src/text/textAssembler.cxx
  91. 2 4
      panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx
  92. 2 4
      panda/src/tinydisplay/tinyTextureContext.cxx
  93. 6 6
      samples/chessboard/main.py

+ 2 - 2
dtool/src/dtoolbase/deletedChain.h

@@ -77,7 +77,7 @@ public:
 // Place this macro within a class definition to define appropriate operator
 // new and delete methods that take advantage of DeletedChain.
 #define ALLOC_DELETED_CHAIN(Type)                            \
-  inline void *operator new(size_t size) {                   \
+  inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
     return (void *)StaticDeletedChain< Type >::allocate(size, get_type_handle(Type)); \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \
@@ -96,7 +96,7 @@ public:
 // Use this variant of the above macro in cases in which the compiler fails to
 // unify the static template pointers properly, to prevent leaks.
 #define ALLOC_DELETED_CHAIN_DECL(Type)                       \
-  inline void *operator new(size_t size) {                   \
+  inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
     return (void *)_deleted_chain.allocate(size, get_type_handle(Type)); \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \

+ 39 - 0
dtool/src/dtoolbase/dtoolbase.h

@@ -76,6 +76,10 @@
 #define __has_builtin(x) 0
 #endif
 
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
 // Use NODEFAULT to optimize a switch() stmt to tell MSVC to automatically go
 // to the final untested case after it has failed all the other cases (i.e.
 // 'assume at least one of the cases is always true')
@@ -96,6 +100,12 @@
 #define ASSUME_ALIGNED(x, y) (x)
 #endif
 
+#if __has_attribute(assume_aligned) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
+#define RETURNS_ALIGNED(x) __attribute__((assume_aligned(x)))
+#else
+#define RETURNS_ALIGNED(x)
+#endif
+
 /*
   include win32 defns for everything up to WinServer2003, and assume
   I'm smart enough to use GetProcAddress for backward compat on
@@ -400,6 +410,35 @@ typedef struct _object PyObject;
 
 #endif
 
+#ifdef LINMATH_ALIGN
+/* We require 16-byte alignment of certain structures, to support SSE2.  We
+   don't strictly have to align everything, but it's just easier to do so. */
+#if defined(HAVE_EIGEN) && defined(__AVX__) && defined(STDFLOAT_DOUBLE)
+/* Eigen uses AVX instructions, but let's only enable this when compiling with
+   double precision, so that we can keep our ABI a bit more stable. */
+#define MEMORY_HOOK_ALIGNMENT 32
+#else
+#define MEMORY_HOOK_ALIGNMENT 16
+#endif
+/* Otherwise, align to two words.  This seems to be pretty standard to the
+   point where some code may rely on this being the case. */
+#elif defined(IS_OSX) || NATIVE_WORDSIZE >= 64
+#define MEMORY_HOOK_ALIGNMENT 16
+#else
+#define MEMORY_HOOK_ALIGNMENT 8
+#endif
+
+#ifdef HAVE_EIGEN
+/* Make sure that Eigen doesn't assume alignment guarantees we don't offer. */
+#define EIGEN_MAX_ALIGN_BYTES MEMORY_HOOK_ALIGNMENT
+#ifndef EIGEN_MPL2_ONLY
+#define EIGEN_MPL2_ONLY 1
+#endif
+#if !defined(_DEBUG) && !defined(EIGEN_NO_DEBUG)
+#define EIGEN_NO_DEBUG 1
+#endif
+#endif
+
 /* Determine our memory-allocation requirements. */
 #if defined(USE_MEMORY_PTMALLOC2) || defined(USE_MEMORY_DLMALLOC) || defined(DO_MEMORY_USAGE) || defined(MEMORY_HOOK_DO_ALIGN)
 /* In this case we have some custom memory management requirements. */

+ 2 - 2
dtool/src/dtoolbase/memoryBase.h

@@ -26,7 +26,7 @@
 #ifndef USE_MEMORY_NOWRAPPERS
 
 #define ALLOC_MEMORY_BASE                                    \
-  inline void *operator new(size_t size) {                   \
+  inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
     return PANDA_MALLOC_SINGLE(size);                        \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \
@@ -38,7 +38,7 @@
   }                                                          \
   inline void operator delete(void *, void *) {              \
   }                                                          \
-  inline void *operator new[](size_t size) {                 \
+  inline void *operator new[](size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \
     return PANDA_MALLOC_ARRAY(size);                         \
   }                                                          \
   inline void *operator new[](size_t size, void *ptr) {      \

+ 12 - 67
dtool/src/dtoolbase/memoryHook.I

@@ -63,14 +63,24 @@ round_up_to_page_size(size_t size) const {
 
 /**
  * Given a pointer that was returned by a MemoryHook allocation, returns the
- * number of bytes that were allocated for it.  Returns 0 if not compiling
- * with DO_MEMORY_USAGE.
+ * number of bytes that were allocated for it.  This may be slightly larger
+ * than the number of bytes requested.
+ * The behavior of this function is undefined if the given pointer was not
+ * returned by the MemoryHook allocator or was already freed.
+ * May return 0 if not compiling with DO_MEMORY_USAGE.
+ *
+ * This is only defined publicly so TypeHandle can get at it; it really
+ * shouldn't be used outside of dtoolbase.
  */
 INLINE size_t MemoryHook::
 get_ptr_size(void *ptr) {
 #if defined(MEMORY_HOOK_DO_ALIGN)
   uintptr_t *root = (uintptr_t *)ptr;
   return (size_t)root[-2];
+#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  // If we are using dlmalloc, we know how it stores the size.
+  size_t *root = (size_t *)ptr;
+  return (root[-1] & ~0x7) - sizeof(size_t);
 #elif defined(DO_MEMORY_USAGE)
   size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
   return *root;
@@ -78,68 +88,3 @@ get_ptr_size(void *ptr) {
   return 0;
 #endif  // DO_MEMORY_USAGE
 }
-
-/**
- * Increments the amount of requested size as necessary to accommodate the
- * extra data we might piggyback on each allocated block.
- */
-INLINE size_t MemoryHook::
-inflate_size(size_t size) {
-#if defined(MEMORY_HOOK_DO_ALIGN)
-  // If we're aligning, we need to request the header size, plus extra bytes
-  // to give us wiggle room to adjust the pointer.
-  return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1;
-#elif defined(DO_MEMORY_USAGE)
-  // If we're not aligning, but we're tracking memory allocations, we just
-  // need the header size extra (this gives us a place to store the size of
-  // the allocated block).  However, we do need to make sure that any
-  // alignment guarantee is kept.
-  return size + MEMORY_HOOK_ALIGNMENT;
-#else
-  // If we're not doing any of that, we can just allocate the precise
-  // requested amount.
-  return size;
-#endif  // DO_MEMORY_USAGE
-}
-
-/**
- * Converts an allocated pointer to a pointer returnable to the application.
- * Stuffs size in the first n bytes of the allocated space.
- */
-INLINE void *MemoryHook::
-alloc_to_ptr(void *alloc, size_t size) {
-#if defined(MEMORY_HOOK_DO_ALIGN)
-  // Add room for two uintptr_t values.
-  uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2);
-  // Align this to the requested boundary.
-  root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
-  root[-2] = size;
-  root[-1] = (uintptr_t)alloc;  // Save the pointer we originally allocated.
-  return (void *)root;
-#elif defined(DO_MEMORY_USAGE)
-  size_t *root = (size_t *)alloc;
-  root[0] = size;
-  return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT);
-#else
-  return alloc;
-#endif  // DO_MEMORY_USAGE
-}
-
-/**
- * Converts an application pointer back to the original allocated pointer.
- * Extracts size from the first n bytes of the allocated space.
- */
-INLINE void *MemoryHook::
-ptr_to_alloc(void *ptr, size_t &size) {
-#if defined(MEMORY_HOOK_DO_ALIGN)
-  uintptr_t *root = (uintptr_t *)ptr;
-  size = root[-2];
-  return (void *)root[-1]; // Get the pointer we originally allocated.
-#elif defined(DO_MEMORY_USAGE)
-  size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
-  size = root[0];
-  return (void *)root;
-#else
-  return ptr;
-#endif  // DO_MEMORY_USAGE
-}

+ 105 - 5
dtool/src/dtoolbase/memoryHook.cxx

@@ -14,6 +14,7 @@
 #include "memoryHook.h"
 #include "deletedBufferChain.h"
 #include <stdlib.h>
+#include "typeRegistry.h"
 
 #ifdef WIN32
 
@@ -104,6 +105,83 @@ static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0,
 
 #endif  // USE_MEMORY_*
 
+/**
+ * Increments the amount of requested size as necessary to accommodate the
+ * extra data we might piggyback on each allocated block.
+ */
+INLINE static size_t
+inflate_size(size_t size) {
+#if defined(MEMORY_HOOK_DO_ALIGN)
+  // If we're aligning, we need to request the header size, plus extra bytes
+  // to give us wiggle room to adjust the pointer.
+  return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1;
+#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  // If we are can access the allocator's bookkeeping to figure out how many
+  // bytes were allocated, we don't need to add our own information.
+  return size;
+#elif defined(DO_MEMORY_USAGE)
+  // If we're not aligning, but we're tracking memory allocations, we just
+  // need the header size extra (this gives us a place to store the size of
+  // the allocated block).  However, we do need to make sure that any
+  // alignment guarantee is kept.
+  return size + MEMORY_HOOK_ALIGNMENT;
+#else
+  // If we're not doing any of that, we can just allocate the precise
+  // requested amount.
+  return size;
+#endif  // DO_MEMORY_USAGE
+}
+
+/**
+ * Converts an allocated pointer to a pointer returnable to the application.
+ * Stuffs size in the first n bytes of the allocated space.
+ */
+INLINE static void *
+alloc_to_ptr(void *alloc, size_t size) {
+#if defined(MEMORY_HOOK_DO_ALIGN)
+  // Add room for two uintptr_t values.
+  uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2);
+  // Align this to the requested boundary.
+  root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1));
+  root[-2] = size;
+  root[-1] = (uintptr_t)alloc;  // Save the pointer we originally allocated.
+  return (void *)root;
+#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  return alloc;
+#elif defined(DO_MEMORY_USAGE)
+  size_t *root = (size_t *)alloc;
+  root[0] = size;
+  return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT);
+#else
+  return alloc;
+#endif  // DO_MEMORY_USAGE
+}
+
+/**
+ * Converts an application pointer back to the original allocated pointer.
+ * Extracts size from the first n bytes of the allocated space, but only if
+ * DO_MEMORY_USAGE is defined.
+ */
+INLINE static void *
+ptr_to_alloc(void *ptr, size_t &size) {
+#if defined(MEMORY_HOOK_DO_ALIGN)
+  uintptr_t *root = (uintptr_t *)ptr;
+  size = root[-2];
+  return (void *)root[-1]; // Get the pointer we originally allocated.
+#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+#ifdef DO_MEMORY_USAGE
+  size = MemoryHook::get_ptr_size(ptr);
+#endif
+  return ptr;
+#elif defined(DO_MEMORY_USAGE)
+  size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
+  size = root[0];
+  return (void *)root;
+#else
+  return ptr;
+#endif  // DO_MEMORY_USAGE
+}
+
 /**
  *
  */
@@ -195,6 +273,11 @@ heap_alloc_single(size_t size) {
 #ifdef DO_MEMORY_USAGE
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // bytes on the heap.
+#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  // dlmalloc may slightly overallocate, however.
+  size = get_ptr_size(alloc);
+  inflated_size = size;
+#endif
   AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size);
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
@@ -204,8 +287,10 @@ heap_alloc_single(size_t size) {
 #endif  // DO_MEMORY_USAGE
 
   void *ptr = alloc_to_ptr(alloc, size);
+#ifdef _DEBUG
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
+#endif
   return ptr;
 }
 
@@ -265,6 +350,11 @@ heap_alloc_array(size_t size) {
 #ifdef DO_MEMORY_USAGE
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // bytes on the heap.
+#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  // dlmalloc may slightly overallocate, however.
+  size = get_ptr_size(alloc);
+  inflated_size = size;
+#endif
   AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size);
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
@@ -274,8 +364,10 @@ heap_alloc_array(size_t size) {
 #endif  // DO_MEMORY_USAGE
 
   void *ptr = alloc_to_ptr(alloc, size);
+#ifdef _DEBUG
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
+#endif
   return ptr;
 }
 
@@ -287,11 +379,6 @@ heap_realloc_array(void *ptr, size_t size) {
   size_t orig_size;
   void *alloc = ptr_to_alloc(ptr, orig_size);
 
-#ifdef DO_MEMORY_USAGE
-  assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
-  AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
-#endif  // DO_MEMORY_USAGE
-
   size_t inflated_size = inflate_size(size);
 
   void *alloc1 = alloc;
@@ -318,6 +405,16 @@ heap_realloc_array(void *ptr, size_t size) {
 #endif
   }
 
+#ifdef DO_MEMORY_USAGE
+#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2)
+  // dlmalloc may slightly overallocate, however.
+  size = get_ptr_size(alloc1);
+  inflated_size = size;
+#endif
+  assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size);
+  AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size);
+#endif  // DO_MEMORY_USAGE
+
   // Align this to the requested boundary.
 #ifdef MEMORY_HOOK_DO_ALIGN
   // This copies the code from alloc_to_ptr, since we can't write the size and
@@ -337,8 +434,11 @@ heap_realloc_array(void *ptr, size_t size) {
 #else
   void *ptr1 = alloc_to_ptr(alloc1, size);
 #endif
+
+#ifdef _DEBUG
   assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
   assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
+#endif
   return ptr1;
 }
 

+ 0 - 21
dtool/src/dtoolbase/memoryHook.h

@@ -20,22 +20,6 @@
 #include "mutexImpl.h"
 #include <map>
 
-#ifdef LINMATH_ALIGN
-// We require 16-byte alignment of certain structures, to support SSE2.  We
-// don't strictly have to align *everything*, but it's just easier to do so.
-#ifdef __AVX__
-#define MEMORY_HOOK_ALIGNMENT 32
-#else
-#define MEMORY_HOOK_ALIGNMENT 16
-#endif
-// Otherwise, align to two words.  This seems to be pretty standard to the
-// point where some code may rely on this being the case.
-#elif defined(IS_OSX) || NATIVE_WORDSIZE >= 64
-#define MEMORY_HOOK_ALIGNMENT 16
-#else
-#define MEMORY_HOOK_ALIGNMENT 8
-#endif
-
 class DeletedBufferChain;
 
 /**
@@ -83,11 +67,6 @@ public:
 
   INLINE static size_t get_ptr_size(void *ptr);
 
-private:
-  INLINE static size_t inflate_size(size_t size);
-  INLINE static void *alloc_to_ptr(void *alloc, size_t size);
-  INLINE static void *ptr_to_alloc(void *ptr, size_t &size);
-
 #ifdef DO_MEMORY_USAGE
 protected:
   TVOLATILE AtomicAdjust::Integer _total_heap_single_size;

+ 5 - 25
dtool/src/dtoolbase/pallocator.T

@@ -19,7 +19,7 @@ pallocator_single(TypeHandle type_handle) NOEXCEPT :
 }
 
 template<class Type>
-INLINE TYPENAME pallocator_single<Type>::pointer pallocator_single<Type>::
+INLINE Type *pallocator_single<Type>::
 allocate(TYPENAME pallocator_single<Type>::size_type n, TYPENAME allocator<void>::const_pointer) {
   TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
   // This doesn't support allocating arrays.
@@ -43,34 +43,14 @@ pallocator_array(TypeHandle type_handle) NOEXCEPT :
 }
 
 template<class Type>
-INLINE TYPENAME pallocator_array<Type>::pointer pallocator_array<Type>::
+INLINE Type *pallocator_array<Type>::
 allocate(TYPENAME pallocator_array<Type>::size_type n, TYPENAME allocator<void>::const_pointer) {
-  TAU_PROFILE("pallocator_array:allocate()", " ", TAU_USER);
-#ifdef DO_MEMORY_USAGE
-  size_t alloc_size = n * sizeof(Type);
-  void *ptr = (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC_ARRAY(alloc_size);
-#ifdef _DEBUG
-  assert(alloc_size == MemoryHook::get_ptr_size(ptr));
-#endif
-  _type_handle.inc_memory_usage(TypeHandle::MC_array, alloc_size);
-  return (TYPENAME pallocator_array<Type>::pointer)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT);
-#else
-  return (TYPENAME pallocator_array<Type>::pointer)PANDA_MALLOC_ARRAY(n * sizeof(Type));
-#endif  // DO_MEMORY_USAGE
+  return (TYPENAME pallocator_array<Type>::pointer)
+    ASSUME_ALIGNED(_type_handle.allocate_array(n * sizeof(Type)), MEMORY_HOOK_ALIGNMENT);
 }
 
 template<class Type>
 INLINE void pallocator_array<Type>::
 deallocate(TYPENAME pallocator_array<Type>::pointer p, TYPENAME pallocator_array<Type>::size_type) {
-  TAU_PROFILE("pallocator_array:deallocate()", " ", TAU_USER);
-#ifdef DO_MEMORY_USAGE
-  // Now we need to recover the total number of bytes.  Fortunately, in the
-  // case of DO_MEMORY_USAGE, MemoryHook already keeps track of this.
-  void *ptr = (void *)p;
-  size_t alloc_size = MemoryHook::get_ptr_size(ptr);
-  _type_handle.dec_memory_usage(TypeHandle::MC_array, alloc_size);
-  PANDA_FREE_ARRAY(ptr);
-#else
-  PANDA_FREE_ARRAY(p);
-#endif  // DO_MEMORY_USAGE
+  _type_handle.deallocate_array((void *)p);
 }

+ 4 - 2
dtool/src/dtoolbase/pallocator.h

@@ -59,7 +59,8 @@ public:
   INLINE pallocator_single(const pallocator_single<U> &copy) NOEXCEPT :
     _type_handle(copy._type_handle) { }
 
-  INLINE pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
+  INLINE Type *allocate(size_type n, allocator<void>::const_pointer hint = 0)
+    RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   INLINE void deallocate(pointer p, size_type n);
 
   template<class U> struct rebind {
@@ -87,7 +88,8 @@ public:
   INLINE pallocator_array(const pallocator_array<U> &copy) NOEXCEPT :
     _type_handle(copy._type_handle) { }
 
-  INLINE pointer allocate(size_type n, allocator<void>::const_pointer hint = 0);
+  INLINE Type *allocate(size_type n, allocator<void>::const_pointer hint = 0)
+    RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
   INLINE void deallocate(pointer p, size_type n);
 
   template<class U> struct rebind {

+ 80 - 6
dtool/src/dtoolbase/typeHandle.cxx

@@ -18,7 +18,6 @@
 // This is initialized to zero by static initialization.
 TypeHandle TypeHandle::_none;
 
-#ifdef DO_MEMORY_USAGE
 /**
  * Returns the total allocated memory used by objects of this type, for the
  * indicated memory class.  This is only updated if track-memory-usage is set
@@ -26,6 +25,7 @@ TypeHandle TypeHandle::_none;
  */
 size_t TypeHandle::
 get_memory_usage(MemoryClass memory_class) const {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) == TypeHandle::none()) {
     return 0;
@@ -34,16 +34,17 @@ get_memory_usage(MemoryClass memory_class) const {
     assert(rnode != (TypeRegistryNode *)NULL);
     return (size_t)AtomicAdjust::get(rnode->_memory_usage[memory_class]);
   }
-}
 #endif  // DO_MEMORY_USAGE
+  return 0;
+}
 
-#ifdef DO_MEMORY_USAGE
 /**
  * Adds the indicated amount to the record for the total allocated memory for
  * objects of this type.
  */
 void TypeHandle::
 inc_memory_usage(MemoryClass memory_class, size_t size) {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
@@ -52,20 +53,20 @@ inc_memory_usage(MemoryClass memory_class, size_t size) {
     // cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " <<
     // rnode->_memory_usage[memory_class] << "\n";
     if (rnode->_memory_usage[memory_class] < 0) {
-      cerr << "Memory usage overflow for type " << *this << ".\n";
+      cerr << "Memory usage overflow for type " << rnode->_name << ".\n";
       abort();
     }
   }
-}
 #endif  // DO_MEMORY_USAGE
+}
 
-#ifdef DO_MEMORY_USAGE
 /**
  * Subtracts the indicated amount from the record for the total allocated
  * memory for objects of this type.
  */
 void TypeHandle::
 dec_memory_usage(MemoryClass memory_class, size_t size) {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
@@ -75,8 +76,81 @@ dec_memory_usage(MemoryClass memory_class, size_t size) {
     // rnode->_memory_usage[memory_class] << "\n";
     assert(rnode->_memory_usage[memory_class] >= 0);
   }
+#endif  // DO_MEMORY_USAGE
 }
+
+/**
+ * Allocates memory, adding it to the total amount of memory allocated for
+ * this type.
+ */
+void *TypeHandle::
+allocate_array(size_t size) {
+  TAU_PROFILE("TypeHandle:allocate_array()", " ", TAU_USER);
+
+  void *ptr = PANDA_MALLOC_ARRAY(size);
+#ifdef DO_MEMORY_USAGE
+  if ((*this) != TypeHandle::none()) {
+    size_t alloc_size = MemoryHook::get_ptr_size(ptr);
+#ifdef _DEBUG
+    assert(size <= alloc_size);
+#endif
+    TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
+    assert(rnode != (TypeRegistryNode *)NULL);
+    AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)alloc_size);
+    if (rnode->_memory_usage[MC_array] < 0) {
+      cerr << "Memory usage overflow for type " << rnode->_name << ".\n";
+      abort();
+    }
+  }
 #endif  // DO_MEMORY_USAGE
+  return ptr;
+}
+
+/**
+ * Reallocates memory, adjusting the total amount of memory allocated for this
+ * type.
+ */
+void *TypeHandle::
+reallocate_array(void *old_ptr, size_t size) {
+  TAU_PROFILE("TypeHandle:reallocate_array()", " ", TAU_USER);
+
+#ifdef DO_MEMORY_USAGE
+  size_t old_size = MemoryHook::get_ptr_size(old_ptr);
+  void *new_ptr = PANDA_REALLOC_ARRAY(old_ptr, size);
+
+  if ((*this) != TypeHandle::none()) {
+    size_t new_size = MemoryHook::get_ptr_size(new_ptr);
+
+    TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
+    assert(rnode != (TypeRegistryNode *)NULL);
+    AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)new_size - (AtomicAdjust::Integer)old_size);
+    assert(rnode->_memory_usage[MC_array] >= 0);
+  }
+#else
+  void *new_ptr = PANDA_REALLOC_ARRAY(old_ptr, size);
+#endif
+  return new_ptr;
+}
+
+/**
+ * Deallocates memory, subtracting it from the total amount of memory
+ * allocated for this type.
+ */
+void TypeHandle::
+deallocate_array(void *ptr) {
+  TAU_PROFILE("TypeHandle:deallocate_array()", " ", TAU_USER);
+
+#ifdef DO_MEMORY_USAGE
+  size_t alloc_size = MemoryHook::get_ptr_size(ptr);
+  if ((*this) != TypeHandle::none()) {
+    TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
+    assert(rnode != (TypeRegistryNode *)NULL);
+    AtomicAdjust::add(rnode->_memory_usage[MC_array], -(AtomicAdjust::Integer)alloc_size);
+    assert(rnode->_memory_usage[MC_array] >= 0);
+  }
+#endif  // DO_MEMORY_USAGE
+  PANDA_FREE_ARRAY(ptr);
+}
 
 /**
  * Return the Index of the BEst fit Classs from a set

+ 47 - 25
dtool/src/dtoolbase/typeHandle.h

@@ -18,25 +18,49 @@
 
 #include <set>
 
-// The following illustrates the convention for declaring a type that uses
-// TypeHandle.  In this example, ThisThingie inherits from TypedObject, which
-// automatically supplies some type-differentiation functions at the cost of
-// one virtual function, get_type(); however, this inheritance is optional,
-// and may be omitted to avoid the virtual function pointer overhead.  (If you
-// do use TypedObject, be sure to consider whether your destructor should also
-// be virtual.)
-
-/*
- * class ThatThingie : public SimpleTypedObject { public: static TypeHandle
- * get_class_type() { return _type_handle; } static void init_type() {
- * register_type(_type_handle, "ThatThingie"); } private: static TypeHandle
- * _type_handle; }; class ThisThingie : public ThatThingie, publid TypedObject
- * { public: static TypeHandle get_class_type() { return _type_handle; }
- * static void init_type() { ThatThingie::init_type();
- * TypedObject::init_type(); register_type(_type_handle, "ThisThingie",
- * ThatThingie::get_class_type(), TypedObject::get_class_type()); } virtual
- * TypeHandle get_type() const { return get_class_type(); } private: static
- * TypeHandle _type_handle; };
+/**
+ * The following illustrates the convention for declaring a type that uses
+ * TypeHandle.  In this example, ThisThingie inherits from TypedObject, which
+ * automatically supplies some type-differentiation functions at the cost of
+ * one virtual function, get_type(); however, this inheritance is optional,
+ * and may be omitted to avoid the virtual function pointer overhead.  (If you
+ * do use TypedObject, be sure to consider whether your destructor should also
+ * be virtual.)
+ *
+ * @code
+ * class ThatThingie : public SimpleTypedObject {
+ * public:
+ *   static TypeHandle get_class_type() {
+ *     return _type_handle;
+ *   }
+ *   static void init_type() {
+ *     register_type(_type_handle, "ThatThingie");
+ *   }
+ *
+ * private:
+ *   static TypeHandle _type_handle;
+ * };
+ *
+ * class ThisThingie : public ThatThingie, publid TypedObject {
+ * public:
+ *   static TypeHandle get_class_type() {
+ *     return _type_handle;
+ *   }
+ *   static void init_type() {
+ *     ThatThingie::init_type();
+ *     TypedObject::init_type();
+ *     register_type(_type_handle, "ThisThingie",
+ *                  ThatThingie::get_class_type(),
+ *                  TypedObject::get_class_type());
+ *   }
+ *   virtual TypeHandle get_type() const {
+ *     return get_class_type();
+ *   }
+ *
+ * private:
+ *   static TypeHandle _type_handle;
+ * };
+ * @endcode
  */
 
 class TypedObject;
@@ -97,15 +121,9 @@ PUBLISHED:
 
   int get_best_parent_from_Set(const std::set< int > &legal_vals) const;
 
-#ifdef DO_MEMORY_USAGE
   size_t get_memory_usage(MemoryClass memory_class) const;
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void dec_memory_usage(MemoryClass memory_class, size_t size);
-#else
-  static CONSTEXPR size_t get_memory_usage(MemoryClass) { return 0; }
-  INLINE void inc_memory_usage(MemoryClass, size_t) { }
-  INLINE void dec_memory_usage(MemoryClass, size_t) { }
-#endif  // DO_MEMORY_USAGE
 
   INLINE int get_index() const;
   INLINE void output(ostream &out) const;
@@ -118,6 +136,10 @@ PUBLISHED:
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
 
 public:
+  void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
+  void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
+  void deallocate_array(void *ptr);
+
   INLINE static TypeHandle from_index(int index);
 
 private:

+ 13 - 0
dtool/src/dtoolbase/typeRegistry.I

@@ -23,6 +23,19 @@ freshen_derivations() {
   }
 }
 
+/**
+ * Returns the pointer to the global TypeRegistry object.
+ */
+INLINE TypeRegistry *TypeRegistry::
+ptr() {
+  // It's OK that we don't acquire the lock, because we guarantee that this is
+  // called at static init time.
+  if (_global_pointer == NULL) {
+    init_global_pointer();
+  }
+  return _global_pointer;
+}
+
 /**
  * Ensures the lock pointer has been allocated.
  */

+ 1 - 14
dtool/src/dtoolbase/typeRegistry.cxx

@@ -488,20 +488,6 @@ write(ostream &out) const {
   _lock->release();
 }
 
-/**
- * Returns the pointer to the global TypeRegistry object.
- */
-TypeRegistry *TypeRegistry::
-ptr() {
-  init_lock();
-  _lock->acquire();
-  if (_global_pointer == NULL) {
-    init_global_pointer();
-  }
-  _lock->release();
-  return _global_pointer;
-}
-
 /**
  *
  */
@@ -531,6 +517,7 @@ TypeRegistry() {
  */
 void TypeRegistry::
 init_global_pointer() {
+  init_lock();
   init_memory_hook();
   _global_pointer = new TypeRegistry;
 }

+ 1 - 1
dtool/src/dtoolbase/typeRegistry.h

@@ -77,7 +77,7 @@ PUBLISHED:
   void write(ostream &out) const;
 
   // ptr() returns the pointer to the global TypeRegistry object.
-  static TypeRegistry *ptr();
+  static INLINE TypeRegistry *ptr();
 
   MAKE_SEQ_PROPERTY(typehandles, get_num_typehandles, get_typehandle);
   MAKE_SEQ_PROPERTY(root_classes, get_num_root_classes, get_root_class);

+ 4 - 4
dtool/src/dtoolutil/executionEnvironment.cxx

@@ -591,8 +591,8 @@ read_args() {
     dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
 
     while (map != NULL) {
-      char *tail = strrchr(map->l_name, '/');
-      char *head = strchr(map->l_name, '/');
+      const char *tail = strrchr(map->l_name, '/');
+      const char *head = strchr(map->l_name, '/');
       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
         _dtool_name = head;
@@ -615,8 +615,8 @@ read_args() {
       char buffer[PATH_MAX];
       buffer[0] = 0;
       maps.getline(buffer, PATH_MAX);
-      char *tail = strrchr(buffer, '/');
-      char *head = strchr(buffer, '/');
+      const char *tail = strrchr(buffer, '/');
+      const char *head = strchr(buffer, '/');
       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
         _dtool_name = head;

+ 52 - 11
dtool/src/dtoolutil/globPattern.cxx

@@ -99,7 +99,7 @@ match_files(vector_string &results, const Filename &cwd) const {
     pattern = source;
   } else {
     pattern = source.substr(0, slash);
-    suffix = source.substr(slash + 1);
+    suffix = source.substr(slash);
   }
 
   GlobPattern glob(pattern);
@@ -118,11 +118,21 @@ r_match_files(const Filename &prefix, const string &suffix,
   size_t slash = suffix.find('/');
   if (slash == string::npos) {
     next_pattern = suffix;
+  } else if (slash + 1 == suffix.size()) {
+    // If the slash is at the end, we need to keep it, since it indicates that
+    // we only want to match directories.
+    next_pattern = suffix.substr(0, slash);
+    next_suffix = "/";
   } else {
     next_pattern = suffix.substr(0, slash);
     next_suffix = suffix.substr(slash + 1);
   }
 
+  if (_pattern == "**" && next_pattern == "**") {
+    // Collapse consecutive globstar patterns.
+    return r_match_files(prefix, next_suffix, results, cwd);
+  }
+
   Filename parent_dir;
   if (prefix.is_local() && !cwd.empty()) {
     parent_dir = Filename(cwd, prefix);
@@ -136,19 +146,24 @@ r_match_files(const Filename &prefix, const string &suffix,
   if (!has_glob_characters()) {
     // If there are no special characters in the pattern, it's a literal
     // match.
+    Filename fn(parent_dir, _pattern);
     if (suffix.empty()) {
       // Time to stop.
-      Filename single_filename(parent_dir, _pattern);
-      if (single_filename.exists()) {
+      if (fn.exists()) {
         results.push_back(Filename(prefix, _pattern));
         return 1;
       }
       return 0;
+    } else if (fn.is_directory()) {
+      // If the pattern ends with a slash, match a directory only.
+      if (suffix == "/") {
+        results.push_back(Filename(prefix, _pattern + "/"));
+        return 1;
+      } else {
+        return next_glob.r_match_files(Filename(prefix, _pattern),
+                                       next_suffix, results, cwd);
+      }
     }
-
-    return next_glob.r_match_files(Filename(prefix, _pattern),
-                                   next_suffix, results, cwd);
-
   }
 
   // If there *are* special glob characters, we must attempt to match the
@@ -164,18 +179,44 @@ r_match_files(const Filename &prefix, const string &suffix,
   // the pattern.
   int num_matched = 0;
 
+  // A globstar pattern matches zero or more directories.
+  if (_pattern == "**") {
+    // Try to match this directory (as if the globstar wasn't there)
+    if (suffix.empty()) {
+      // This is a directory.  Add it.
+      results.push_back(Filename(prefix));
+      num_matched++;
+    } else if (suffix == "/") {
+      // Keep the trailing slash, but be sure not to duplicate it.
+      results.push_back(Filename(prefix, ""));
+      num_matched++;
+    } else {
+      num_matched += next_glob.r_match_files(prefix, next_suffix, results, cwd);
+    }
+    next_suffix = suffix;
+    next_glob = *this;
+  }
+
   vector_string::const_iterator fi;
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
     const string &local_file = (*fi);
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
       if (matches(local_file)) {
         // We have a match; continue.
-        if (suffix.empty()) {
+        if (Filename(parent_dir, local_file).is_directory()) {
+          if (suffix.empty() && _pattern != "**") {
+            results.push_back(Filename(prefix, local_file));
+            num_matched++;
+          } else if (suffix == "/" && _pattern != "**") {
+            results.push_back(Filename(prefix, local_file + "/"));
+            num_matched++;
+          } else {
+            num_matched += next_glob.r_match_files(Filename(prefix, local_file),
+                                                   next_suffix, results, cwd);
+          }
+        } else if (suffix.empty()) {
           results.push_back(Filename(prefix, local_file));
           num_matched++;
-        } else {
-          num_matched += next_glob.r_match_files(Filename(prefix, local_file),
-                                                 next_suffix, results, cwd);
         }
       }
     }

+ 13 - 0
dtool/src/dtoolutil/pandaSystem.cxx

@@ -45,6 +45,11 @@ PandaSystem() :
 #else
   set_system_tag("eigen", "vectorize", "0");
 #endif
+#ifdef __AVX__
+  set_system_tag("eigen", "avx", "1");
+#else
+  set_system_tag("eigen", "avx", "0");
+#endif
 #endif  // HAVE_EIGEN
 
 #ifdef USE_MEMORY_DLMALLOC
@@ -189,6 +194,14 @@ is_official_version() {
 #endif
 }
 
+/**
+ * Returns the memory alignment that Panda's allocators are using.
+ */
+int PandaSystem::
+get_memory_alignment() {
+  return MEMORY_HOOK_ALIGNMENT;
+}
+
 /**
  * Returns the string defined by the distributor of this version of Panda, or
  * "homebuilt" if this version was built directly from the sources by the end-

+ 2 - 0
dtool/src/dtoolutil/pandaSystem.h

@@ -39,6 +39,8 @@ PUBLISHED:
   static int get_sequence_version();
   static bool is_official_version();
 
+  static int get_memory_alignment();
+
   static string get_distributor();
   static string get_compiler();
   static string get_build_date();

+ 1 - 1
dtool/src/interrogate/interfaceMakerPythonNative.cxx

@@ -6219,7 +6219,7 @@ write_make_seq(ostream &out, Object *obj, const std::string &ClassName,
     // the assumption that the called method doesn't do anything with this
     // tuple other than unpack it (which is a fairly safe assumption to make).
     out << "  PyTupleObject args;\n";
-    out << "  (void)PyObject_INIT_VAR(&args, &PyTuple_Type, 1);\n";
+    out << "  (void)PyObject_INIT_VAR((PyVarObject *)&args, &PyTuple_Type, 1);\n";
   }
 
   out <<

+ 7 - 1
dtool/src/interrogatedb/py_panda.h

@@ -303,8 +303,14 @@ template<class T> INLINE bool DTOOL_Call_ExtractThisPointer(PyObject *self, T *&
 // Functions related to error reporting.
 EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
 
+// _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred.
+// Some implementations of the CPython API (e.g. PyPy's cpyext) do not define
+// it, so in these cases we just silently fall back to PyErr_Occurred.
+#ifndef _PyErr_OCCURRED
+#define _PyErr_OCCURRED() PyErr_Occurred()
+#endif
+
 #ifdef NDEBUG
-// _PyErr_OCCURRED is an undocumented inline version of PyErr_Occurred.
 #define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL)
 #else
 #define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred()

+ 1 - 2
dtool/src/parser-inc/openssl/evp.h

@@ -2,7 +2,6 @@
 #ifndef EVP_H
 #define EVP_H
 
-struct EVP_CIPHER_CTX;
-struct EVP_PKEY;
+#include <openssl/ssl.h>
 
 #endif

+ 8 - 7
dtool/src/parser-inc/openssl/ssl.h

@@ -2,13 +2,14 @@
 #ifndef SSL_H
 #define SSL_H
 
-struct BIO;
-struct SSL_CTX;
-struct EVP_CIPHER_CTX;
-struct EVP_PKEY;
-struct X509;
-struct X509_STORE;
-struct X509_NAME;
+typedef struct bio_st BIO;
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
+typedef struct evp_pkey_st EVP_PKEY;
+typedef struct x509_st X509;
+typedef struct x509_store_st X509_STORE;
+typedef struct X509_name_st X509_NAME;
+typedef struct ssl_cipher_st SSL_CIPHER;
 struct SSL;
 #define STACK_OF(type) struct stack_st_##type
 

+ 1 - 3
dtool/src/parser-inc/openssl/x509.h

@@ -2,9 +2,7 @@
 #ifndef X509_H
 #define X509_H
 
-struct X509;
-struct X509_STORE;
-struct X509_NAME;
+#include <openssl/ssl.h>
 
 #endif
 

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

@@ -21,6 +21,7 @@
 #ifdef HAVE_OPENSSL
 
 #include "openssl/rand.h"
+#include "openssl/evp.h"
 
 #ifndef HAVE_STREAMSIZE
 // Some compilers (notably SGI) don't define this for us

+ 1 - 1
dtool/src/prc/encryptStreamBuf.h

@@ -19,7 +19,7 @@
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 
-#include "openssl/evp.h"
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
 
 /**
  * The streambuf object that implements IDecompressStream and OCompressStream.

+ 4 - 0
dtool/src/prc/prcKeyRegistry.cxx

@@ -19,8 +19,12 @@
 
 #ifdef HAVE_OPENSSL
 
+#include "openssl/evp.h"
 #include "openssl/pem.h"
 
+// Some versions of OpenSSL appear to define this as a macro.  Yucky.
+#undef set_key
+
 PrcKeyRegistry *PrcKeyRegistry::_global_ptr = NULL;
 
 /**

+ 1 - 3
dtool/src/prc/prcKeyRegistry.h

@@ -22,10 +22,8 @@
 #ifdef HAVE_OPENSSL
 
 #include <vector>
-#include "openssl/evp.h"
 
-// Some versions of OpenSSL appear to define this as a macro.  Yucky.
-#undef set_key
+typedef struct evp_pkey_st EVP_PKEY;
 
 /**
  * This class records the set of public keys used to verify the signature on a

+ 1 - 3
makepanda/makepanda.py

@@ -973,9 +973,7 @@ if GetTarget() == 'android':
     DefSymbol("ALWAYS", "ANDROID")
 
 if not PkgSkip("EIGEN"):
-    DefSymbol("ALWAYS", "EIGEN_MPL2_ONLY")
     if GetOptimize() >= 3:
-        DefSymbol("ALWAYS", "EIGEN_NO_DEBUG")
         if COMPILER == "MSVC":
             # Squeeze out a bit more performance on MSVC builds...
             # Only do this if EIGEN_NO_DEBUG is also set, otherwise it
@@ -1292,7 +1290,7 @@ def CompileCxx(obj,src,opts):
         cmd += " -fno-strict-aliasing"
 
         if optlevel >= 3:
-            cmd += " -ffast-math"
+            cmd += " -ffast-math -fno-stack-protector"
         if optlevel == 3:
             # Fast math is nice, but we'd like to see NaN in dev builds.
             cmd += " -fno-finite-math-only"

+ 18 - 1
panda/src/cull/cullBinBackToFront.cxx

@@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
 void CullBinBackToFront::
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
-    CullHandler::draw(object, _gsg, force, current_thread);
+
+    if (object->_draw_callback == nullptr) {
+      nassertd(object->_geom != nullptr) continue;
+
+      _gsg->set_state_and_transform(object->_state, object->_internal_transform);
+      data_reader.set_object(object->_munged_data);
+      data_reader.check_array_readers();
+      geom_reader.set_object(object->_geom);
+      geom_reader.draw(_gsg, object->_munger, &data_reader, force);
+    } else {
+      // It has a callback associated.
+      object->draw_callback(_gsg, force, current_thread);
+      // Now the callback has taken care of drawing.
+    }
   }
 }
 

+ 18 - 1
panda/src/cull/cullBinFixed.cxx

@@ -70,10 +70,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
 void CullBinFixed::
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
-    CullHandler::draw(object, _gsg, force, current_thread);
+
+    if (object->_draw_callback == nullptr) {
+      nassertd(object->_geom != nullptr) continue;
+
+      _gsg->set_state_and_transform(object->_state, object->_internal_transform);
+      data_reader.set_object(object->_munged_data);
+      data_reader.check_array_readers();
+      geom_reader.set_object(object->_geom);
+      geom_reader.draw(_gsg, object->_munger, &data_reader, force);
+    } else {
+      // It has a callback associated.
+      object->draw_callback(_gsg, force, current_thread);
+      // Now the callback has taken care of drawing.
+    }
   }
 }
 

+ 18 - 1
panda/src/cull/cullBinFrontToBack.cxx

@@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
 void CullBinFrontToBack::
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
-    CullHandler::draw(object, _gsg, force, current_thread);
+
+    if (object->_draw_callback == nullptr) {
+      nassertd(object->_geom != nullptr) continue;
+
+      _gsg->set_state_and_transform(object->_state, object->_internal_transform);
+      data_reader.set_object(object->_munged_data);
+      data_reader.check_array_readers();
+      geom_reader.set_object(object->_geom);
+      geom_reader.draw(_gsg, object->_munger, &data_reader, force);
+    } else {
+      // It has a callback associated.
+      object->draw_callback(_gsg, force, current_thread);
+      // Now the callback has taken care of drawing.
+    }
   }
 }
 

+ 18 - 1
panda/src/cull/cullBinStateSorted.cxx

@@ -69,10 +69,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
 void CullBinStateSorted::
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
-    CullHandler::draw(object, _gsg, force, current_thread);
+
+    if (object->_draw_callback == nullptr) {
+      nassertd(object->_geom != nullptr) continue;
+
+      _gsg->set_state_and_transform(object->_state, object->_internal_transform);
+      data_reader.set_object(object->_munged_data);
+      data_reader.check_array_readers();
+      geom_reader.set_object(object->_geom);
+      geom_reader.draw(_gsg, object->_munger, &data_reader, force);
+    } else {
+      // It has a callback associated.
+      object->draw_callback(_gsg, force, current_thread);
+      // Now the callback has taken care of drawing.
+    }
   }
 }
 

+ 18 - 1
panda/src/cull/cullBinUnsorted.cxx

@@ -54,10 +54,27 @@ add_object(CullableObject *object, Thread *current_thread) {
 void CullBinUnsorted::
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi);
-    CullHandler::draw(object, _gsg, force, current_thread);
+
+    if (object->_draw_callback == nullptr) {
+      nassertd(object->_geom != nullptr) continue;
+
+      _gsg->set_state_and_transform(object->_state, object->_internal_transform);
+      data_reader.set_object(object->_munged_data);
+      data_reader.check_array_readers();
+      geom_reader.set_object(object->_geom);
+      geom_reader.draw(_gsg, object->_munger, &data_reader, force);
+    } else {
+      // It has a callback associated.
+      object->draw_callback(_gsg, force, current_thread);
+      // Now the callback has taken care of drawing.
+    }
   }
 }
 

+ 6 - 0
panda/src/display/displayRegion.cxx

@@ -491,6 +491,12 @@ get_screenshot() {
     return NULL;
   }
 
+  {
+    // Make sure that the correct viewport is active.
+    DisplayRegionPipelineReader dr_reader(this, current_thread);
+    gsg->prepare_display_region(&dr_reader);
+  }
+
   PT(Texture) tex = new Texture;
 
   RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(),

+ 67 - 95
panda/src/display/graphicsEngine.cxx

@@ -1328,21 +1328,24 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
   GraphicsStateGuardian *gsg = win->get_gsg();
   nassertv(gsg != (GraphicsStateGuardian *)NULL);
 
-  DisplayRegionPipelineReader *dr_reader =
-    new DisplayRegionPipelineReader(dr, current_thread);
+  PT(SceneSetup) scene_setup;
+
+  {
+    DisplayRegionPipelineReader dr_reader(dr, current_thread);
+    win->change_scenes(&dr_reader);
+    gsg->prepare_display_region(&dr_reader);
 
-  win->change_scenes(dr_reader);
-  gsg->prepare_display_region(dr_reader);
+    if (dr_reader.is_any_clear_active()) {
+      gsg->clear(dr);
+    }
 
-  if (dr_reader->is_any_clear_active()) {
-    gsg->clear(dr);
+    scene_setup = setup_scene(gsg, &dr_reader);
   }
 
-  PT(SceneSetup) scene_setup = setup_scene(gsg, dr_reader);
   if (scene_setup == (SceneSetup *)NULL) {
     // Never mind.
 
-  } else if (dr_reader->get_object()->is_stereo()) {
+  } else if (dr->is_stereo()) {
     // Don't draw stereo DisplayRegions directly.
 
   } else if (!gsg->set_scene(scene_setup)) {
@@ -1353,9 +1356,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
   } else {
     DrawCullHandler cull_handler(gsg);
     if (gsg->begin_scene()) {
-      delete dr_reader;
-      dr_reader = NULL;
-
       CallbackObject *cbobj = dr->get_cull_callback();
       if (cbobj != (CallbackObject *)NULL) {
         // Issue the cull callback on this DisplayRegion.
@@ -1372,10 +1372,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
       gsg->end_scene();
     }
   }
-
-  if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
-    delete dr_reader;
-  }
 }
 
 /**
@@ -1399,27 +1395,41 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   for (size_t wi = 0; wi < wlist_size; ++wi) {
     GraphicsOutput *win = wlist[wi];
     if (win->is_active() && win->get_gsg()->is_active()) {
+      GraphicsStateGuardian *gsg = win->get_gsg();
       PStatTimer timer(win->get_cull_window_pcollector(), current_thread);
       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) {
-          DisplayRegionPipelineReader *dr_reader =
-            new DisplayRegionPipelineReader(dr, current_thread);
-
+        if (dr != nullptr) {
+          PT(SceneSetup) scene_setup;
+          PT(CullResult) cull_result;
           CullKey key;
-          key._gsg = win->get_gsg();
-          key._camera = dr_reader->get_camera();
-          key._lens_index = dr_reader->get_lens_index();
+          {
+            PStatTimer timer(_cull_setup_pcollector, current_thread);
+            DisplayRegionPipelineReader dr_reader(dr, current_thread);
+            scene_setup = setup_scene(gsg, &dr_reader);
+            if (scene_setup == nullptr) {
+              continue;
+            }
+
+            key._gsg = gsg;
+            key._camera = dr_reader.get_camera();
+            key._lens_index = dr_reader.get_lens_index();
+          }
 
-          AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(key, (DisplayRegion *)NULL)).first;
-          if ((*aci).second == NULL) {
+          AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(move(key), nullptr)).first;
+          if ((*aci).second == nullptr) {
             // We have not used this camera already in this thread.  Perform
             // the cull operation.
-            delete dr_reader;
-            dr_reader = NULL;
+            cull_result = dr->get_cull_result(current_thread);
+            if (cull_result != nullptr) {
+              cull_result = cull_result->make_next();
+            } else {
+              // This DisplayRegion has no cull results; draw it.
+              cull_result = new CullResult(gsg, dr->get_draw_region_pcollector());
+            }
             (*aci).second = dr;
-            cull_to_bins(win, dr, current_thread);
+            cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread);
 
           } else {
             // We have already culled a scene using this camera in this
@@ -1429,14 +1439,11 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
             // image.)  Of course, the cull result will be the same, so just
             // use the result from the other DisplayRegion.
             DisplayRegion *other_dr = (*aci).second;
-            dr->set_cull_result(other_dr->get_cull_result(current_thread),
-                                setup_scene(win->get_gsg(), dr_reader),
-                                current_thread);
+            cull_result = other_dr->get_cull_result(current_thread);
           }
 
-          if (dr_reader != (DisplayRegionPipelineReader *)NULL) {
-            delete dr_reader;
-          }
+          // Save the results for next frame.
+          dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread);
         }
       }
     }
@@ -1447,50 +1454,26 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
  * Called only within the inner loop of cull_to_bins(), above.
  */
 void GraphicsEngine::
-cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
-  GraphicsStateGuardian *gsg = win->get_gsg();
-  if (gsg == (GraphicsStateGuardian *)NULL) {
-    return;
-  }
-
-  PT(CullResult) cull_result;
-  PT(SceneSetup) scene_setup;
-  {
-    PStatTimer timer(_cull_setup_pcollector, current_thread);
-    DisplayRegionPipelineReader dr_reader(dr, current_thread);
-    scene_setup = setup_scene(gsg, &dr_reader);
-    cull_result = dr->get_cull_result(current_thread);
-
-    if (cull_result != (CullResult *)NULL) {
-      cull_result = cull_result->make_next();
+cull_to_bins(GraphicsOutput *win, GraphicsStateGuardian *gsg,
+             DisplayRegion *dr, SceneSetup *scene_setup,
+             CullResult *cull_result, Thread *current_thread) {
 
-    } else {
-      // This DisplayRegion has no cull results; draw it.
-      cull_result = new CullResult(gsg, dr->get_draw_region_pcollector());
-    }
-  }
-
-  if (scene_setup != (SceneSetup *)NULL) {
-    BinCullHandler cull_handler(cull_result);
-    CallbackObject *cbobj = dr->get_cull_callback();
-    if (cbobj != (CallbackObject *)NULL) {
-      // Issue the cull callback on this DisplayRegion.
-      DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
-      cbobj->do_callback(&cbdata);
+  BinCullHandler cull_handler(cull_result);
+  CallbackObject *cbobj = dr->get_cull_callback();
+  if (cbobj != (CallbackObject *)NULL) {
+    // Issue the cull callback on this DisplayRegion.
+    DisplayRegionCullCallbackData cbdata(&cull_handler, scene_setup);
+    cbobj->do_callback(&cbdata);
 
-      // The callback has taken care of the culling.
+    // The callback has taken care of the culling.
 
-    } else {
-      // Perform the cull normally.
-      dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
-    }
-
-    PStatTimer timer(_cull_sort_pcollector, current_thread);
-    cull_result->finish_cull(scene_setup, current_thread);
+  } else {
+    // Perform the cull normally.
+    dr->do_cull(&cull_handler, scene_setup, gsg, current_thread);
   }
 
-  // Save the results for next frame.
-  dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread);
+  PStatTimer timer(_cull_sort_pcollector, current_thread);
+  cull_result->finish_cull(scene_setup, current_thread);
 }
 
 /**
@@ -1538,7 +1521,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
           for (int i = 0; i < num_display_regions; ++i) {
             DisplayRegion *dr = win->get_active_display_region(i);
             if (dr != (DisplayRegion *)NULL) {
-              draw_bins(win, dr, current_thread);
+              do_draw(win, gsg, dr, current_thread);
             }
           }
         }
@@ -1582,22 +1565,6 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
   }
 }
 
-/**
- * This variant on draw_bins() is only called from draw_bins(), above.  It
- * draws the cull result for a particular DisplayRegion.
- */
-void GraphicsEngine::
-draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
-  GraphicsStateGuardian *gsg = win->get_gsg();
-  if (gsg == (GraphicsStateGuardian *)NULL) {
-    return;
-  }
-
-  PT(CullResult) cull_result = dr->get_cull_result(current_thread);
-  PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread);
-  do_draw(cull_result, scene_setup, win, dr, current_thread);
-}
-
 /**
  * Called in the draw thread, this calls make_context() on each window on the
  * list to guarantee its gsg and graphics context both get created.
@@ -1899,15 +1866,20 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) {
  * Draws the previously-culled scene.
  */
 void GraphicsEngine::
-do_draw(CullResult *cull_result, SceneSetup *scene_setup,
-        GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) {
-
-  CallbackObject *cbobj;
-  GraphicsStateGuardian *gsg = win->get_gsg();
-
+do_draw(GraphicsOutput *win, GraphicsStateGuardian *gsg, DisplayRegion *dr, Thread *current_thread) {
   // Statistics
   PStatGPUTimer timer(gsg, dr->get_draw_region_pcollector(), current_thread);
 
+  PT(CullResult) cull_result;
+  PT(SceneSetup) scene_setup;
+  {
+    DisplayRegion::CDCullReader cdata(dr->_cycler_cull, current_thread);
+    cull_result = cdata->_cull_result;
+    scene_setup = cdata->_scene_setup;
+  }
+
+  CallbackObject *cbobj;
+
   {
     DisplayRegionPipelineReader dr_reader(dr, current_thread);
     win->change_scenes(&dr_reader);

+ 5 - 4
panda/src/display/graphicsEngine.h

@@ -147,9 +147,10 @@ private:
                               Thread *current_thread);
 
   void cull_to_bins(const Windows &wlist, Thread *current_thread);
-  void cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread);
+  void cull_to_bins(GraphicsOutput *win, GraphicsStateGuardian *gsg,
+                    DisplayRegion *dr, SceneSetup *scene_setup,
+                    CullResult *cull_result, Thread *current_thread);
   void draw_bins(const Windows &wlist, Thread *current_thread);
-  void draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread);
   void make_contexts(const Windows &wlist, Thread *current_thread);
 
   void process_events(const Windows &wlist, Thread *current_thread);
@@ -162,8 +163,8 @@ private:
 
   PT(SceneSetup) setup_scene(GraphicsStateGuardian *gsg,
                              DisplayRegionPipelineReader *dr);
-  void do_draw(CullResult *cull_result, SceneSetup *scene_setup,
-               GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread);
+  void do_draw(GraphicsOutput *win, GraphicsStateGuardian *gsg,
+               DisplayRegion *dr, Thread *current_thread);
 
   void do_add_window(GraphicsOutput *window,
                      const GraphicsThreadingModel &threading_model);

+ 1 - 4
panda/src/display/graphicsPipe.cxx

@@ -23,11 +23,8 @@
 #include <unistd.h>
 #endif
 
-#ifdef IS_OSX
+#if defined(IS_OSX) || defined(IS_FREEBSD)
 #include <sys/sysctl.h>
-#endif
-
-#ifdef IS_FREEBSD
 #include <unistd.h>
 #endif
 

+ 8 - 0
panda/src/display/graphicsStateGuardian.I

@@ -538,6 +538,14 @@ get_supports_depth_stencil() const {
   return _supports_depth_stencil;
 }
 
+/**
+ * Returns true if this particular GSG supports luminance textures.
+ */
+INLINE bool GraphicsStateGuardian::
+get_supports_luminance_texture() const {
+  return _supports_luminance_texture;
+}
+
 /**
  * Returns true if this particular GSG supports the filter mode FT_shadow for
  * depth textures.

+ 3 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -253,6 +253,9 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_geometry_instancing = false;
   _supports_indirect_draw = false;
 
+  // We are safe assuming it has luminance support
+  _supports_luminance_texture = true;
+
   // Assume a maximum of 1 render target in absence of MRT.
   _max_color_targets = 1;
   _supports_dual_source_blending = false;

+ 3 - 0
panda/src/display/graphicsStateGuardian.h

@@ -154,6 +154,7 @@ PUBLISHED:
   INLINE bool get_supports_generate_mipmap() const;
   INLINE bool get_supports_depth_texture() const;
   INLINE bool get_supports_depth_stencil() const;
+  INLINE bool get_supports_luminance_texture() const;
   INLINE bool get_supports_shadow_filter() const;
   INLINE bool get_supports_sampler_objects() const;
   INLINE bool get_supports_basic_shaders() const;
@@ -203,6 +204,7 @@ PUBLISHED:
   MAKE_PROPERTY(supports_generate_mipmap, get_supports_generate_mipmap);
   MAKE_PROPERTY(supports_depth_texture, get_supports_depth_texture);
   MAKE_PROPERTY(supports_depth_stencil, get_supports_depth_stencil);
+  MAKE_PROPERTY(supports_luminance_texture, get_supports_luminance_texture);
   MAKE_PROPERTY(supports_shadow_filter, get_supports_shadow_filter);
   MAKE_PROPERTY(supports_sampler_objects, get_supports_sampler_objects);
   MAKE_PROPERTY(supports_basic_shaders, get_supports_basic_shaders);
@@ -597,6 +599,7 @@ protected:
   bool _supports_generate_mipmap;
   bool _supports_depth_texture;
   bool _supports_depth_stencil;
+  bool _supports_luminance_texture;
   bool _supports_shadow_filter;
   bool _supports_sampler_objects;
   bool _supports_basic_shaders;

+ 0 - 8
panda/src/downloader/bioPtr.I

@@ -18,14 +18,6 @@ INLINE BioPtr::
 BioPtr(BIO *bio) : _bio(bio) {
 }
 
-/**
- *
- */
-INLINE bool BioPtr::
-should_retry() const {
-  return (_bio != NULL) && BIO_should_retry(_bio);
-}
-
 /**
  *
  */

+ 12 - 1
panda/src/downloader/bioPtr.cxx

@@ -18,6 +18,9 @@
 #include "urlSpec.h"
 #include "config_downloader.h"
 
+#include "openSSLWrapper.h"  // must be included before any other openssl.
+#include "openssl/ssl.h"
+
 #ifdef _WIN32
 #include <winsock2.h>
 #else
@@ -199,7 +202,7 @@ connect() {
 
     if (result != 0 && BIO_sock_should_retry(-1)) {
       // It's still in progress; we should retry later.  This causes
-      // should_reply() to return true.
+      // should_retry() to return true.
       BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
       _connecting = true;
       return false;
@@ -218,6 +221,14 @@ connect() {
   return true;
 }
 
+/**
+ *
+ */
+bool BioPtr::
+should_retry() const {
+  return (_bio != NULL) && BIO_should_retry(_bio);
+}
+
 /**
  *
  */

+ 3 - 7
panda/src/downloader/bioPtr.h

@@ -19,13 +19,7 @@
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "referenceCount.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 
 #ifdef _WIN32
 #include <winsock2.h>
@@ -35,6 +29,8 @@
 #include <netinet/in.h>
 #endif
 
+typedef struct bio_st BIO;
+
 class URLSpec;
 
 /**
@@ -52,7 +48,7 @@ public:
   void set_nbio(bool nbio);
   bool connect();
 
-  INLINE bool should_retry() const;
+  bool should_retry() const;
 
   INLINE BIO &operator *() const;
   INLINE BIO *operator -> () const;

+ 0 - 6
panda/src/downloader/bioStreamBuf.h

@@ -19,14 +19,8 @@
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "bioPtr.h"
 #include "pointerTo.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 
 /**
  * The streambuf object that implements IBioStream.

+ 0 - 6
panda/src/downloader/bioStreamPtr.h

@@ -19,14 +19,8 @@
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "bioStream.h"
 #include "referenceCount.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 
 /**
  * A wrapper around an BioStream object to make a reference-counting pointer

+ 2 - 0
panda/src/downloader/httpChannel.cxx

@@ -27,6 +27,8 @@
 
 #ifdef HAVE_OPENSSL
 
+#include "openSSLWrapper.h"
+
 #if defined(WIN32_VC) || defined(WIN64_VC)
   #include <WinSock2.h>
   #include <windows.h>  // for select()

+ 2 - 6
panda/src/downloader/httpChannel.h

@@ -22,10 +22,6 @@
 
 #ifdef HAVE_OPENSSL
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "httpClient.h"
 #include "httpEnum.h"
 #include "urlSpec.h"
@@ -37,10 +33,10 @@
 #include "pointerTo.h"
 #include "config_downloader.h"
 #include "filename.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 #include "typedReferenceCount.h"
 
+typedef struct bio_st BIO;
+
 class Ramfile;
 class HTTPClient;
 

+ 64 - 62
panda/src/downloader/httpClient.cxx

@@ -24,6 +24,8 @@
 
 #ifdef HAVE_OPENSSL
 
+#include "openSSLWrapper.h"
+
 PT(HTTPClient) HTTPClient::_global_ptr;
 
 /**
@@ -68,6 +70,68 @@ tokenize(const string &str, vector_string &words, const string &delimiters) {
   words.push_back(string());
 }
 
+#ifndef NDEBUG
+/**
+ * This method is attached as a callback for SSL messages only when debug
+ * output is enabled.
+ */
+static void
+ssl_msg_callback(int write_p, int version, int content_type,
+                 const void *, size_t len, SSL *, void *) {
+  ostringstream describe;
+  if (write_p) {
+    describe << "sent ";
+  } else {
+    describe << "received ";
+  }
+  switch (version) {
+  case SSL2_VERSION:
+    describe << "SSL 2.0 ";
+    break;
+
+  case SSL3_VERSION:
+    describe << "SSL 3.0 ";
+    break;
+
+  case TLS1_VERSION:
+    describe << "TLS 1.0 ";
+    break;
+
+  default:
+    describe << "unknown protocol ";
+  }
+
+  describe << "message: ";
+
+  if (version != SSL2_VERSION) {
+    switch (content_type) {
+    case 20:
+      describe << "change cipher spec, ";
+      break;
+
+    case 21:
+      describe << "alert, ";
+      break;
+
+    case 22:
+      describe << "handshake, ";
+      break;
+
+    case 23:
+      describe << "application data, ";
+      break;
+
+    default:
+      describe << "unknown content type, ";
+    }
+  }
+
+  describe << len << " bytes.\n";
+
+  downloader_cat.debug() << describe.str();
+}
+#endif  // !defined(NDEBUG)
+
 /**
  *
  */
@@ -1564,68 +1628,6 @@ split_whitespace(string &a, string &b, const string &c) {
   b = c.substr(p);
 }
 
-#ifndef NDEBUG
-/**
- * This method is attached as a callback for SSL messages only when debug
- * output is enabled.
- */
-void HTTPClient::
-ssl_msg_callback(int write_p, int version, int content_type,
-                 const void *, size_t len, SSL *, void *) {
-  ostringstream describe;
-  if (write_p) {
-    describe << "sent ";
-  } else {
-    describe << "received ";
-  }
-  switch (version) {
-  case SSL2_VERSION:
-    describe << "SSL 2.0 ";
-    break;
-
-  case SSL3_VERSION:
-    describe << "SSL 3.0 ";
-    break;
-
-  case TLS1_VERSION:
-    describe << "TLS 1.0 ";
-    break;
-
-  default:
-    describe << "unknown protocol ";
-  }
-
-  describe << "message: ";
-
-  if (version != SSL2_VERSION) {
-    switch (content_type) {
-    case 20:
-      describe << "change cipher spec, ";
-      break;
-
-    case 21:
-      describe << "alert, ";
-      break;
-
-    case 22:
-      describe << "handshake, ";
-      break;
-
-    case 23:
-      describe << "application data, ";
-      break;
-
-    default:
-      describe << "unknown content type, ";
-    }
-  }
-
-  describe << len << " bytes.\n";
-
-  downloader_cat.debug() << describe.str();
-}
-#endif  // !defined(NDEBUG)
-
 /**
  *
  */

+ 5 - 7
panda/src/downloader/httpClient.h

@@ -32,7 +32,11 @@
 #include "pmap.h"
 #include "pset.h"
 #include "referenceCount.h"
-#include "openSSLWrapper.h"
+
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct x509_st X509;
+typedef struct X509_name_st X509_NAME;
+typedef struct evp_pkey_st EVP_PKEY;
 
 class Filename;
 class HTTPChannel;
@@ -155,12 +159,6 @@ private:
 
   static void split_whitespace(string &a, string &b, const string &c);
 
-#ifndef NDEBUG
-  static void ssl_msg_callback(int write_p, int version, int content_type,
-                               const void *buf, size_t len, SSL *ssl,
-                               void *arg);
-#endif
-
   typedef pvector<URLSpec> Proxies;
   typedef pmap<string, Proxies> ProxiesByScheme;
   ProxiesByScheme _proxies_by_scheme;

+ 1 - 2
panda/src/dxgsg9/dxIndexBufferContext9.cxx

@@ -132,8 +132,7 @@ allocate_ibuffer(DXScreenData &scrn,
       dxgsg9_cat.debug()
         << "creating index buffer " << _ibuffer << ": "
         << reader->get_num_vertices() << " indices ("
-        << reader->get_vertices_reader()->get_array_format()->get_column(0)->get_numeric_type()
-        << ")\n";
+        << reader->get_index_type() << ")\n";
     }
   }
 }

+ 8 - 4
panda/src/egg2pg/eggSaver.cxx

@@ -482,7 +482,7 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
       } else if (child->is_of_type(CollisionSphere::get_class_type())) {
         CPT(CollisionSphere) sphere = DCAST(CollisionSphere, child);
         LPoint3 center = sphere->get_center();
-        LVector3 offset(sphere->get_radius(), 0, 0);
+        PN_stdfloat radius = sphere->get_radius();
 
         EggGroup *egg_sphere;
         if (num_solids == 1) {
@@ -499,15 +499,19 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
         }
         egg_sphere->set_collide_flags(flags);
 
-        EggVertex ev1, ev2;
-        ev1.set_pos(LCAST(double, (center + offset) * net_mat));
-        ev2.set_pos(LCAST(double, (center - offset) * net_mat));
+        EggVertex ev1, ev2, ev3, ev4;
+        ev1.set_pos(LCAST(double, (center + LVector3(radius, 0, 0)) * net_mat));
+        ev2.set_pos(LCAST(double, (center + LVector3(0, radius, 0)) * net_mat));
+        ev3.set_pos(LCAST(double, (center + LVector3(-radius, 0, 0)) * net_mat));
+        ev4.set_pos(LCAST(double, (center + LVector3(0, -radius, 0)) * net_mat));
 
         EggPolygon *egg_poly = new EggPolygon;
         egg_sphere->add_child(egg_poly);
 
         egg_poly->add_vertex(cvpool->create_unique_vertex(ev1));
         egg_poly->add_vertex(cvpool->create_unique_vertex(ev2));
+        egg_poly->add_vertex(cvpool->create_unique_vertex(ev3));
+        egg_poly->add_vertex(cvpool->create_unique_vertex(ev4));
 
       } else if (child->is_of_type(CollisionPlane::get_class_type())) {
         LPlane plane = DCAST(CollisionPlane, child)->get_plane();

+ 2 - 37
panda/src/express/multifile.cxx

@@ -26,6 +26,8 @@
 #include <iterator>
 #include <time.h>
 
+#include "openSSLWrapper.h"
+
 // This sequence of bytes begins each Multifile to identify it as a Multifile.
 const char Multifile::_header[] = "pmf\0\n\r";
 const size_t Multifile::_header_size = 6;
@@ -768,43 +770,6 @@ add_signature(const Filename &composite, const string &password) {
 }
 #endif  // HAVE_OPENSSL
 
-#ifdef HAVE_OPENSSL
-/**
- * Adds a new signature to the Multifile.  This signature associates the
- * indicated certificate with the current contents of the Multifile.  When the
- * Multifile is read later, the signature will still be present only if the
- * Multifile is unchanged; any subsequent changes to the Multifile will
- * automatically invalidate and remove the signature.
- *
- * If chain is non-NULL, it represents the certificate chain that validates
- * the certificate.
- *
- * The specified private key must match the certificate, and the Multifile
- * must be open in read-write mode.  The private key is only used for
- * generating the signature; it is not written to the Multifile and cannot be
- * retrieved from the Multifile later.  (However, the certificate *can* be
- * retrieved from the Multifile later, to identify the entity that created the
- * signature.)
- *
- * This implicitly causes a repack() operation if one is needed.  Returns true
- * on success, false on failure.
- */
-bool Multifile::
-add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey) {
-  // Convert the certificate and chain into our own CertChain structure.
-  CertChain cert_chain;
-  cert_chain.push_back(CertRecord(certificate));
-  if (chain != NULL) {
-    int num = sk_X509_num(chain);
-    for (int i = 0; i < num; ++i) {
-      cert_chain.push_back(CertRecord((X509 *)sk_X509_value(chain, i)));
-    }
-  }
-
-  return add_signature(cert_chain, pkey);
-}
-#endif  // HAVE_OPENSSL
-
 #ifdef HAVE_OPENSSL
 /**
  * Adds a new signature to the Multifile.  This signature associates the

+ 5 - 2
panda/src/express/multifile.h

@@ -24,7 +24,11 @@
 #include "indirectLess.h"
 #include "referenceCount.h"
 #include "pvector.h"
-#include "openSSLWrapper.h"
+
+#ifdef HAVE_OPENSSL
+typedef struct x509_st X509;
+typedef struct evp_pkey_st EVP_PKEY;
+#endif
 
 /**
  * A file that contains a set of files.
@@ -148,7 +152,6 @@ public:
   };
   typedef pvector<CertRecord> CertChain;
 
-  bool add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey);
   bool add_signature(const CertChain &chain, EVP_PKEY *pkey);
 
   const CertChain &get_signature(int n) const;

+ 12 - 7
panda/src/glstuff/glCgShaderContext_src.cxx

@@ -145,7 +145,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
 
     if (cgGetParameterBaseResource(p) == CG_ATTR0) {
       // The Cg toolkit claims that it is bound to a generic vertex attribute.
-      if (_glsl_program != 0) {
+      if (_glgsg->has_fixed_function_pipeline() && _glsl_program != 0) {
         // This is where the Cg glslv compiler lies, making the stupid
         // assumption that we're using an NVIDIA card where generic attributes
         // are aliased with conventional vertex attributes.  Instead, it
@@ -246,7 +246,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
       // A conventional texture coordinate set.
       loc = CA_texcoord + cgGetParameterResourceIndex(p);
 
-    } else {
+    } else if (_glgsg->has_fixed_function_pipeline()) {
       // Some other conventional vertex attribute.
       switch (res) {
       case CG_POSITION0:
@@ -276,6 +276,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
         GLCAT.error(false) << ".\n";
         loc = CA_unknown;
       }
+    } else {
+      GLCAT.error()
+        << "Cg varying " << cgGetParameterName(p);
+      if (cgGetParameterSemantic(p)) {
+        GLCAT.error(false) << " : " << cgGetParameterSemantic(p);
+      }
+      GLCAT.error(false) << " is bound to a conventional vertex attribute, "
+                            "but the compatibility profile is not enabled.\n";
     }
 
 #ifndef NDEBUG
@@ -916,8 +924,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
       } else {
         // There is no vertex column with this name; disable the attribute
         // array.
-#ifdef SUPPORT_FIXED_FUNCTION
-        if (p == 0) {
+        if (_glgsg->has_fixed_function_pipeline() && p == 0) {
           // NOTE: if we disable attribute 0 in compatibility profile, the
           // object will disappear.  In GLSL we fix this by forcing the vertex
           // column to be at 0, but we don't have control over that with Cg.
@@ -930,9 +937,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
             _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
           }
 
-        } else
-#endif  // SUPPORT_FIXED_FUNCTION
-        if (p >= 0) {
+        } else if (p >= 0) {
           _glgsg->disable_vertex_attrib_array(p);
 
           if (p == _color_attrib_index) {

+ 19 - 26
panda/src/glstuff/glGraphicsBuffer_src.cxx

@@ -95,8 +95,7 @@ clear(Thread *current_thread) {
     return;
   }
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   if (glgsg->_glClearBufferfv == NULL) {
     // We can't efficiently clear the buffer.  Fall back to the inefficient
@@ -254,8 +253,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
     // until we call glBlitFramebuffer.
 #ifndef OPENGLES_1
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
-      CLP(GraphicsStateGuardian) *glgsg;
-      DCAST_INTO_R(glgsg, _gsg, false);
+      CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
       TextureContexts::iterator it;
       for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
@@ -269,6 +267,9 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       }
     }
 #endif
+  } else if (mode == FM_refresh) {
+    // Just bind the FBO.
+    rebuild_bitplanes();
   }
 
   _gsg->set_current_properties(&get_fb_properties());
@@ -282,8 +283,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
  */
 bool CLP(GraphicsBuffer)::
 check_fbo() {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_R(glgsg, _gsg, false);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
@@ -338,8 +338,7 @@ rebuild_bitplanes() {
     return;
   }
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   if (!_needs_rebuild) {
     if (_fbo_multisample != 0) {
@@ -682,8 +681,7 @@ rebuild_bitplanes() {
  */
 void CLP(GraphicsBuffer)::
 bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   Texture *tex = attach[slot];
 
@@ -1017,8 +1015,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
  */
 void CLP(GraphicsBuffer)::
 bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   if ((_rbm[slot] != 0)&&(!rb_resize)) {
     return;
@@ -1141,8 +1138,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
  */
 void CLP(GraphicsBuffer)::
 attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   if (view >= attach->get_num_views()) {
     attach->set_num_views(view + 1);
@@ -1162,8 +1158,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   glgsg->apply_texture(gtc);
 
 #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION)
-  GLclampf priority = 1.0f;
-  glPrioritizeTextures(1, &gtc->_index, &priority);
+  if (glgsg->has_fixed_function_pipeline()) {
+    GLclampf priority = 1.0f;
+    glPrioritizeTextures(1, &gtc->_index, &priority);
+  }
 #endif
 
 #ifndef OPENGLES
@@ -1210,8 +1208,7 @@ generate_mipmaps() {
     return;
   }
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
 
@@ -1248,8 +1245,7 @@ end_frame(FrameMode mode, Thread *current_thread) {
 
   // Unbind the FBO.  TODO: calling bind_fbo is slow, so we should probably
   // move this to begin_frame to prevent unnecessary calls.
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
   glgsg->bind_fbo(0);
   _bound_tex_page = -1;
 
@@ -1288,8 +1284,7 @@ void CLP(GraphicsBuffer)::
 select_target_tex_page(int page) {
   nassertv(page >= 0 && page < _fbo.size());
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   bool switched_page = (_bound_tex_page != page);
 
@@ -1684,8 +1679,7 @@ report_my_errors(int line, const char *file) {
       GLCAT.error() << file << ", line " << line << ": GL error " << (int)error_code << "\n";
     }
   } else {
-    CLP(GraphicsStateGuardian) *glgsg;
-    DCAST_INTO_V(glgsg, _gsg);
+    CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
     glgsg->report_my_errors(line, file);
   }
 }
@@ -1718,8 +1712,7 @@ void CLP(GraphicsBuffer)::
 resolve_multisamples() {
   nassertv(_fbo.size() > 0);
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
   PStatGPUTimer timer(glgsg, _resolve_multisample_pcollector);
 

+ 28 - 1
panda/src/glstuff/glGraphicsStateGuardian_src.I

@@ -130,6 +130,33 @@ get_gl_version_minor() const {
   return _gl_version_minor;
 }
 
+/**
+ * Returns whether a core profile or a compatibility mode is considered.
+ */
+/*INLINE bool CLP(GraphicsStateGuardian)::
+has_core_profile() const {
+  return _core_profile;
+}*/
+
+/**
+ * Returns whether the fixed function pipeline is supported.
+ */
+INLINE bool CLP(GraphicsStateGuardian)::
+has_fixed_function_pipeline() const {
+#ifndef SUPPORT_FIXED_FUNCTION
+  return false;
+#elif defined(OPENGLES_1)
+  return true;
+#elif defined(OPENGLES)
+  return false;
+#else
+  // Otherwise, we can just check whether we are using a core profile or a
+  // compatibility mode. The variable _core_profile is already taking into
+  // account if a GL < 3.2 is considered (becoming false)
+  return !_core_profile;
+#endif
+}
+
 /**
  * Calls glFinish() if the config variable gl-finish is set True.
  */
@@ -363,7 +390,7 @@ enable_line_smooth(bool val) {
 INLINE void CLP(GraphicsStateGuardian)::
 enable_point_smooth(bool val) {
 #ifdef SUPPORT_FIXED_FUNCTION
-  if (_point_smooth_enabled != val) {
+  if (has_fixed_function_pipeline() && _point_smooth_enabled != val) {
     _state_mask.clear_bit(TransparencyAttrib::get_class_slot());
     _point_smooth_enabled = val;
     if (val) {

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 310 - 216
panda/src/glstuff/glGraphicsStateGuardian_src.cxx


+ 6 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -399,6 +399,7 @@ public:
   INLINE const string &get_gl_version() const;
   INLINE int get_gl_version_major() const;
   INLINE int get_gl_version_minor() const;
+  INLINE bool has_fixed_function_pipeline() const;
 
   virtual void set_state_and_transform(const RenderState *state,
                                        const TransformState *transform);
@@ -719,6 +720,11 @@ protected:
 
   pset<string> _extensions;
 
+#ifndef OPENGLES
+  // True for non-compatibility GL 3.2+ contexts.
+  bool _core_profile;
+#endif
+
 public:
   bool _supports_point_parameters;
   PFNGLPOINTPARAMETERFVPROC _glPointParameterfv;

+ 43 - 19
panda/src/gobj/geom.I

@@ -51,7 +51,7 @@ get_geom_rendering() const {
 INLINE CPT(GeomVertexData) Geom::
 get_vertex_data(Thread *current_thread) const {
   CDReader cdata(_cycler, current_thread);
-  return cdata->_data.get_read_pointer();
+  return cdata->_data.get_read_pointer(current_thread);
 }
 
 /**
@@ -514,6 +514,18 @@ CData(const Geom::CData &copy) :
 {
 }
 
+
+/**
+ *
+ */
+INLINE GeomPipelineReader::
+GeomPipelineReader(Thread *current_thread) :
+  _object(nullptr),
+  _current_thread(current_thread),
+  _cdata(nullptr)
+{
+}
+
 /**
  *
  */
@@ -531,34 +543,22 @@ GeomPipelineReader(const Geom *object, Thread *current_thread) :
 #endif  // DO_PIPELINING
 }
 
-/**
- * Don't attempt to copy these objects.
- */
-INLINE GeomPipelineReader::
-GeomPipelineReader(const GeomPipelineReader &) {
-  nassertv(false);
-}
-
-/**
- * Don't attempt to copy these objects.
- */
-INLINE void GeomPipelineReader::
-operator = (const GeomPipelineReader &) {
-  nassertv(false);
-}
-
 /**
  *
  */
 INLINE GeomPipelineReader::
 ~GeomPipelineReader() {
 #ifdef _DEBUG
-  nassertv(_object->test_ref_count_nonzero());
+  if (_object != nullptr) {
+    nassertv(_object->test_ref_count_nonzero());
+  }
 #endif // _DEBUG
   // _object->_cycler.release_read(_cdata);
 
 #ifdef DO_PIPELINING
-  unref_delete((CycleData *)_cdata);
+  if (_cdata != nullptr) {
+    unref_delete((CycleData *)_cdata);
+  }
 #endif  // DO_PIPELINING
 
 #ifdef _DEBUG
@@ -567,6 +567,30 @@ INLINE GeomPipelineReader::
 #endif  // _DEBUG
 }
 
+/**
+ *
+ */
+INLINE void GeomPipelineReader::
+set_object(const Geom *object) {
+  if (object != _object) {
+    // _object->_cycler.release_read(_cdata);
+
+#ifdef DO_PIPELINING
+    if (_cdata != NULL) {
+      unref_delete((CycleData *)_cdata);
+    }
+#endif  // DO_PIPELINING
+
+    _cdata = object->_cycler.read_unlocked(_current_thread);
+
+#ifdef DO_PIPELINING
+    _cdata->ref();
+#endif  // DO_PIPELINING
+
+    _object = object;
+  }
+}
+
 /**
  *
  */

+ 35 - 33
panda/src/gobj/geom.cxx

@@ -236,7 +236,7 @@ make_nonindexed(bool composite_only) {
   int num_changed = 0;
 
   CDWriter cdata(_cycler, true, current_thread);
-  CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer();
+  CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread);
   PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
   new_data->clear_rows();
 
@@ -247,7 +247,7 @@ make_nonindexed(bool composite_only) {
   Primitives new_prims;
   new_prims.reserve(cdata->_primitives.size());
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy();
+    PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy();
     new_prims.push_back(primitive.p());
 
     // GeomPoints are considered "composite" for the purposes of making
@@ -298,7 +298,7 @@ set_primitive(int i, const GeomPrimitive *primitive) {
   Thread *current_thread = Thread::get_current_thread();
   CDWriter cdata(_cycler, true, current_thread);
   nassertv(i >= 0 && i < (int)cdata->_primitives.size());
-  nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
+  nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
 
   // All primitives within a particular Geom must have the same fundamental
   // primitive type (triangles, points, or lines).
@@ -339,7 +339,7 @@ add_primitive(const GeomPrimitive *primitive) {
   Thread *current_thread = Thread::get_current_thread();
   CDWriter cdata(_cycler, true, current_thread);
 
-  nassertv(primitive->check_valid(cdata->_data.get_read_pointer()));
+  nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread)));
 
   // All primitives within a particular Geom must have the same fundamental
   // primitive type (triangles, points, or lines).
@@ -426,11 +426,11 @@ decompose_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->decompose();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -460,11 +460,11 @@ doubleside_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->doubleside();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -494,11 +494,11 @@ reverse_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->reverse();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -528,11 +528,11 @@ rotate_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->rotate();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -596,7 +596,7 @@ unify_in_place(int max_indices, bool preserve_order) {
 
   Primitives::const_iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
+    CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread);
     NewPrims::iterator npi = new_prims.find(primitive->get_type());
     if (npi == new_prims.end()) {
       // This is the first primitive of this type.
@@ -648,7 +648,7 @@ unify_in_place(int max_indices, bool preserve_order) {
   for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
     GeomPrimitive *prim = (*npi).second;
 
-    nassertv(prim->check_valid(cdata->_data.get_read_pointer()));
+    nassertv(prim->check_valid(cdata->_data.get_read_pointer(current_thread)));
 
     // Each new primitive, naturally, inherits the Geom's overall shade model.
     prim->set_shade_model(cdata->_shade_model);
@@ -706,11 +706,11 @@ make_lines_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_lines();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_lines();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -740,11 +740,11 @@ make_points_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -774,11 +774,11 @@ make_patches_in_place() {
 #endif
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
-    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_patches();
+    CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 #ifndef NDEBUG
-    if (!new_prim->check_valid(cdata->_data.get_read_pointer())) {
+    if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) {
       all_is_valid = false;
     }
 #endif
@@ -865,7 +865,9 @@ get_num_bytes() const {
  */
 bool Geom::
 request_resident() const {
-  CDReader cdata(_cycler);
+  Thread *current_thread = Thread::get_current_thread();
+
+  CDReader cdata(_cycler, current_thread);
 
   bool resident = true;
 
@@ -873,7 +875,7 @@ request_resident() const {
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        ++pi) {
-    if (!(*pi).get_read_pointer()->request_resident()) {
+    if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
       resident = false;
     }
   }
@@ -1197,7 +1199,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
   int num_vertices = 0;
 
   // Get the vertex data, after animation.
-  CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer();
+  CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread);
   vertex_data = vertex_data->animate_vertices(true, current_thread);
 
   // Now actually compute the bounding volume.  We do this by using
@@ -1296,7 +1298,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
     for (pi = cdata->_primitives.begin();
          pi != cdata->_primitives.end();
          ++pi) {
-      CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
+      CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
       num_vertices += prim->get_num_vertices();
     }
 
@@ -1327,7 +1329,7 @@ do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        ++pi) {
-    CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
+    CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
     prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
                             found_any, vertex_data, got_mat, mat,
                             column_name, current_thread);
@@ -1345,7 +1347,7 @@ do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        ++pi) {
-    CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
+    CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
     prim->calc_sphere_radius(center, sq_radius, found_any,
                              vertex_data, current_thread);
   }
@@ -1469,8 +1471,10 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim,
     a_prim->append_unused_vertices(a_vertices, b_vertex);
   }
 
-  PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread);
-  CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread);
+  PT(GeomVertexArrayDataHandle) a_handle =
+    new GeomVertexArrayDataHandle(move(a_vertices), current_thread);
+  CPT(GeomVertexArrayDataHandle) b_handle =
+    new GeomVertexArrayDataHandle(move(b_vertices), current_thread);
 
   size_t orig_a_vertices = a_handle->get_num_rows();
 
@@ -1683,8 +1687,7 @@ check_valid(const GeomVertexDataPipelineReader *data_reader) const {
   for (pi = _cdata->_primitives.begin();
        pi != _cdata->_primitives.end();
        ++pi) {
-    CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
-    GeomPrimitivePipelineReader reader(primitive, _current_thread);
+    GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
     reader.check_minmax();
     if (!reader.check_valid(data_reader)) {
       return false;
@@ -1707,12 +1710,11 @@ draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger,
     for (pi = _cdata->_primitives.begin();
          pi != _cdata->_primitives.end();
          ++pi) {
-      CPT(GeomPrimitive) primitive = (*pi).get_read_pointer();
-      GeomPrimitivePipelineReader reader(primitive, _current_thread);
+      GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread);
       if (reader.get_num_vertices() != 0) {
         reader.check_minmax();
         nassertr(reader.check_valid(data_reader), false);
-        if (!primitive->draw(gsg, &reader, force)) {
+        if (!reader.draw(gsg, force)) {
           all_ok = false;
         }
       }

+ 4 - 2
panda/src/gobj/geom.h

@@ -401,15 +401,17 @@ private:
  */
 class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
 public:
+  INLINE GeomPipelineReader(Thread *current_thread);
   INLINE GeomPipelineReader(const Geom *object, Thread *current_thread);
 private:
-  INLINE GeomPipelineReader(const GeomPipelineReader &copy);
-  INLINE void operator = (const GeomPipelineReader &copy);
+  GeomPipelineReader(const GeomPipelineReader &copy) DELETED;
+  GeomPipelineReader &operator = (const GeomPipelineReader &copy) DELETED_ASSIGN;
 
 public:
   INLINE ~GeomPipelineReader();
   ALLOC_DELETED_CHAIN(GeomPipelineReader);
 
+  INLINE void set_object(const Geom *object);
   INLINE const Geom *get_object() const;
   INLINE Thread *get_current_thread() const;
 

+ 2 - 2
panda/src/gobj/geomCacheEntry.cxx

@@ -95,8 +95,8 @@ PT(GeomCacheEntry) GeomCacheEntry::
 erase() {
   nassertr(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL, NULL);
 
-  PT(GeomCacheEntry) keepme = this;
-  unref();
+  PT(GeomCacheEntry) keepme;
+  keepme.cheat() = this;
 
   if (gobj_cat.is_debug()) {
     gobj_cat.debug()

+ 60 - 36
panda/src/gobj/geomPrimitive.I

@@ -235,6 +235,24 @@ get_vertices() const {
   return cdata->_vertices.get_read_pointer();
 }
 
+/**
+ * Equivalent to get_vertices().get_handle().
+ */
+INLINE CPT(GeomVertexArrayDataHandle) GeomPrimitive::
+get_vertices_handle(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
+  return new GeomVertexArrayDataHandle(cdata->_vertices.get_read_pointer(current_thread), current_thread);
+}
+
+/**
+ * Equivalent to modify_vertices().get_handle().
+ */
+INLINE PT(GeomVertexArrayDataHandle) GeomPrimitive::
+modify_vertices_handle(Thread *current_thread) {
+  CDWriter cdata(_cycler, true, current_thread);
+  return new GeomVertexArrayDataHandle(do_modify_vertices(cdata), current_thread);
+}
+
 /**
  * A convenience function to return the gap between successive index numbers,
  * in bytes, of the index data.
@@ -414,38 +432,32 @@ CData(const GeomPrimitive::CData &copy) :
  *
  */
 INLINE GeomPrimitivePipelineReader::
-GeomPrimitivePipelineReader(const GeomPrimitive *object,
+GeomPrimitivePipelineReader(CPT(GeomPrimitive) object,
                             Thread *current_thread) :
-  _object(object),
+  _object(move(object)),
   _current_thread(current_thread),
-  _cdata(object->_cycler.read_unlocked(current_thread)),
-  _vertices_reader(NULL)
+#ifndef CPPPARSER
+  _cdata(_object->_cycler.read_unlocked(current_thread)),
+#endif
+  _vertices_cdata(NULL)
 {
   nassertv(_object->test_ref_count_nonzero());
 #ifdef DO_PIPELINING
   _cdata->ref();
 #endif  // DO_PIPELINING
+
   if (!_cdata->_vertices.is_null()) {
-    _vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle();
+    _vertices = _cdata->_vertices.get_read_pointer(current_thread);
+    _vertices_cdata = _vertices->_cycler.read_unlocked(current_thread);
+#ifdef DO_PIPELINING
+    _vertices_cdata->ref();
+#endif  // DO_PIPELINING
+    // We must grab the lock *after* we have incremented the reference count,
+    // above.
+    _vertices_cdata->_rw_lock.acquire();
   }
 }
 
-/**
- * Don't attempt to copy these objects.
- */
-INLINE GeomPrimitivePipelineReader::
-GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &) {
-  nassertv(false);
-}
-
-/**
- * Don't attempt to copy these objects.
- */
-INLINE void GeomPrimitivePipelineReader::
-operator = (const GeomPrimitivePipelineReader &) {
-  nassertv(false);
-}
-
 /**
  *
  */
@@ -460,8 +472,17 @@ INLINE GeomPrimitivePipelineReader::
   unref_delete((CycleData *)_cdata);
 #endif  // DO_PIPELINING
 
+  if (_vertices_cdata != nullptr) {
+    // We must release the lock *before* we decrement the reference count,
+    // below.
+    _vertices_cdata->_rw_lock.release();
+
+#ifdef DO_PIPELINING
+    unref_delete((CycleData *)_vertices_cdata);
+#endif  // DO_PIPELINING
+  }
+
 #ifdef _DEBUG
-  _vertices_reader = NULL;
   _object = NULL;
   _cdata = NULL;
 #endif  // _DEBUG
@@ -512,7 +533,7 @@ get_index_type() const {
  */
 INLINE bool GeomPrimitivePipelineReader::
 is_indexed() const {
-  return (!_cdata->_vertices.is_null());
+  return (!_vertices.is_null());
 }
 
 /**
@@ -523,8 +544,10 @@ get_num_vertices() const {
   if (_cdata->_num_vertices != -1) {
     return _cdata->_num_vertices;
   } else {
-    nassertr(!_cdata->_vertices.is_null(), 0);
-    return _vertices_reader->get_num_rows();
+    nassertr(!_vertices.is_null(), 0);
+    size_t stride = _vertices->_array_format->get_stride();
+    nassertr(stride != 0, 0);
+    return get_data_size_bytes() / stride;
   }
 }
 
@@ -551,7 +574,7 @@ get_max_vertex() const {
  */
 INLINE int GeomPrimitivePipelineReader::
 get_data_size_bytes() const {
-  return _vertices_reader->get_data_size_bytes();
+  return _vertices_cdata->_buffer.get_size();
 }
 
 /**
@@ -568,15 +591,7 @@ get_modified() const {
 INLINE int GeomPrimitivePipelineReader::
 get_index_stride() const {
   nassertr(is_indexed(), 0);
-  return _cdata->_vertices.get_read_pointer()->get_array_format()->get_stride();
-}
-
-/**
- *
- */
-INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader::
-get_vertices_reader() const {
-  return _vertices_reader;
+  return _vertices->_array_format->get_stride();
 }
 
 /**
@@ -584,7 +599,8 @@ get_vertices_reader() const {
  */
 INLINE const unsigned char *GeomPrimitivePipelineReader::
 get_read_pointer(bool force) const {
-  return _vertices_reader->get_read_pointer(force);
+  ((GeomVertexArrayData *)_vertices.p())->mark_used();
+  return _vertices_cdata->_buffer.get_read_pointer(force);
 }
 
 /**
@@ -632,6 +648,14 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
   return ((GeomPrimitive *)_object.p())->prepare_now(prepared_objects, gsg);
 }
 
+/**
+ * Calls the appropriate method on the GSG to draw the primitive.
+ */
+INLINE bool GeomPrimitivePipelineReader::
+draw(GraphicsStateGuardianBase *gsg, bool force) const {
+  return _object->draw(gsg, this, force);
+}
+
 INLINE ostream &
 operator << (ostream &out, const GeomPrimitive &obj) {
   obj.output(out);

+ 16 - 13
panda/src/gobj/geomPrimitive.cxx

@@ -1036,23 +1036,23 @@ get_num_bytes() const {
  * shortly; try again later.
  */
 bool GeomPrimitive::
-request_resident() const {
-  CDReader cdata(_cycler);
+request_resident(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
 
   bool resident = true;
 
   if (!cdata->_vertices.is_null() &&
-      !cdata->_vertices.get_read_pointer()->request_resident()) {
+      !cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) {
     resident = false;
   }
 
   if (is_composite() && cdata->_got_minmax) {
     if (!cdata->_mins.is_null() &&
-        !cdata->_mins.get_read_pointer()->request_resident()) {
+        !cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) {
       resident = false;
     }
     if (!cdata->_maxs.is_null() &&
-        !cdata->_maxs.get_read_pointer()->request_resident()) {
+        !cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) {
       resident = false;
     }
   }
@@ -2178,14 +2178,17 @@ check_minmax() const {
  */
 int GeomPrimitivePipelineReader::
 get_first_vertex() const {
-  if (_cdata->_vertices.is_null()) {
+  if (_vertices.is_null()) {
     return _cdata->_first_vertex;
-  } else if (_vertices_reader->get_num_rows() == 0) {
+  }
+
+  size_t size = _vertices_cdata->_buffer.get_size();
+  if (size == 0) {
     return 0;
-  } else {
-    GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0);
-    return index.get_data1i();
   }
+
+  GeomVertexReader index(_vertices, 0);
+  return index.get_data1i();
 }
 
 /**
@@ -2193,11 +2196,11 @@ get_first_vertex() const {
  */
 int GeomPrimitivePipelineReader::
 get_vertex(int i) const {
-  if (!_cdata->_vertices.is_null()) {
+  if (!_vertices.is_null()) {
     // The indexed case.
-    nassertr(i >= 0 && i < _vertices_reader->get_num_rows(), -1);
+    nassertr(i >= 0 && i < get_num_vertices(), -1);
 
-    GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0);
+    GeomVertexReader index(_vertices, 0);
     index.set_row_unsafe(i);
     return index.get_data1i();
 

+ 9 - 6
panda/src/gobj/geomPrimitive.h

@@ -142,7 +142,7 @@ PUBLISHED:
   MAKE_PROPERTY(data_size_bytes, get_data_size_bytes);
   MAKE_PROPERTY(modified, get_modified);
 
-  bool request_resident() const;
+  bool request_resident(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE bool check_valid(const GeomVertexData *vertex_data) const;
 
@@ -162,7 +162,9 @@ PUBLISHED:
  */
 
   INLINE CPT(GeomVertexArrayData) get_vertices() const;
+  INLINE CPT(GeomVertexArrayDataHandle) get_vertices_handle(Thread *current_thread) const;
   PT(GeomVertexArrayData) modify_vertices(int num_vertices = -1);
+  INLINE PT(GeomVertexArrayDataHandle) modify_vertices_handle(Thread *current_thread);
   void set_vertices(const GeomVertexArrayData *vertices, int num_vertices = -1);
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
 
@@ -347,10 +349,10 @@ private:
  */
 class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums {
 public:
-  INLINE GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread);
+  INLINE GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread);
 private:
-  INLINE GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &copy);
-  INLINE void operator = (const GeomPrimitivePipelineReader &copy);
+  GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &copy) DELETED;
+  GeomPrimitivePipelineReader &operator = (const GeomPrimitivePipelineReader &copy) DELETED_ASSIGN;
 
 public:
   INLINE ~GeomPrimitivePipelineReader();
@@ -375,7 +377,6 @@ public:
   INLINE UpdateSeq get_modified() const;
   bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
   INLINE int get_index_stride() const;
-  INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const;
   INLINE const unsigned char *get_read_pointer(bool force) const;
   INLINE int get_strip_cut_index() const;
   INLINE CPTA_int get_ends() const;
@@ -384,13 +385,15 @@ public:
 
   INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                                          GraphicsStateGuardianBase *gsg) const;
+  INLINE bool draw(GraphicsStateGuardianBase *gsg, bool force) const;
 
 private:
   CPT(GeomPrimitive) _object;
   Thread *_current_thread;
   const GeomPrimitive::CData *_cdata;
 
-  CPT(GeomVertexArrayDataHandle) _vertices_reader;
+  CPT(GeomVertexArrayData) _vertices;
+  const GeomVertexArrayData::CData *_vertices_cdata;
 
 public:
   static TypeHandle get_class_type() {

+ 67 - 18
panda/src/gobj/geomVertexArrayData.I

@@ -130,9 +130,25 @@ get_modified() const {
  * back into memory shortly; try again later.
  */
 INLINE bool GeomVertexArrayData::
-request_resident() const {
-  CPT(GeomVertexArrayDataHandle) handle = get_handle();
-  return handle->request_resident();
+request_resident(Thread *current_thread) const {
+  const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread);
+
+#ifdef DO_PIPELINING
+  cdata->ref();
+#endif
+
+  cdata->_rw_lock.acquire();
+
+  ((GeomVertexArrayData *)this)->mark_used();
+  bool is_resident = (cdata->_buffer.get_read_pointer(false) != nullptr);
+
+  cdata->_rw_lock.release();
+
+#ifdef DO_PIPELINING
+  unref_delete((CycleData *)cdata);
+#endif
+
+  return is_resident;
 }
 
 /**
@@ -143,9 +159,7 @@ request_resident() const {
  */
 INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData::
 get_handle(Thread *current_thread) const {
-  const CData *cdata = _cycler.read_unlocked(current_thread);
-  return new GeomVertexArrayDataHandle(this, current_thread,
-                                       cdata, false);
+  return new GeomVertexArrayDataHandle(this, current_thread);
 }
 
 /**
@@ -156,9 +170,7 @@ get_handle(Thread *current_thread) const {
  */
 INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData::
 modify_handle(Thread *current_thread) {
-  CData *cdata = _cycler.write_upstream(true, current_thread);
-  return new GeomVertexArrayDataHandle(this, current_thread,
-                                       cdata, true);
+  return new GeomVertexArrayDataHandle(PT(GeomVertexArrayData)(this), current_thread);
 }
 
 /**
@@ -202,6 +214,17 @@ set_lru_size(size_t lru_size) {
   }
 }
 
+/**
+ */
+INLINE void GeomVertexArrayData::
+mark_used() {
+  if ((int)get_lru_size() <= vertex_data_small_size) {
+    SimpleLruPage::mark_used_lru(&_small_lru);
+  } else {
+    SimpleLruPage::mark_used_lru(&_independent_lru);
+  }
+}
+
 /**
  *
  */
@@ -238,15 +261,40 @@ operator = (const GeomVertexArrayData::CData &copy) {
  *
  */
 INLINE GeomVertexArrayDataHandle::
-GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
-                          Thread *current_thread,
-                          const GeomVertexArrayData::CData *cdata,
-                          bool writable) :
-  _object((GeomVertexArrayData *)object),
+GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object,
+                          Thread *current_thread) :
+  _current_thread(current_thread),
+  _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)),
+  _writable(false)
+{
+  _object.swap(object);
+
+#ifdef _DEBUG
+  nassertv(_object->test_ref_count_nonzero());
+#endif // _DEBUG
+#ifdef DO_PIPELINING
+  _cdata->ref();
+#endif  // DO_PIPELINING
+  // We must grab the lock *after* we have incremented the reference count,
+  // above.
+  _cdata->_rw_lock.acquire();
+#ifdef DO_MEMORY_USAGE
+  MemoryUsage::update_type(this, get_class_type());
+#endif
+}
+
+/**
+ *
+ */
+INLINE GeomVertexArrayDataHandle::
+GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object,
+                          Thread *current_thread) :
   _current_thread(current_thread),
-  _cdata((GeomVertexArrayData::CData *)cdata),
-  _writable(writable)
+  _cdata(object->_cycler.write_upstream(true, current_thread)),
+  _writable(true)
 {
+  _object.swap(object);
+
 #ifdef _DEBUG
   nassertv(_object->test_ref_count_nonzero());
 #endif // _DEBUG
@@ -265,7 +313,8 @@ GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
  * Don't attempt to copy these objects.
  */
 INLINE GeomVertexArrayDataHandle::
-GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy) {
+GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy)
+  : _current_thread(copy._current_thread) {
   nassertv(false);
 }
 
@@ -448,7 +497,7 @@ get_subdata(size_t start, size_t size) const {
  */
 void GeomVertexArrayDataHandle::
 mark_used() const {
-  _object->set_lru_size(_object->get_lru_size());
+  _object->mark_used();
 }
 
 INLINE ostream &

+ 15 - 8
panda/src/gobj/geomVertexArrayData.h

@@ -95,7 +95,7 @@ PUBLISHED:
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
 
-  INLINE bool request_resident() const;
+  INLINE bool request_resident(Thread *current_thread = Thread::get_current_thread()) const;
 
   INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread());
@@ -124,6 +124,7 @@ public:
 
 private:
   INLINE void set_lru_size(size_t lru_size);
+  INLINE void mark_used();
 
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void reverse_data_endianness(unsigned char *dest,
@@ -230,6 +231,7 @@ private:
   friend class GeomVertexData;
   friend class PreparedGraphicsObjects;
   friend class GeomVertexArrayDataHandle;
+  friend class GeomPrimitivePipelineReader;
 };
 
 /**
@@ -246,10 +248,10 @@ private:
  */
 class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums {
 private:
-  INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
-                                   Thread *current_thread,
-                                   const GeomVertexArrayData::CData *_cdata,
-                                   bool writable);
+  INLINE GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object,
+                                   Thread *current_thread);
+  INLINE GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object,
+                                   Thread *current_thread);
   INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &);
   INLINE void operator = (const GeomVertexArrayDataHandle &);
 
@@ -261,8 +263,8 @@ public:
 
   INLINE Thread *get_current_thread() const;
 
-  INLINE const unsigned char *get_read_pointer(bool force) const;
-  unsigned char *get_write_pointer();
+  INLINE const unsigned char *get_read_pointer(bool force) const RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
+  unsigned char *get_write_pointer() RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
 
 PUBLISHED:
   INLINE const GeomVertexArrayData *get_object() const;
@@ -316,7 +318,7 @@ PUBLISHED:
 
 private:
   PT(GeomVertexArrayData) _object;
-  Thread *_current_thread;
+  Thread *const _current_thread;
   GeomVertexArrayData::CData *_cdata;
   bool _writable;
 
@@ -333,6 +335,11 @@ public:
 private:
   static TypeHandle _type_handle;
 
+  friend class Geom;
+  friend class GeomPrimitive;
+  friend class GeomVertexData;
+  friend class GeomVertexDataPipelineReader;
+  friend class GeomVertexDataPipelineWriter;
   friend class GeomVertexArrayData;
 };
 

+ 59 - 41
panda/src/gobj/geomVertexData.I

@@ -147,6 +147,17 @@ get_array(int i) const {
   return cdata->_arrays[i].get_read_pointer();
 }
 
+/**
+ * Equivalent to get_array(i).get_handle().
+ */
+INLINE CPT(GeomVertexArrayDataHandle) GeomVertexData::
+get_array_handle(int i) const {
+  Thread *current_thread = Thread::get_current_thread();
+  CDReader cdata(_cycler, current_thread);
+  nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
+  return new GeomVertexArrayDataHandle(cdata->_arrays[i].get_read_pointer(), current_thread);
+}
+
 /**
  * Returns a modifiable pointer to the indicated vertex array, so that
  * application code may directly manipulate the data.  You should avoid
@@ -162,6 +173,16 @@ modify_array(int i) {
   return writer.modify_array(i);
 }
 
+/**
+ * Equivalent to modify_array(i).modify_handle().
+ */
+INLINE PT(GeomVertexArrayDataHandle) GeomVertexData::
+modify_array_handle(int i) {
+  Thread *current_thread = Thread::get_current_thread();
+  GeomVertexDataPipelineWriter writer(this, true, current_thread);
+  return new GeomVertexArrayDataHandle(writer.modify_array(i), current_thread);
+}
+
 /**
  * Replaces the indicated vertex data array with a completely new array.  You
  * should be careful that the new array has the same length and format as the
@@ -575,6 +596,17 @@ CData(const GeomVertexData::CData &copy) :
 {
 }
 
+/**
+ *
+ */
+INLINE GeomVertexDataPipelineBase::
+GeomVertexDataPipelineBase(Thread *current_thread) :
+  _object(nullptr),
+  _current_thread(current_thread),
+  _cdata(nullptr)
+{
+}
+
 /**
  *
  */
@@ -600,11 +632,15 @@ GeomVertexDataPipelineBase(GeomVertexData *object,
 INLINE GeomVertexDataPipelineBase::
 ~GeomVertexDataPipelineBase() {
 #ifdef _DEBUG
-  nassertv(_object->test_ref_count_nonzero());
+  if (_object != nullptr) {
+    nassertv(_object->test_ref_count_nonzero());
+  }
 #endif // _DEBUG
 
 #ifdef DO_PIPELINING
-  unref_delete((CycleData *)_cdata);
+  if (_cdata != nullptr) {
+    unref_delete((CycleData *)_cdata);
+  }
 #endif  // DO_PIPELINING
 
 #ifdef _DEBUG
@@ -698,41 +734,41 @@ get_modified() const {
  *
  */
 INLINE GeomVertexDataPipelineReader::
-GeomVertexDataPipelineReader(const GeomVertexData *object,
-                             Thread *current_thread) :
-  GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread,
-                             (GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)),
+GeomVertexDataPipelineReader(Thread *current_thread) :
+  GeomVertexDataPipelineBase(current_thread),
   _got_array_readers(false)
 {
 }
 
 /**
- * Don't attempt to copy these objects.
+ *
  */
 INLINE GeomVertexDataPipelineReader::
-GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy) :
-  GeomVertexDataPipelineBase(copy)
+GeomVertexDataPipelineReader(const GeomVertexData *object,
+                             Thread *current_thread) :
+  GeomVertexDataPipelineBase((GeomVertexData *)object, current_thread,
+                             (GeomVertexData::CData *)object->_cycler.read_unlocked(current_thread)),
+  _got_array_readers(false)
 {
-  nassertv(false);
-}
-
-/**
- * Don't attempt to copy these objects.
- */
-INLINE void GeomVertexDataPipelineReader::
-operator = (const GeomVertexDataPipelineReader &) {
-  nassertv(false);
 }
 
 /**
  *
  */
-INLINE GeomVertexDataPipelineReader::
-~GeomVertexDataPipelineReader() {
-  if (_got_array_readers) {
-    delete_array_readers();
+INLINE void GeomVertexDataPipelineReader::
+set_object(CPT(GeomVertexData) object) {
+#ifdef DO_PIPELINING
+  if (_cdata != NULL) {
+    unref_delete((CycleData *)_cdata);
   }
-  // _object->_cycler.release_read(_cdata);
+#endif  // DO_PIPELINING
+  _array_readers.clear();
+
+  _object.swap(object);
+  _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread);
+  _got_array_readers = false;
+
+  _cdata->ref();
 }
 
 /**
@@ -819,24 +855,6 @@ GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
 #endif // _DEBUG
 }
 
-/**
- * Don't attempt to copy these objects.
- */
-INLINE GeomVertexDataPipelineWriter::
-GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy) :
-  GeomVertexDataPipelineBase(copy)
-{
-  nassertv(false);
-}
-
-/**
- * Don't attempt to copy these objects.
- */
-INLINE void GeomVertexDataPipelineWriter::
-operator = (const GeomVertexDataPipelineWriter &) {
-  nassertv(false);
-}
-
 /**
  *
  */

+ 20 - 37
panda/src/gobj/geomVertexData.cxx

@@ -516,9 +516,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
         if (keep_data_objects) {
           // Copy the data, but keep the same GeomVertexArrayData object.
 
-          PT(GeomVertexArrayData) dest_data = modify_array(dest_i);
-          CPT(GeomVertexArrayData) source_data = source->get_array(source_i);
-          dest_data->modify_handle()->copy_data_from(source_data->get_handle());
+          modify_array_handle(dest_i)->copy_data_from(source->get_array_handle(source_i));
         } else {
           // Copy the GeomVertexArrayData object.
           if (get_array(dest_i) != source->get_array(source_i)) {
@@ -533,13 +531,16 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
   }
 
   // Now make sure the arrays we didn't share are all filled in.
-  reserve_num_rows(num_rows);
-  set_num_rows(num_rows);
+  {
+    GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread());
+    writer.check_array_writers();
+    writer.reserve_num_rows(num_rows);
+    writer.set_num_rows(num_rows);
+  }
 
   // Now go back through and copy any data that's left over.
   for (source_i = 0; source_i < num_arrays; ++source_i) {
-    CPT(GeomVertexArrayData) array_obj = source->get_array(source_i);
-    CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle();
+    CPT(GeomVertexArrayDataHandle) array_handle = source->get_array_handle(source_i);
     const unsigned char *array_data = array_handle->get_read_pointer(true);
     const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
     int num_columns = source_array_format->get_num_columns();
@@ -557,8 +558,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
 
         if (dest_column->is_bytewise_equivalent(*source_column)) {
           // We can do a quick bytewise copy.
-          PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
           bytewise_copy(dest_array_data + dest_column->get_start(),
@@ -569,8 +569,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
         } else if (dest_column->is_packed_argb() &&
                    source_column->is_uint8_rgba()) {
           // A common special case: OpenGL color to DirectX color.
-          PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
           uint8_rgba_to_packed_argb
@@ -582,8 +581,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
         } else if (dest_column->is_uint8_rgba() &&
                    source_column->is_packed_argb()) {
           // Another common special case: DirectX color to OpenGL color.
-          PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i);
-          PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+          PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i);
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
           packed_argb_to_uint8_rgba
@@ -700,12 +698,10 @@ copy_row_from(int dest_row, const GeomVertexData *source,
   int num_arrays = source_format->get_num_arrays();
 
   for (int i = 0; i < num_arrays; ++i) {
-    PT(GeomVertexArrayData) dest_array_obj = modify_array(i);
-    PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle();
+    PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i);
     unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
-    CPT(GeomVertexArrayData) source_array_obj = source->get_array(i);
-    CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle();
+    CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i);
     const unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
 
     const GeomVertexArrayFormat *array_format = source_format->get_array(i);
@@ -1144,8 +1140,7 @@ do_set_color(GeomVertexData *vdata, const LColor &color) {
   packer->set_data4f(buffer, color);
 #endif
 
-  PT(GeomVertexArrayDataHandle) handle =
-    vdata->modify_array(array_index)->modify_handle();
+  PT(GeomVertexArrayDataHandle) handle = vdata->modify_array_handle(array_index);
   unsigned char *write_ptr = handle->get_write_pointer();
   unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes();
   write_ptr += column->get_start();
@@ -1586,7 +1581,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
   }
 
   // Then apply the transforms.
-  CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer();
+  CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(current_thread);
   if (tb_table != (TransformBlendTable *)NULL) {
     // Recompute all the blends up front, so we don't have to test each one
     // for staleness at each vertex.
@@ -1617,7 +1612,8 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
     if (blend_array_format->get_stride() == 2 &&
         blend_array_format->get_column(0)->get_component_bytes() == 2) {
       // The blend indices are a table of ushorts.  Optimize this common case.
-      CPT(GeomVertexArrayDataHandle) blend_array_handle = cdata->_arrays[blend_array_index].get_read_pointer()->get_handle(current_thread);
+      CPT(GeomVertexArrayDataHandle) blend_array_handle =
+        new GeomVertexArrayDataHandle(cdata->_arrays[blend_array_index].get_read_pointer(current_thread), current_thread);
       const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true);
 
       size_t ci;
@@ -2399,24 +2395,12 @@ make_array_readers() {
   _array_readers.reserve(_cdata->_arrays.size());
   GeomVertexData::Arrays::const_iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
-    CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer();
-    _array_readers.push_back(array_obj->get_handle(_current_thread));
+    _array_readers.push_back(new GeomVertexArrayDataHandle((*ai).get_read_pointer(_current_thread), _current_thread));
   }
 
   _got_array_readers = true;
 }
 
-/**
- *
- */
-void GeomVertexDataPipelineReader::
-delete_array_readers() {
-  nassertv(_got_array_readers);
-
-  _array_readers.clear();
-  _got_array_readers = false;
-}
-
 /**
  *
  */
@@ -2610,7 +2594,7 @@ set_array(int i, const GeomVertexArrayData *array) {
   _cdata->_animated_vertices_modified = UpdateSeq();
 
   if (_got_array_writers) {
-    _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread);
+    _array_writers[i] = new GeomVertexArrayDataHandle(_cdata->_arrays[i].get_write_pointer(), _current_thread);
   }
 }
 
@@ -2624,8 +2608,7 @@ make_array_writers() {
   _array_writers.reserve(_cdata->_arrays.size());
   GeomVertexData::Arrays::iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) {
-    PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer();
-    _array_writers.push_back(array_obj->modify_handle(_current_thread));
+    _array_writers.push_back(new GeomVertexArrayDataHandle((*ai).get_write_pointer(), _current_thread));
   }
 
   _object->clear_cache_stage();

+ 9 - 10
panda/src/gobj/geomVertexData.h

@@ -107,8 +107,10 @@ PUBLISHED:
 
   INLINE int get_num_arrays() const;
   INLINE CPT(GeomVertexArrayData) get_array(int i) const;
+  INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(int i) const;
   MAKE_SEQ(get_arrays, get_num_arrays, get_array);
   INLINE PT(GeomVertexArrayData) modify_array(int i);
+  INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(int i);
   INLINE void set_array(int i, const GeomVertexArrayData *array);
   MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array);
 
@@ -402,10 +404,15 @@ private:
  */
 class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums {
 protected:
+  INLINE GeomVertexDataPipelineBase(Thread *current_thread);
   INLINE GeomVertexDataPipelineBase(GeomVertexData *object,
                                     Thread *current_thread,
                                     GeomVertexData::CData *cdata);
 
+private:
+  GeomVertexDataPipelineBase(const GeomVertexDataPipelineBase &copy) DELETED;
+  GeomVertexDataPipelineBase &operator = (const GeomVertexDataPipelineBase &copy) DELETED_ASSIGN;
+
 public:
   INLINE ~GeomVertexDataPipelineBase();
 
@@ -436,15 +443,12 @@ protected:
  */
 class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipelineBase {
 public:
+  INLINE GeomVertexDataPipelineReader(Thread *current_thread);
   INLINE GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread);
-private:
-  INLINE GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader &copy);
-  INLINE void operator = (const GeomVertexDataPipelineReader &copy);
 
-public:
-  INLINE ~GeomVertexDataPipelineReader();
   ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader);
 
+  INLINE void set_object(CPT(GeomVertexData) object);
   INLINE const GeomVertexData *get_object() const;
 
   INLINE void check_array_readers() const;
@@ -480,7 +484,6 @@ public:
 
 private:
   void make_array_readers();
-  void delete_array_readers();
 
   bool _got_array_readers;
   typedef pvector<CPT(GeomVertexArrayDataHandle) > ArrayReaders;
@@ -506,11 +509,7 @@ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineWriter : public GeomVertexDataPipel
 public:
   INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0,
                                       Thread *current_thread);
-private:
-  INLINE GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter &copy);
-  INLINE void operator = (const GeomVertexDataPipelineWriter &copy);
 
-public:
   INLINE ~GeomVertexDataPipelineWriter();
   ALLOC_DELETED_CHAIN(GeomVertexDataPipelineWriter);
 

+ 1 - 1
panda/src/gobj/geomVertexWriter.cxx

@@ -14,7 +14,7 @@
 #include "geomVertexWriter.h"
 
 
-#ifndef NDEBUG
+#ifdef _DEBUG
   // This is defined just for the benefit of having something non-NULL to
   // return from a nassertr() call.
 unsigned char GeomVertexWriter::empty_buffer[100] = { 0 };

+ 1 - 1
panda/src/gobj/geomVertexWriter.h

@@ -212,7 +212,7 @@ private:
 
   int _start_row;
 
-#ifndef NDEBUG
+#ifdef _DEBUG
   // This is defined just for the benefit of having something non-NULL to
   // return from a nassertr() call.
   static unsigned char empty_buffer[100];

+ 11 - 20
panda/src/gobj/vertexDataBuffer.cxx

@@ -27,15 +27,13 @@ operator = (const VertexDataBuffer &copy) {
 
   if (_resident_data != (unsigned char *)NULL) {
     nassertv(_reserved_size != 0);
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
-    PANDA_FREE_ARRAY(_resident_data);
+    get_class_type().deallocate_array(_resident_data);
     _resident_data = NULL;
   }
   if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) {
     // We only allocate _size bytes, not the full _reserved_size allocated by
     // the original copy.
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)copy._size);
-    _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(copy._size);
+    _resident_data = (unsigned char *)get_class_type().allocate_array(copy._size);
     memcpy(_resident_data, copy._resident_data, copy._size);
   }
   _size = copy._size;
@@ -55,17 +53,16 @@ swap(VertexDataBuffer &other) {
   unsigned char *resident_data = _resident_data;
   size_t size = _size;
   size_t reserved_size = _reserved_size;
-  PT(VertexDataBlock) block = _block;
+
+  _block.swap(other._block);
 
   _resident_data = other._resident_data;
   _size = other._size;
   _reserved_size = other._reserved_size;
-  _block = other._block;
 
   other._resident_data = resident_data;
   other._size = size;
   other._reserved_size = reserved_size;
-  other._block = block;
   nassertv(_reserved_size >= _size);
 }
 
@@ -94,13 +91,12 @@ do_clean_realloc(size_t reserved_size) {
       do_page_in();
     }
 
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size - (int)_reserved_size);
     if (_reserved_size == 0) {
       nassertv(_resident_data == (unsigned char *)NULL);
-      _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
+      _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size);
     } else {
       nassertv(_resident_data != (unsigned char *)NULL);
-      _resident_data = (unsigned char *)PANDA_REALLOC_ARRAY(_resident_data, reserved_size);
+      _resident_data = (unsigned char *)get_class_type().reallocate_array(_resident_data, reserved_size);
     }
     nassertv(_resident_data != (unsigned char *)NULL);
     _reserved_size = reserved_size;
@@ -129,16 +125,14 @@ do_unclean_realloc(size_t reserved_size) {
     if (_resident_data != (unsigned char *)NULL) {
       nassertv(_reserved_size != 0);
 
-      get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
-      PANDA_FREE_ARRAY(_resident_data);
+      get_class_type().deallocate_array(_resident_data);
       _resident_data = NULL;
       _reserved_size = 0;
     }
 
     if (reserved_size != 0) {
-      get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size);
       nassertv(_resident_data == (unsigned char *)NULL);
-      _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
+      _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size);
     }
 
     _reserved_size = reserved_size;
@@ -166,8 +160,7 @@ do_page_out(VertexDataBook &book) {
   if (_size == 0) {
     // It's an empty buffer.  Just deallocate it; don't bother to create a
     // block.
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
-    PANDA_FREE_ARRAY(_resident_data);
+    get_class_type().deallocate_array(_resident_data);
     _resident_data = NULL;
     _reserved_size = 0;
 
@@ -180,8 +173,7 @@ do_page_out(VertexDataBook &book) {
     nassertv(pointer != (unsigned char *)NULL);
     memcpy(pointer, _resident_data, _size);
 
-    get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
-    PANDA_FREE_ARRAY(_resident_data);
+    get_class_type().deallocate_array(_resident_data);
     _resident_data = NULL;
 
     _reserved_size = _size;
@@ -205,8 +197,7 @@ do_page_in() {
   nassertv(_block != (VertexDataBlock *)NULL);
   nassertv(_reserved_size == _size);
 
-  get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
-  _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(_size);
+  _resident_data = (unsigned char *)get_class_type().allocate_array(_size);
   nassertv(_resident_data != (unsigned char *)NULL);
 
   memcpy(_resident_data, _block->get_pointer(true), _size);

+ 2 - 2
panda/src/gobj/vertexDataBuffer.h

@@ -57,8 +57,8 @@ public:
   void operator = (const VertexDataBuffer &copy);
   INLINE ~VertexDataBuffer();
 
-  INLINE const unsigned char *get_read_pointer(bool force) const;
-  INLINE unsigned char *get_write_pointer();
+  INLINE const unsigned char *get_read_pointer(bool force) const RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
+  INLINE unsigned char *get_write_pointer() RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
 
   INLINE size_t get_size() const;
   INLINE size_t get_reserved_size() const;

+ 33 - 28
panda/src/grutil/meshDrawer.cxx

@@ -33,7 +33,7 @@
 TypeHandle MeshDrawer::_type_handle;
 
 PN_stdfloat randFloat() {
-  return ((PN_stdfloat) rand() / (PN_stdfloat) 0x7fffffff);
+  return ((PN_stdfloat)rand() / (PN_stdfloat)RAND_MAX);
 }
 
 /**
@@ -42,39 +42,43 @@ PN_stdfloat randFloat() {
 void MeshDrawer::generator(int budget) {
   // create enough triangles for budget:
   _vdata = new GeomVertexData(_root.get_name(), GeomVertexFormat::get_v3n3c4t2(), Geom::UH_static);//UH_dynamic);
-  GeomVertexWriter *tvertex = new GeomVertexWriter(_vdata, "vertex");
-  GeomVertexWriter *tnormal = new GeomVertexWriter(_vdata, "normal");
-  GeomVertexWriter *tuv = new GeomVertexWriter(_vdata, "texcoord");
-  GeomVertexWriter *tcolor = new GeomVertexWriter(_vdata, "color");
-  _prim = new GeomTriangles(Geom::UH_static);
-
-  // iterate and fill _up a geom with random data so that it will not be
-  // optimized out by panda3d system
-  for(int i = 0; i < budget; i++) {
-    for( int vert = 0; vert < 3; vert++) {
-      LVector3 vec3 = LVector3(randFloat()+1000,randFloat(),randFloat())*.001;
-      LVector4 vec4 = LVector4(1,1,1,randFloat());
-      LVector2 vec2 = LVector2(0,randFloat());
-      tvertex->add_data3(vec3);
-      tcolor->add_data4(vec4);
-      tuv->add_data2(vec2);
-      tnormal->add_data3(vec3);
+  _vdata->unclean_set_num_rows(budget * 3);
+
+  {
+    GeomVertexWriter tvertex(_vdata, "vertex");
+    GeomVertexWriter tnormal(_vdata, "normal");
+    GeomVertexWriter tuv(_vdata, "texcoord");
+    GeomVertexWriter tcolor(_vdata, "color");
+
+    // iterate and fill _up a geom with random data so that it will not be
+    // optimized out by panda3d system
+    for (int i = 0; i < budget; i++) {
+      for (int vert = 0; vert < 3; vert++) {
+        LVector3 vec3 = LVector3(randFloat()+1000,randFloat(),randFloat())*.001;
+        LVector4 vec4 = LVector4(1,1,1,randFloat());
+        LVector2 vec2 = LVector2(0,randFloat());
+        tvertex.set_data3(vec3);
+        tcolor.set_data4(vec4);
+        tuv.set_data2(vec2);
+        tnormal.set_data3(vec3);
+      }
     }
-    _prim->add_vertices(i * 3, i * 3 + 1, i * 3 + 2);
   }
+
   // create our node and attach it to this node path
+  _prim = new GeomTriangles(Geom::UH_static);
+  _prim->add_next_vertices(budget * 3);
   _prim->close_primitive();
   _geom = new Geom(_vdata);
   _geom->add_primitive(_prim);
-  _geomnode = new GeomNode("__MeshDrawer_GeomNode");
+  if (_geomnode == NULL) {
+    _geomnode = new GeomNode("__MeshDrawer_GeomNode");
+    _root.attach_new_node(_geomnode);
+  } else {
+    _geomnode->remove_all_geoms();
+  }
   _geomnode->add_geom(_geom);
-  _root.attach_new_node(_geomnode);
   _last_clear_index = budget;
-
-  delete tvertex;
-  delete tnormal;
-  delete tuv;
-  delete tcolor;
 }
 
 /**
@@ -451,8 +455,9 @@ link_segment(const LVector3 &pos, const LVector4 &frame,
   LVector3 cam_stop3d = _camera.get_relative_point(_render, stop);
   LPoint2 cam_stop2d = LVector2();
 
-  PT(Camera) camera = DCAST(Camera, _camera.node());
-  PT(Lens) lens = camera->get_lens();
+  const Camera *camera;
+  DCAST_INTO_V(camera, _camera.node());
+  const Lens *lens = camera->get_lens();
 
   lens->project(cam_start3d, cam_start2d);
   lens->project(cam_stop3d, cam_stop2d);

+ 1 - 1
panda/src/grutil/shaderTerrainMesh.cxx

@@ -528,7 +528,7 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat
   state = state->set_attrib(current_shader_attrib, 10000);
 
   // Emit chunk
-  CullableObject *object = new CullableObject(_chunk_geom, state, modelview_transform);
+  CullableObject *object = new CullableObject(_chunk_geom, move(state), move(modelview_transform));
   trav->get_cull_handler()->record_object(object, trav);
 
   // After rendering, increment the view index

+ 1 - 1
panda/src/linmath/lsimpleMatrix.h

@@ -58,7 +58,7 @@ private:
 #endif  // HAVE_EIGEN
 
 // This is as good a place as any to define this alignment macro.
-#if defined(LINMATH_ALIGN) && defined(HAVE_EIGEN) && defined(__AVX__)
+#if defined(LINMATH_ALIGN) && defined(HAVE_EIGEN) && defined(__AVX__) && defined(STDFLOAT_DOUBLE)
 #define ALIGN_LINMATH ALIGN_32BYTE
 #elif defined(LINMATH_ALIGN)
 #define ALIGN_LINMATH ALIGN_16BYTE

+ 3 - 1
panda/src/parametrics/hermiteCurve.h

@@ -163,7 +163,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    register_type(_type_handle, "HermiteCurve");
+    PiecewiseCurve::init_type();
+    register_type(_type_handle, "HermiteCurve",
+                  PiecewiseCurve::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 1 - 1
panda/src/pgraph/cullTraverserData.cxx

@@ -101,7 +101,7 @@ apply_transform_and_state(CullTraverser *trav,
   if (clip_plane_cull) {
     _cull_planes = _cull_planes->apply_state(trav, this,
                                              (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()),
-                                             DCAST(ClipPlaneAttrib, off_clip_planes),
+                                             (const ClipPlaneAttrib *)off_clip_planes,
                                              (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type()));
   }
 }

+ 20 - 5
panda/src/pgraph/cullableObject.I

@@ -26,11 +26,11 @@ CullableObject() {
  * render state and transform.
  */
 INLINE CullableObject::
-CullableObject(const Geom *geom, const RenderState *state,
-               const TransformState *internal_transform) :
-  _geom(geom),
-  _state(state),
-  _internal_transform(internal_transform)
+CullableObject(CPT(Geom) geom, CPT(RenderState) state,
+               CPT(TransformState) internal_transform) :
+  _geom(move(geom)),
+  _state(move(state)),
+  _internal_transform(move(internal_transform))
 {
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
@@ -135,6 +135,21 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread)
   _geom->draw(gsg, _munger, _munged_data, force, current_thread);
 }
 
+/**
+ * Invokes the draw callback, assuming one is set.  Crashes if not.
+ */
+INLINE void CullableObject::
+draw_callback(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) {
+  gsg->clear_before_callback();
+  gsg->set_state_and_transform(_state, _internal_transform);
+  GeomDrawCallbackData cbdata(this, gsg, force);
+  _draw_callback->do_callback(&cbdata);
+  if (cbdata.get_lost_state()) {
+    // Tell the GSG to forget its state.
+    gsg->clear_state_and_transform();
+  }
+}
+
 /**
  *
  */

+ 7 - 5
panda/src/pgraph/cullableObject.h

@@ -46,8 +46,8 @@ class EXPCL_PANDA_PGRAPH CullableObject
 {
 public:
   INLINE CullableObject();
-  INLINE CullableObject(const Geom *geom, const RenderState *state,
-                        const TransformState *internal_transform);
+  INLINE CullableObject(CPT(Geom) geom, CPT(RenderState) state,
+                        CPT(TransformState) internal_transform);
 
   INLINE CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
@@ -63,6 +63,11 @@ public:
 
   INLINE void set_draw_callback(CallbackObject *draw_callback);
 
+  INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
+                          bool force, Thread *current_thread);
+  INLINE void draw_callback(GraphicsStateGuardianBase *gsg,
+                            bool force, Thread *current_thread);
+
 public:
   ALLOC_DELETED_CHAIN(CullableObject);
 
@@ -82,9 +87,6 @@ private:
   static CPT(RenderState) get_flash_cpu_state();
   static CPT(RenderState) get_flash_hardware_state();
 
-  INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
-                          bool force, Thread *current_thread);
-
 private:
   // This class is used internally by munge_points_to_quads().
   class PointData {

+ 2 - 2
panda/src/pgraph/geomNode.cxx

@@ -515,7 +515,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
   CPT(TransformState) internal_transform = data.get_internal_transform(trav);
 
   for (int i = 0; i < num_geoms; i++) {
-    const Geom *geom = geoms.get_geom(i);
+    CPT(Geom) geom = geoms.get_geom(i);
     if (geom->is_empty()) {
       continue;
     }
@@ -558,7 +558,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
     }
 
     CullableObject *object =
-      new CullableObject(geom, state, internal_transform);
+      new CullableObject(move(geom), move(state), internal_transform);
     trav->get_cull_handler()->record_object(object, trav);
   }
 }

+ 5 - 7
panda/src/pgraph/geomTransformer.cxx

@@ -1243,16 +1243,14 @@ apply_collect_changes() {
 void GeomTransformer::NewCollectedData::
 append_vdata(const GeomVertexData *vdata, int vertex_offset) {
   for (int i = 0; i < vdata->get_num_arrays(); ++i) {
-    PT(GeomVertexArrayData) new_array = _new_data->modify_array(i);
-    CPT(GeomVertexArrayData) old_array = vdata->get_array(i);
+    PT(GeomVertexArrayDataHandle) new_handle = _new_data->modify_array_handle(i);
+    CPT(GeomVertexArrayDataHandle) old_handle = vdata->get_array_handle(i);
     size_t stride = (size_t)_new_format->get_array(i)->get_stride();
     size_t start_byte = (size_t)vertex_offset * stride;
-    size_t copy_bytes = old_array->get_data_size_bytes();
-    nassertv(start_byte + copy_bytes <= new_array->get_data_size_bytes());
+    size_t copy_bytes = old_handle->get_data_size_bytes();
+    nassertv(start_byte + copy_bytes <= new_handle->get_data_size_bytes());
 
-    new_array->modify_handle()->copy_subdata_from
-      (start_byte, copy_bytes,
-       old_array->get_handle(), 0, copy_bytes);
+    new_handle->copy_subdata_from(start_byte, copy_bytes, old_handle, 0, copy_bytes);
   }
 
   // Also, copy the animation data (if any).  This means combining transform

+ 2 - 4
panda/src/pgraph/pandaNode.h

@@ -799,12 +799,10 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedWritable::init_type();
-    ReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     Namable::init_type();
     register_type(_type_handle, "PandaNode",
-                  TypedWritable::get_class_type(),
-                  ReferenceCount::get_class_type(),
+                  TypedWritableReferenceCount::get_class_type(),
                   Namable::get_class_type());
     CData::init_type();
     Down::init_type();

+ 4 - 4
panda/src/pgraph/workingNodePath.I

@@ -43,10 +43,10 @@ WorkingNodePath(const WorkingNodePath &copy) :
  * traversal to the next node.
  */
 INLINE WorkingNodePath::
-WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) {
-  _next = &parent;
-  _start = (NodePathComponent *)NULL;
-  _node = child;
+WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) :
+  _next(&parent),
+  _start(nullptr),
+  _node(child) {
   nassertv(_node != _next->_node);
 }
 

+ 4 - 4
panda/src/pgraphnodes/shaderGenerator.h

@@ -151,9 +151,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedObject::init_type();
+    TypedReferenceCount::init_type();
     register_type(_type_handle, "ShaderGenerator",
-                  TypedObject::get_class_type());
+                  TypedReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();
@@ -173,9 +173,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedObject::init_type();
+    TypedReferenceCount::init_type();
     register_type(_type_handle, "ShaderGenerator",
-                  TypedObject::get_class_type());
+                  TypedReferenceCount::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 9 - 0
panda/src/pipeline/thread.I

@@ -73,7 +73,16 @@ get_unique_id() const {
  */
 INLINE int Thread::
 get_pipeline_stage() const {
+#if !defined(_DEBUG) && defined(__has_builtin) && __has_builtin(__builtin_assume)
+  // Because this is a signed int, this results in a sign extend on x86-64.
+  // However, since we guarantee that this is never less than zero, clang
+  // offers a nice way to avoid that.
+  int pipeline_stage = _pipeline_stage;
+  __builtin_assume(_pipeline_stage >= 0);
+  return pipeline_stage;
+#else
   return _pipeline_stage;
+#endif
 }
 
 /**

+ 18 - 6
panda/src/putil/copyOnWritePointer.I

@@ -166,7 +166,7 @@ operator < (const CopyOnWritePointer &other) const {
  * This flavor of the method is written for the non-threaded case.
  */
 INLINE const CopyOnWriteObject *CopyOnWritePointer::
-get_read_pointer() const {
+get_read_pointer(Thread *current_thread) const {
   return _cow_object;
 }
 #endif  // COW_THREADED
@@ -362,8 +362,14 @@ operator = (PointerTo<T> &&from) NOEXCEPT {
  */
 template<class T>
 INLINE CPT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
-get_read_pointer() const {
-  return (const To *)(CopyOnWritePointer::get_read_pointer().p());
+get_read_pointer(Thread *current_thread) const {
+  // This is necessary because we don't currently have a way to cast between
+  // two compatible PointerTo types without losing the reference count.
+  CPT(TYPENAME CopyOnWritePointerTo<T>::To) to;
+  CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread);
+  to.cheat() = (const To *)from.p();
+  from.cheat() = nullptr;
+  return to;
 }
 #else  // COW_THREADED
 /**
@@ -371,8 +377,8 @@ get_read_pointer() const {
  */
 template<class T>
 INLINE const TYPENAME CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<T>::
-get_read_pointer() const {
-  return (const To *)CopyOnWritePointer::get_read_pointer();
+get_read_pointer(Thread *current_thread) const {
+  return (const To *)CopyOnWritePointer::get_read_pointer(current_thread);
 }
 #endif  // COW_THREADED
 #endif  // CPPPARSER
@@ -385,7 +391,13 @@ get_read_pointer() const {
 template<class T>
 INLINE PT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
 get_write_pointer() {
-  return (To *)(CopyOnWritePointer::get_write_pointer().p());
+  // This is necessary because we don't currently have a way to cast between
+  // two compatible PointerTo types without losing the reference count.
+  PT(TYPENAME CopyOnWritePointerTo<T>::To) to;
+  PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer();
+  to.cheat() = (To *)from.p();
+  from.cheat() = nullptr;
+  return to;
 }
 #else  // COW_THREADED
 /**

+ 1 - 3
panda/src/putil/copyOnWritePointer.cxx

@@ -23,13 +23,11 @@
  * This flavor of the method is written for the threaded case.
  */
 CPT(CopyOnWriteObject) CopyOnWritePointer::
-get_read_pointer() const {
+get_read_pointer(Thread *current_thread) const {
   if (_cow_object == (CopyOnWriteObject *)NULL) {
     return NULL;
   }
 
-  Thread *current_thread = Thread::get_current_thread();
-
   MutexHolder holder(_cow_object->_lock_mutex);
   while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
     if (_cow_object->_locking_thread == current_thread) {

+ 4 - 4
panda/src/putil/copyOnWritePointer.h

@@ -48,10 +48,10 @@ public:
   INLINE bool operator < (const CopyOnWritePointer &other) const;
 
 #ifdef COW_THREADED
-  CPT(CopyOnWriteObject) get_read_pointer() const;
+  CPT(CopyOnWriteObject) get_read_pointer(Thread *current_thread) const;
   PT(CopyOnWriteObject) get_write_pointer();
 #else
-  INLINE const CopyOnWriteObject *get_read_pointer() const;
+  INLINE const CopyOnWriteObject *get_read_pointer(Thread *current_thread) const;
   INLINE CopyOnWriteObject *get_write_pointer();
 #endif  // COW_THREADED
 
@@ -93,10 +93,10 @@ public:
 #endif
 
 #ifdef COW_THREADED
-  INLINE CPT(To) get_read_pointer() const;
+  INLINE CPT(To) get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE PT(To) get_write_pointer();
 #else
-  INLINE const To *get_read_pointer() const;
+  INLINE const To *get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE To *get_write_pointer();
 #endif  // COW_THREADED
 

+ 4 - 4
panda/src/text/textAssembler.cxx

@@ -1142,7 +1142,6 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
     } else {
       tris->set_index_type(GeomEnums::NT_uint16);
     }
-    PT(GeomVertexArrayData) indices = tris->modify_vertices();
 
     int i = 0;
 
@@ -1150,9 +1149,10 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
     // bottleneck.  So, I've written this out the hard way instead.  Two
     // versions of the loop: one for 32-bit indices, one for 16-bit.
     {
-      PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array(0)->modify_handle();
+      PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array_handle(0);
       vtx_handle->unclean_set_num_rows(quads.size() * 4);
 
+      Thread *current_thread = Thread::get_current_thread();
       unsigned char *write_ptr = vtx_handle->get_write_pointer();
       size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32);
 
@@ -1163,7 +1163,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
 
       if (tris->get_index_type() == GeomEnums::NT_uint32) {
         // 32-bit index case.
-        PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle();
+        PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
         idx_handle->unclean_set_num_rows(quads.size() * 6);
         uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
 
@@ -1219,7 +1219,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
         }
       } else {
         // 16-bit index case.
-        PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle();
+        PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread);
         idx_handle->unclean_set_num_rows(quads.size() * 6);
         uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();
 

+ 2 - 4
panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx

@@ -2612,12 +2612,10 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) {
 
   if (gltex->total_bytecount != total_bytecount) {
     if (gltex->allocated_buffer != NULL) {
-      PANDA_FREE_ARRAY(gltex->allocated_buffer);
-      TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
+      TinyTextureContext::get_class_type().deallocate_array(gltex->allocated_buffer);
     }
-    gltex->allocated_buffer = PANDA_MALLOC_ARRAY(total_bytecount);
+    gltex->allocated_buffer = TinyTextureContext::get_class_type().allocate_array(total_bytecount);
     gltex->total_bytecount = total_bytecount;
-    TinyTextureContext::get_class_type().inc_memory_usage(TypeHandle::MC_array, total_bytecount);
   }
 
   char *next_buffer = (char *)gltex->allocated_buffer;

+ 2 - 4
panda/src/tinydisplay/tinyTextureContext.cxx

@@ -24,8 +24,7 @@ TinyTextureContext::
   GLTexture *gltex = &_gltex;
   if (gltex->allocated_buffer != NULL) {
     nassertv(gltex->num_levels != 0);
-    TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
-    PANDA_FREE_ARRAY(gltex->allocated_buffer);
+    get_class_type().deallocate_array(gltex->allocated_buffer);
     gltex->allocated_buffer = NULL;
     gltex->total_bytecount = 0;
     gltex->num_levels = 0;
@@ -51,8 +50,7 @@ evict_lru() {
   GLTexture *gltex = &_gltex;
   if (gltex->allocated_buffer != NULL) {
     nassertv(gltex->num_levels != 0);
-    TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
-    PANDA_FREE_ARRAY(gltex->allocated_buffer);
+    get_class_type().deallocate_array(gltex->allocated_buffer);
     gltex->allocated_buffer = NULL;
     gltex->total_bytecount = 0;
     gltex->num_levels = 0;

+ 6 - 6
samples/chessboard/main.py

@@ -20,7 +20,7 @@ from direct.showbase.DirectObject import DirectObject
 from direct.task.Task import Task
 import sys
 
-# First we define some contants for the colors
+# First we define some constants for the colors
 BLACK = (0, 0, 0, 1)
 WHITE = (1, 1, 1, 1)
 HIGHLIGHT = (0, 1, 1, 1)
@@ -33,7 +33,7 @@ PIECEBLACK = (.15, .15, .15, 1)
 # This is how we know where to position an object in 3D space based on a 2D mouse
 # position. It also assumes that we are dragging in the XY plane.
 #
-# This is derived from the mathmatical of a plane, solved for a given point
+# This is derived from the mathematical of a plane, solved for a given point
 def PointAtZ(z, point, vec):
     return point + vec * ((z - point.getZ()) / vec.getZ())
 
@@ -41,7 +41,7 @@ def PointAtZ(z, point, vec):
 def SquarePos(i):
     return LPoint3((i % 8) - 3.5, int(i // 8) - 3.5, 0)
 
-# Helper function for determining wheter a square should be white or black
+# Helper function for determining whether a square should be white or black
 # The modulo operations (%) generate the every-other pattern of a chess-board
 def SquareColor(i):
     if (i + ((i // 8) % 2)) % 2:
@@ -84,7 +84,7 @@ class ChessboardDemo(ShowBase):
         # relative to it
         self.pickerNP = camera.attachNewNode(self.pickerNode)
         # Everything to be picked will use bit 1. This way if we were doing other
-        # collision we could seperate it
+        # collision we could separate it
         self.pickerNode.setFromCollideMask(BitMask32.bit(1))
         self.pickerRay = CollisionRay()  # Make our ray
         # Add it to the collision node
@@ -96,7 +96,7 @@ class ChessboardDemo(ShowBase):
         # Now we create the chess board and its pieces
 
         # We will attach all of the squares to their own root. This way we can do the
-        # collision pass just on the sqaures and save the time of checking the rest
+        # collision pass just on the squares and save the time of checking the rest
         # of the scene
         self.squareRoot = render.attachNewNode("squareRoot")
 
@@ -240,7 +240,7 @@ class ChessboardDemo(ShowBase):
         render.setLight(render.attachNewNode(ambientLight))
 
 
-# Class for a piece. This just handels loading the model and setting initial
+# Class for a piece. This just handles loading the model and setting initial
 # position and color
 class Piece(object):
     def __init__(self, square, color):

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно