Browse Source

Merge branch 'master' into cmake

Sam Edwards 8 years ago
parent
commit
76a7c84330
93 changed files with 1553 additions and 1055 deletions
  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
 // Place this macro within a class definition to define appropriate operator
 // new and delete methods that take advantage of DeletedChain.
 // new and delete methods that take advantage of DeletedChain.
 #define ALLOC_DELETED_CHAIN(Type)                            \
 #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)); \
     return (void *)StaticDeletedChain< Type >::allocate(size, get_type_handle(Type)); \
   }                                                          \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \
   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
 // Use this variant of the above macro in cases in which the compiler fails to
 // unify the static template pointers properly, to prevent leaks.
 // unify the static template pointers properly, to prevent leaks.
 #define ALLOC_DELETED_CHAIN_DECL(Type)                       \
 #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)); \
     return (void *)_deleted_chain.allocate(size, get_type_handle(Type)); \
   }                                                          \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \
   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
 #define __has_builtin(x) 0
 #endif
 #endif
 
 
+#ifndef __has_attribute
+#define __has_attribute(x) 0
+#endif
+
 // Use NODEFAULT to optimize a switch() stmt to tell MSVC to automatically go
 // 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.
 // 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')
 // 'assume at least one of the cases is always true')
@@ -96,6 +100,12 @@
 #define ASSUME_ALIGNED(x, y) (x)
 #define ASSUME_ALIGNED(x, y) (x)
 #endif
 #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
   include win32 defns for everything up to WinServer2003, and assume
   I'm smart enough to use GetProcAddress for backward compat on
   I'm smart enough to use GetProcAddress for backward compat on
@@ -400,6 +410,35 @@ typedef struct _object PyObject;
 
 
 #endif
 #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. */
 /* Determine our memory-allocation requirements. */
 #if defined(USE_MEMORY_PTMALLOC2) || defined(USE_MEMORY_DLMALLOC) || defined(DO_MEMORY_USAGE) || defined(MEMORY_HOOK_DO_ALIGN)
 #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. */
 /* 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
 #ifndef USE_MEMORY_NOWRAPPERS
 
 
 #define ALLOC_MEMORY_BASE                                    \
 #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);                        \
     return PANDA_MALLOC_SINGLE(size);                        \
   }                                                          \
   }                                                          \
   inline void *operator new(size_t size, void *ptr) {        \
   inline void *operator new(size_t size, void *ptr) {        \
@@ -38,7 +38,7 @@
   }                                                          \
   }                                                          \
   inline void operator delete(void *, void *) {              \
   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);                         \
     return PANDA_MALLOC_ARRAY(size);                         \
   }                                                          \
   }                                                          \
   inline void *operator new[](size_t size, void *ptr) {      \
   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
  * 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::
 INLINE size_t MemoryHook::
 get_ptr_size(void *ptr) {
 get_ptr_size(void *ptr) {
 #if defined(MEMORY_HOOK_DO_ALIGN)
 #if defined(MEMORY_HOOK_DO_ALIGN)
   uintptr_t *root = (uintptr_t *)ptr;
   uintptr_t *root = (uintptr_t *)ptr;
   return (size_t)root[-2];
   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)
 #elif defined(DO_MEMORY_USAGE)
   size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
   size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT);
   return *root;
   return *root;
@@ -78,68 +88,3 @@ get_ptr_size(void *ptr) {
   return 0;
   return 0;
 #endif  // DO_MEMORY_USAGE
 #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 "memoryHook.h"
 #include "deletedBufferChain.h"
 #include "deletedBufferChain.h"
 #include <stdlib.h>
 #include <stdlib.h>
+#include "typeRegistry.h"
 
 
 #ifdef WIN32
 #ifdef WIN32
 
 
@@ -104,6 +105,83 @@ static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0,
 
 
 #endif  // USE_MEMORY_*
 #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
 #ifdef DO_MEMORY_USAGE
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // bytes on the heap.
   // 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);
   AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size);
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
@@ -204,8 +287,10 @@ heap_alloc_single(size_t size) {
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
 
 
   void *ptr = alloc_to_ptr(alloc, size);
   void *ptr = alloc_to_ptr(alloc, size);
+#ifdef _DEBUG
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
+#endif
   return ptr;
   return ptr;
 }
 }
 
 
@@ -265,6 +350,11 @@ heap_alloc_array(size_t size) {
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // In the DO_MEMORY_USAGE case, we want to track the total size of allocated
   // bytes on the heap.
   // 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);
   AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size);
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
   if ((size_t)AtomicAdjust::get(_total_heap_single_size) +
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
       (size_t)AtomicAdjust::get(_total_heap_array_size) >
@@ -274,8 +364,10 @@ heap_alloc_array(size_t size) {
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
 
 
   void *ptr = alloc_to_ptr(alloc, size);
   void *ptr = alloc_to_ptr(alloc, size);
+#ifdef _DEBUG
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
   assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size);
+#endif
   return ptr;
   return ptr;
 }
 }
 
 
@@ -287,11 +379,6 @@ heap_realloc_array(void *ptr, size_t size) {
   size_t orig_size;
   size_t orig_size;
   void *alloc = ptr_to_alloc(ptr, 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);
   size_t inflated_size = inflate_size(size);
 
 
   void *alloc1 = alloc;
   void *alloc1 = alloc;
@@ -318,6 +405,16 @@ heap_realloc_array(void *ptr, size_t size) {
 #endif
 #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.
   // Align this to the requested boundary.
 #ifdef MEMORY_HOOK_DO_ALIGN
 #ifdef MEMORY_HOOK_DO_ALIGN
   // This copies the code from alloc_to_ptr, since we can't write the size and
   // 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
 #else
   void *ptr1 = alloc_to_ptr(alloc1, size);
   void *ptr1 = alloc_to_ptr(alloc1, size);
 #endif
 #endif
+
+#ifdef _DEBUG
   assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
   assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size);
   assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
   assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0);
+#endif
   return ptr1;
   return ptr1;
 }
 }
 
 

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

@@ -20,22 +20,6 @@
 #include "mutexImpl.h"
 #include "mutexImpl.h"
 #include <map>
 #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;
 class DeletedBufferChain;
 
 
 /**
 /**
@@ -83,11 +67,6 @@ public:
 
 
   INLINE static size_t get_ptr_size(void *ptr);
   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
 #ifdef DO_MEMORY_USAGE
 protected:
 protected:
   TVOLATILE AtomicAdjust::Integer _total_heap_single_size;
   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>
 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) {
 allocate(TYPENAME pallocator_single<Type>::size_type n, TYPENAME allocator<void>::const_pointer) {
   TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
   TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER);
   // This doesn't support allocating arrays.
   // This doesn't support allocating arrays.
@@ -43,34 +43,14 @@ pallocator_array(TypeHandle type_handle) NOEXCEPT :
 }
 }
 
 
 template<class Type>
 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) {
 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>
 template<class Type>
 INLINE void pallocator_array<Type>::
 INLINE void pallocator_array<Type>::
 deallocate(TYPENAME pallocator_array<Type>::pointer p, TYPENAME pallocator_array<Type>::size_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 :
   INLINE pallocator_single(const pallocator_single<U> &copy) NOEXCEPT :
     _type_handle(copy._type_handle) { }
     _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);
   INLINE void deallocate(pointer p, size_type n);
 
 
   template<class U> struct rebind {
   template<class U> struct rebind {
@@ -87,7 +88,8 @@ public:
   INLINE pallocator_array(const pallocator_array<U> &copy) NOEXCEPT :
   INLINE pallocator_array(const pallocator_array<U> &copy) NOEXCEPT :
     _type_handle(copy._type_handle) { }
     _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);
   INLINE void deallocate(pointer p, size_type n);
 
 
   template<class U> struct rebind {
   template<class U> struct rebind {

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

@@ -18,7 +18,6 @@
 // This is initialized to zero by static initialization.
 // This is initialized to zero by static initialization.
 TypeHandle TypeHandle::_none;
 TypeHandle TypeHandle::_none;
 
 
-#ifdef DO_MEMORY_USAGE
 /**
 /**
  * Returns the total allocated memory used by objects of this type, for the
  * 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
  * indicated memory class.  This is only updated if track-memory-usage is set
@@ -26,6 +25,7 @@ TypeHandle TypeHandle::_none;
  */
  */
 size_t TypeHandle::
 size_t TypeHandle::
 get_memory_usage(MemoryClass memory_class) const {
 get_memory_usage(MemoryClass memory_class) const {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) == TypeHandle::none()) {
   if ((*this) == TypeHandle::none()) {
     return 0;
     return 0;
@@ -34,16 +34,17 @@ get_memory_usage(MemoryClass memory_class) const {
     assert(rnode != (TypeRegistryNode *)NULL);
     assert(rnode != (TypeRegistryNode *)NULL);
     return (size_t)AtomicAdjust::get(rnode->_memory_usage[memory_class]);
     return (size_t)AtomicAdjust::get(rnode->_memory_usage[memory_class]);
   }
   }
-}
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
+  return 0;
+}
 
 
-#ifdef DO_MEMORY_USAGE
 /**
 /**
  * Adds the indicated amount to the record for the total allocated memory for
  * Adds the indicated amount to the record for the total allocated memory for
  * objects of this type.
  * objects of this type.
  */
  */
 void TypeHandle::
 void TypeHandle::
 inc_memory_usage(MemoryClass memory_class, size_t size) {
 inc_memory_usage(MemoryClass memory_class, size_t size) {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
     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 << ") -> " <<
     // cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " <<
     // rnode->_memory_usage[memory_class] << "\n";
     // rnode->_memory_usage[memory_class] << "\n";
     if (rnode->_memory_usage[memory_class] < 0) {
     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();
       abort();
     }
     }
   }
   }
-}
 #endif  // DO_MEMORY_USAGE
 #endif  // DO_MEMORY_USAGE
+}
 
 
-#ifdef DO_MEMORY_USAGE
 /**
 /**
  * Subtracts the indicated amount from the record for the total allocated
  * Subtracts the indicated amount from the record for the total allocated
  * memory for objects of this type.
  * memory for objects of this type.
  */
  */
 void TypeHandle::
 void TypeHandle::
 dec_memory_usage(MemoryClass memory_class, size_t size) {
 dec_memory_usage(MemoryClass memory_class, size_t size) {
+#ifdef DO_MEMORY_USAGE
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit);
   if ((*this) != TypeHandle::none()) {
   if ((*this) != TypeHandle::none()) {
     TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
     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";
     // rnode->_memory_usage[memory_class] << "\n";
     assert(rnode->_memory_usage[memory_class] >= 0);
     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
 #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
  * Return the Index of the BEst fit Classs from a set

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

@@ -18,25 +18,49 @@
 
 
 #include <set>
 #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;
 class TypedObject;
@@ -97,15 +121,9 @@ PUBLISHED:
 
 
   int get_best_parent_from_Set(const std::set< int > &legal_vals) const;
   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;
   size_t get_memory_usage(MemoryClass memory_class) const;
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void inc_memory_usage(MemoryClass memory_class, size_t size);
   void dec_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 int get_index() const;
   INLINE void output(ostream &out) const;
   INLINE void output(ostream &out) const;
@@ -118,6 +136,10 @@ PUBLISHED:
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
   MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class);
 
 
 public:
 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);
   INLINE static TypeHandle from_index(int index);
 
 
 private:
 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.
  * Ensures the lock pointer has been allocated.
  */
  */

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

@@ -488,20 +488,6 @@ write(ostream &out) const {
   _lock->release();
   _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::
 void TypeRegistry::
 init_global_pointer() {
 init_global_pointer() {
+  init_lock();
   init_memory_hook();
   init_memory_hook();
   _global_pointer = new TypeRegistry;
   _global_pointer = new TypeRegistry;
 }
 }

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

@@ -77,7 +77,7 @@ PUBLISHED:
   void write(ostream &out) const;
   void write(ostream &out) const;
 
 
   // ptr() returns the pointer to the global TypeRegistry object.
   // 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(typehandles, get_num_typehandles, get_typehandle);
   MAKE_SEQ_PROPERTY(root_classes, get_num_root_classes, get_root_class);
   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);
     dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
 
 
     while (map != NULL) {
     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
       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
         _dtool_name = head;
         _dtool_name = head;
@@ -615,8 +615,8 @@ read_args() {
       char buffer[PATH_MAX];
       char buffer[PATH_MAX];
       buffer[0] = 0;
       buffer[0] = 0;
       maps.getline(buffer, PATH_MAX);
       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
       if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
                         || strcmp(tail, "/libp3dtool.so") == 0)) {
         _dtool_name = head;
         _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;
     pattern = source;
   } else {
   } else {
     pattern = source.substr(0, slash);
     pattern = source.substr(0, slash);
-    suffix = source.substr(slash + 1);
+    suffix = source.substr(slash);
   }
   }
 
 
   GlobPattern glob(pattern);
   GlobPattern glob(pattern);
@@ -118,11 +118,21 @@ r_match_files(const Filename &prefix, const string &suffix,
   size_t slash = suffix.find('/');
   size_t slash = suffix.find('/');
   if (slash == string::npos) {
   if (slash == string::npos) {
     next_pattern = suffix;
     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 {
   } else {
     next_pattern = suffix.substr(0, slash);
     next_pattern = suffix.substr(0, slash);
     next_suffix = suffix.substr(slash + 1);
     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;
   Filename parent_dir;
   if (prefix.is_local() && !cwd.empty()) {
   if (prefix.is_local() && !cwd.empty()) {
     parent_dir = Filename(cwd, prefix);
     parent_dir = Filename(cwd, prefix);
@@ -136,19 +146,24 @@ r_match_files(const Filename &prefix, const string &suffix,
   if (!has_glob_characters()) {
   if (!has_glob_characters()) {
     // If there are no special characters in the pattern, it's a literal
     // If there are no special characters in the pattern, it's a literal
     // match.
     // match.
+    Filename fn(parent_dir, _pattern);
     if (suffix.empty()) {
     if (suffix.empty()) {
       // Time to stop.
       // Time to stop.
-      Filename single_filename(parent_dir, _pattern);
-      if (single_filename.exists()) {
+      if (fn.exists()) {
         results.push_back(Filename(prefix, _pattern));
         results.push_back(Filename(prefix, _pattern));
         return 1;
         return 1;
       }
       }
       return 0;
       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
   // 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.
   // the pattern.
   int num_matched = 0;
   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;
   vector_string::const_iterator fi;
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
   for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) {
     const string &local_file = (*fi);
     const string &local_file = (*fi);
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
     if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) {
       if (matches(local_file)) {
       if (matches(local_file)) {
         // We have a match; continue.
         // 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));
           results.push_back(Filename(prefix, local_file));
           num_matched++;
           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
 #else
   set_system_tag("eigen", "vectorize", "0");
   set_system_tag("eigen", "vectorize", "0");
 #endif
 #endif
+#ifdef __AVX__
+  set_system_tag("eigen", "avx", "1");
+#else
+  set_system_tag("eigen", "avx", "0");
+#endif
 #endif  // HAVE_EIGEN
 #endif  // HAVE_EIGEN
 
 
 #ifdef USE_MEMORY_DLMALLOC
 #ifdef USE_MEMORY_DLMALLOC
@@ -189,6 +194,14 @@ is_official_version() {
 #endif
 #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
  * 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-
  * "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 int get_sequence_version();
   static bool is_official_version();
   static bool is_official_version();
 
 
+  static int get_memory_alignment();
+
   static string get_distributor();
   static string get_distributor();
   static string get_compiler();
   static string get_compiler();
   static string get_build_date();
   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
     // 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).
     // tuple other than unpack it (which is a fairly safe assumption to make).
     out << "  PyTupleObject args;\n";
     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 <<
   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.
 // Functions related to error reporting.
 EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred();
 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
 #ifdef NDEBUG
-// _PyErr_OCCURRED is an undocumented inline version of PyErr_Occurred.
 #define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL)
 #define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL)
 #else
 #else
 #define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred()
 #define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred()

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

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

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

@@ -2,13 +2,14 @@
 #ifndef SSL_H
 #ifndef SSL_H
 #define 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;
 struct SSL;
 #define STACK_OF(type) struct stack_st_##type
 #define STACK_OF(type) struct stack_st_##type
 
 

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

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

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

@@ -21,6 +21,7 @@
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
 #include "openssl/rand.h"
 #include "openssl/rand.h"
+#include "openssl/evp.h"
 
 
 #ifndef HAVE_STREAMSIZE
 #ifndef HAVE_STREAMSIZE
 // Some compilers (notably SGI) don't define this for us
 // 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.
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
-#include "openssl/evp.h"
+typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX;
 
 
 /**
 /**
  * The streambuf object that implements IDecompressStream and OCompressStream.
  * The streambuf object that implements IDecompressStream and OCompressStream.

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

@@ -19,8 +19,12 @@
 
 
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
+#include "openssl/evp.h"
 #include "openssl/pem.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;
 PrcKeyRegistry *PrcKeyRegistry::_global_ptr = NULL;
 
 
 /**
 /**

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

@@ -22,10 +22,8 @@
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
 #include <vector>
 #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
  * 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")
     DefSymbol("ALWAYS", "ANDROID")
 
 
 if not PkgSkip("EIGEN"):
 if not PkgSkip("EIGEN"):
-    DefSymbol("ALWAYS", "EIGEN_MPL2_ONLY")
     if GetOptimize() >= 3:
     if GetOptimize() >= 3:
-        DefSymbol("ALWAYS", "EIGEN_NO_DEBUG")
         if COMPILER == "MSVC":
         if COMPILER == "MSVC":
             # Squeeze out a bit more performance on MSVC builds...
             # Squeeze out a bit more performance on MSVC builds...
             # Only do this if EIGEN_NO_DEBUG is also set, otherwise it
             # 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"
         cmd += " -fno-strict-aliasing"
 
 
         if optlevel >= 3:
         if optlevel >= 3:
-            cmd += " -ffast-math"
+            cmd += " -ffast-math -fno-stack-protector"
         if optlevel == 3:
         if optlevel == 3:
             # Fast math is nice, but we'd like to see NaN in dev builds.
             # Fast math is nice, but we'd like to see NaN in dev builds.
             cmd += " -fno-finite-math-only"
             cmd += " -fno-finite-math-only"

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

@@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) {
 void CullBinBackToFront::
 void CullBinBackToFront::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     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::
 void CullBinFixed::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     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::
 void CullBinFrontToBack::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     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::
 void CullBinStateSorted::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::const_iterator oi;
   Objects::const_iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*oi)._object;
     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::
 void CullBinUnsorted::
 draw(bool force, Thread *current_thread) {
 draw(bool force, Thread *current_thread) {
   PStatTimer timer(_draw_this_pcollector, current_thread);
   PStatTimer timer(_draw_this_pcollector, current_thread);
+
+  GeomPipelineReader geom_reader(current_thread);
+  GeomVertexDataPipelineReader data_reader(current_thread);
+
   Objects::iterator oi;
   Objects::iterator oi;
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
   for (oi = _objects.begin(); oi != _objects.end(); ++oi) {
     CullableObject *object = (*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;
     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;
   PT(Texture) tex = new Texture;
 
 
   RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(),
   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();
   GraphicsStateGuardian *gsg = win->get_gsg();
   nassertv(gsg != (GraphicsStateGuardian *)NULL);
   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) {
   if (scene_setup == (SceneSetup *)NULL) {
     // Never mind.
     // Never mind.
 
 
-  } else if (dr_reader->get_object()->is_stereo()) {
+  } else if (dr->is_stereo()) {
     // Don't draw stereo DisplayRegions directly.
     // Don't draw stereo DisplayRegions directly.
 
 
   } else if (!gsg->set_scene(scene_setup)) {
   } else if (!gsg->set_scene(scene_setup)) {
@@ -1353,9 +1356,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
   } else {
   } else {
     DrawCullHandler cull_handler(gsg);
     DrawCullHandler cull_handler(gsg);
     if (gsg->begin_scene()) {
     if (gsg->begin_scene()) {
-      delete dr_reader;
-      dr_reader = NULL;
-
       CallbackObject *cbobj = dr->get_cull_callback();
       CallbackObject *cbobj = dr->get_cull_callback();
       if (cbobj != (CallbackObject *)NULL) {
       if (cbobj != (CallbackObject *)NULL) {
         // Issue the cull callback on this DisplayRegion.
         // Issue the cull callback on this DisplayRegion.
@@ -1372,10 +1372,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr,
       gsg->end_scene();
       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) {
   for (size_t wi = 0; wi < wlist_size; ++wi) {
     GraphicsOutput *win = wlist[wi];
     GraphicsOutput *win = wlist[wi];
     if (win->is_active() && win->get_gsg()->is_active()) {
     if (win->is_active() && win->get_gsg()->is_active()) {
+      GraphicsStateGuardian *gsg = win->get_gsg();
       PStatTimer timer(win->get_cull_window_pcollector(), current_thread);
       PStatTimer timer(win->get_cull_window_pcollector(), current_thread);
       int num_display_regions = win->get_num_active_display_regions();
       int num_display_regions = win->get_num_active_display_regions();
       for (int i = 0; i < num_display_regions; ++i) {
       for (int i = 0; i < num_display_regions; ++i) {
         DisplayRegion *dr = win->get_active_display_region(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;
           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
             // We have not used this camera already in this thread.  Perform
             // the cull operation.
             // 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;
             (*aci).second = dr;
-            cull_to_bins(win, dr, current_thread);
+            cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread);
 
 
           } else {
           } else {
             // We have already culled a scene using this camera in this
             // 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
             // image.)  Of course, the cull result will be the same, so just
             // use the result from the other DisplayRegion.
             // use the result from the other DisplayRegion.
             DisplayRegion *other_dr = (*aci).second;
             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.
  * Called only within the inner loop of cull_to_bins(), above.
  */
  */
 void GraphicsEngine::
 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) {
           for (int i = 0; i < num_display_regions; ++i) {
             DisplayRegion *dr = win->get_active_display_region(i);
             DisplayRegion *dr = win->get_active_display_region(i);
             if (dr != (DisplayRegion *)NULL) {
             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
  * 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.
  * 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.
  * Draws the previously-culled scene.
  */
  */
 void GraphicsEngine::
 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
   // Statistics
   PStatGPUTimer timer(gsg, dr->get_draw_region_pcollector(), current_thread);
   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);
     DisplayRegionPipelineReader dr_reader(dr, current_thread);
     win->change_scenes(&dr_reader);
     win->change_scenes(&dr_reader);

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

@@ -147,9 +147,10 @@ private:
                               Thread *current_thread);
                               Thread *current_thread);
 
 
   void cull_to_bins(const Windows &wlist, 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(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 make_contexts(const Windows &wlist, Thread *current_thread);
 
 
   void process_events(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,
   PT(SceneSetup) setup_scene(GraphicsStateGuardian *gsg,
                              DisplayRegionPipelineReader *dr);
                              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,
   void do_add_window(GraphicsOutput *window,
                      const GraphicsThreadingModel &threading_model);
                      const GraphicsThreadingModel &threading_model);

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

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

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

@@ -538,6 +538,14 @@ get_supports_depth_stencil() const {
   return _supports_depth_stencil;
   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
  * Returns true if this particular GSG supports the filter mode FT_shadow for
  * depth textures.
  * depth textures.

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

@@ -253,6 +253,9 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system,
   _supports_geometry_instancing = false;
   _supports_geometry_instancing = false;
   _supports_indirect_draw = 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.
   // Assume a maximum of 1 render target in absence of MRT.
   _max_color_targets = 1;
   _max_color_targets = 1;
   _supports_dual_source_blending = false;
   _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_generate_mipmap() const;
   INLINE bool get_supports_depth_texture() const;
   INLINE bool get_supports_depth_texture() const;
   INLINE bool get_supports_depth_stencil() 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_shadow_filter() const;
   INLINE bool get_supports_sampler_objects() const;
   INLINE bool get_supports_sampler_objects() const;
   INLINE bool get_supports_basic_shaders() 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_generate_mipmap, get_supports_generate_mipmap);
   MAKE_PROPERTY(supports_depth_texture, get_supports_depth_texture);
   MAKE_PROPERTY(supports_depth_texture, get_supports_depth_texture);
   MAKE_PROPERTY(supports_depth_stencil, get_supports_depth_stencil);
   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_shadow_filter, get_supports_shadow_filter);
   MAKE_PROPERTY(supports_sampler_objects, get_supports_sampler_objects);
   MAKE_PROPERTY(supports_sampler_objects, get_supports_sampler_objects);
   MAKE_PROPERTY(supports_basic_shaders, get_supports_basic_shaders);
   MAKE_PROPERTY(supports_basic_shaders, get_supports_basic_shaders);
@@ -597,6 +599,7 @@ protected:
   bool _supports_generate_mipmap;
   bool _supports_generate_mipmap;
   bool _supports_depth_texture;
   bool _supports_depth_texture;
   bool _supports_depth_stencil;
   bool _supports_depth_stencil;
+  bool _supports_luminance_texture;
   bool _supports_shadow_filter;
   bool _supports_shadow_filter;
   bool _supports_sampler_objects;
   bool _supports_sampler_objects;
   bool _supports_basic_shaders;
   bool _supports_basic_shaders;

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

@@ -18,14 +18,6 @@ INLINE BioPtr::
 BioPtr(BIO *bio) : _bio(bio) {
 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 "urlSpec.h"
 #include "config_downloader.h"
 #include "config_downloader.h"
 
 
+#include "openSSLWrapper.h"  // must be included before any other openssl.
+#include "openssl/ssl.h"
+
 #ifdef _WIN32
 #ifdef _WIN32
 #include <winsock2.h>
 #include <winsock2.h>
 #else
 #else
@@ -199,7 +202,7 @@ connect() {
 
 
     if (result != 0 && BIO_sock_should_retry(-1)) {
     if (result != 0 && BIO_sock_should_retry(-1)) {
       // It's still in progress; we should retry later.  This causes
       // 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);
       BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY);
       _connecting = true;
       _connecting = true;
       return false;
       return false;
@@ -218,6 +221,14 @@ connect() {
   return true;
   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.
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "referenceCount.h"
 #include "referenceCount.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 #include <winsock2.h>
 #include <winsock2.h>
@@ -35,6 +29,8 @@
 #include <netinet/in.h>
 #include <netinet/in.h>
 #endif
 #endif
 
 
+typedef struct bio_st BIO;
+
 class URLSpec;
 class URLSpec;
 
 
 /**
 /**
@@ -52,7 +48,7 @@ public:
   void set_nbio(bool nbio);
   void set_nbio(bool nbio);
   bool connect();
   bool connect();
 
 
-  INLINE bool should_retry() const;
+  bool should_retry() const;
 
 
   INLINE BIO &operator *() const;
   INLINE BIO &operator *() 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.
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "bioPtr.h"
 #include "bioPtr.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
-#include "openSSLWrapper.h"  // must be included before any other openssl.
-#include "openssl/ssl.h"
 
 
 /**
 /**
  * The streambuf object that implements IBioStream.
  * 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.
 // This module is not compiled if OpenSSL is not available.
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
-#ifndef OPENSSL_NO_KRB5
-#define OPENSSL_NO_KRB5
-#endif
-
 #include "bioStream.h"
 #include "bioStream.h"
 #include "referenceCount.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
  * 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
 #ifdef HAVE_OPENSSL
 
 
+#include "openSSLWrapper.h"
+
 #if defined(WIN32_VC) || defined(WIN64_VC)
 #if defined(WIN32_VC) || defined(WIN64_VC)
   #include <WinSock2.h>
   #include <WinSock2.h>
   #include <windows.h>  // for select()
   #include <windows.h>  // for select()

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

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

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

@@ -24,6 +24,8 @@
 
 
 #ifdef HAVE_OPENSSL
 #ifdef HAVE_OPENSSL
 
 
+#include "openSSLWrapper.h"
+
 PT(HTTPClient) HTTPClient::_global_ptr;
 PT(HTTPClient) HTTPClient::_global_ptr;
 
 
 /**
 /**
@@ -68,6 +70,68 @@ tokenize(const string &str, vector_string &words, const string &delimiters) {
   words.push_back(string());
   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);
   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 "pmap.h"
 #include "pset.h"
 #include "pset.h"
 #include "referenceCount.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 Filename;
 class HTTPChannel;
 class HTTPChannel;
@@ -155,12 +159,6 @@ private:
 
 
   static void split_whitespace(string &a, string &b, const string &c);
   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 pvector<URLSpec> Proxies;
   typedef pmap<string, Proxies> ProxiesByScheme;
   typedef pmap<string, Proxies> ProxiesByScheme;
   ProxiesByScheme _proxies_by_scheme;
   ProxiesByScheme _proxies_by_scheme;

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

@@ -132,8 +132,7 @@ allocate_ibuffer(DXScreenData &scrn,
       dxgsg9_cat.debug()
       dxgsg9_cat.debug()
         << "creating index buffer " << _ibuffer << ": "
         << "creating index buffer " << _ibuffer << ": "
         << reader->get_num_vertices() << " indices ("
         << 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())) {
       } else if (child->is_of_type(CollisionSphere::get_class_type())) {
         CPT(CollisionSphere) sphere = DCAST(CollisionSphere, child);
         CPT(CollisionSphere) sphere = DCAST(CollisionSphere, child);
         LPoint3 center = sphere->get_center();
         LPoint3 center = sphere->get_center();
-        LVector3 offset(sphere->get_radius(), 0, 0);
+        PN_stdfloat radius = sphere->get_radius();
 
 
         EggGroup *egg_sphere;
         EggGroup *egg_sphere;
         if (num_solids == 1) {
         if (num_solids == 1) {
@@ -499,15 +499,19 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path,
         }
         }
         egg_sphere->set_collide_flags(flags);
         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;
         EggPolygon *egg_poly = new EggPolygon;
         egg_sphere->add_child(egg_poly);
         egg_sphere->add_child(egg_poly);
 
 
         egg_poly->add_vertex(cvpool->create_unique_vertex(ev1));
         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(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())) {
       } else if (child->is_of_type(CollisionPlane::get_class_type())) {
         LPlane plane = DCAST(CollisionPlane, child)->get_plane();
         LPlane plane = DCAST(CollisionPlane, child)->get_plane();

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

@@ -26,6 +26,8 @@
 #include <iterator>
 #include <iterator>
 #include <time.h>
 #include <time.h>
 
 
+#include "openSSLWrapper.h"
+
 // This sequence of bytes begins each Multifile to identify it as a Multifile.
 // This sequence of bytes begins each Multifile to identify it as a Multifile.
 const char Multifile::_header[] = "pmf\0\n\r";
 const char Multifile::_header[] = "pmf\0\n\r";
 const size_t Multifile::_header_size = 6;
 const size_t Multifile::_header_size = 6;
@@ -768,43 +770,6 @@ add_signature(const Filename &composite, const string &password) {
 }
 }
 #endif  // HAVE_OPENSSL
 #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
 #ifdef HAVE_OPENSSL
 /**
 /**
  * Adds a new signature to the Multifile.  This signature associates the
  * 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 "indirectLess.h"
 #include "referenceCount.h"
 #include "referenceCount.h"
 #include "pvector.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.
  * A file that contains a set of files.
@@ -148,7 +152,6 @@ public:
   };
   };
   typedef pvector<CertRecord> CertChain;
   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);
   bool add_signature(const CertChain &chain, EVP_PKEY *pkey);
 
 
   const CertChain &get_signature(int n) const;
   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) {
     if (cgGetParameterBaseResource(p) == CG_ATTR0) {
       // The Cg toolkit claims that it is bound to a generic vertex attribute.
       // 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
         // This is where the Cg glslv compiler lies, making the stupid
         // assumption that we're using an NVIDIA card where generic attributes
         // assumption that we're using an NVIDIA card where generic attributes
         // are aliased with conventional vertex attributes.  Instead, it
         // 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.
       // A conventional texture coordinate set.
       loc = CA_texcoord + cgGetParameterResourceIndex(p);
       loc = CA_texcoord + cgGetParameterResourceIndex(p);
 
 
-    } else {
+    } else if (_glgsg->has_fixed_function_pipeline()) {
       // Some other conventional vertex attribute.
       // Some other conventional vertex attribute.
       switch (res) {
       switch (res) {
       case CG_POSITION0:
       case CG_POSITION0:
@@ -276,6 +276,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte
         GLCAT.error(false) << ".\n";
         GLCAT.error(false) << ".\n";
         loc = CA_unknown;
         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
 #ifndef NDEBUG
@@ -916,8 +924,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
       } else {
       } else {
         // There is no vertex column with this name; disable the attribute
         // There is no vertex column with this name; disable the attribute
         // array.
         // 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
           // NOTE: if we disable attribute 0 in compatibility profile, the
           // object will disappear.  In GLSL we fix this by forcing the vertex
           // 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.
           // 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);
             _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);
           _glgsg->disable_vertex_attrib_array(p);
 
 
           if (p == _color_attrib_index) {
           if (p == _color_attrib_index) {

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

@@ -95,8 +95,7 @@ clear(Thread *current_thread) {
     return;
     return;
   }
   }
 
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
 
   if (glgsg->_glClearBufferfv == NULL) {
   if (glgsg->_glClearBufferfv == NULL) {
     // We can't efficiently clear the buffer.  Fall back to the inefficient
     // 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.
     // until we call glBlitFramebuffer.
 #ifndef OPENGLES_1
 #ifndef OPENGLES_1
     if (gl_enable_memory_barriers && _fbo_multisample == 0) {
     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;
       TextureContexts::iterator it;
       for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
       for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
@@ -269,6 +267,9 @@ begin_frame(FrameMode mode, Thread *current_thread) {
       }
       }
     }
     }
 #endif
 #endif
+  } else if (mode == FM_refresh) {
+    // Just bind the FBO.
+    rebuild_bitplanes();
   }
   }
 
 
   _gsg->set_current_properties(&get_fb_properties());
   _gsg->set_current_properties(&get_fb_properties());
@@ -282,8 +283,7 @@ begin_frame(FrameMode mode, Thread *current_thread) {
  */
  */
 bool CLP(GraphicsBuffer)::
 bool CLP(GraphicsBuffer)::
 check_fbo() {
 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);
   GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT);
   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
   if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
@@ -338,8 +338,7 @@ rebuild_bitplanes() {
     return;
     return;
   }
   }
 
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
 
   if (!_needs_rebuild) {
   if (!_needs_rebuild) {
     if (_fbo_multisample != 0) {
     if (_fbo_multisample != 0) {
@@ -682,8 +681,7 @@ rebuild_bitplanes() {
  */
  */
 void CLP(GraphicsBuffer)::
 void CLP(GraphicsBuffer)::
 bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
 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];
   Texture *tex = attach[slot];
 
 
@@ -1017,8 +1015,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
  */
  */
 void CLP(GraphicsBuffer)::
 void CLP(GraphicsBuffer)::
 bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) {
 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)) {
   if ((_rbm[slot] != 0)&&(!rb_resize)) {
     return;
     return;
@@ -1141,8 +1138,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot,
  */
  */
 void CLP(GraphicsBuffer)::
 void CLP(GraphicsBuffer)::
 attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
 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()) {
   if (view >= attach->get_num_views()) {
     attach->set_num_views(view + 1);
     attach->set_num_views(view + 1);
@@ -1162,8 +1158,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
   glgsg->apply_texture(gtc);
   glgsg->apply_texture(gtc);
 
 
 #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION)
 #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
 #endif
 
 
 #ifndef OPENGLES
 #ifndef OPENGLES
@@ -1210,8 +1208,7 @@ generate_mipmaps() {
     return;
     return;
   }
   }
 
 
-  CLP(GraphicsStateGuardian) *glgsg;
-  DCAST_INTO_V(glgsg, _gsg);
+  CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
 
 
   // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector);
   // 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
   // Unbind the FBO.  TODO: calling bind_fbo is slow, so we should probably
   // move this to begin_frame to prevent unnecessary calls.
   // 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);
   glgsg->bind_fbo(0);
   _bound_tex_page = -1;
   _bound_tex_page = -1;
 
 
@@ -1288,8 +1284,7 @@ void CLP(GraphicsBuffer)::
 select_target_tex_page(int page) {
 select_target_tex_page(int page) {
   nassertv(page >= 0 && page < _fbo.size());
   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);
   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";
       GLCAT.error() << file << ", line " << line << ": GL error " << (int)error_code << "\n";
     }
     }
   } else {
   } else {
-    CLP(GraphicsStateGuardian) *glgsg;
-    DCAST_INTO_V(glgsg, _gsg);
+    CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p();
     glgsg->report_my_errors(line, file);
     glgsg->report_my_errors(line, file);
   }
   }
 }
 }
@@ -1718,8 +1712,7 @@ void CLP(GraphicsBuffer)::
 resolve_multisamples() {
 resolve_multisamples() {
   nassertv(_fbo.size() > 0);
   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);
   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;
   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.
  * Calls glFinish() if the config variable gl-finish is set True.
  */
  */
@@ -363,7 +390,7 @@ enable_line_smooth(bool val) {
 INLINE void CLP(GraphicsStateGuardian)::
 INLINE void CLP(GraphicsStateGuardian)::
 enable_point_smooth(bool val) {
 enable_point_smooth(bool val) {
 #ifdef SUPPORT_FIXED_FUNCTION
 #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());
     _state_mask.clear_bit(TransparencyAttrib::get_class_slot());
     _point_smooth_enabled = val;
     _point_smooth_enabled = val;
     if (val) {
     if (val) {

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

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

@@ -51,7 +51,7 @@ get_geom_rendering() const {
 INLINE CPT(GeomVertexData) Geom::
 INLINE CPT(GeomVertexData) Geom::
 get_vertex_data(Thread *current_thread) const {
 get_vertex_data(Thread *current_thread) const {
   CDReader cdata(_cycler, current_thread);
   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
 #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::
 INLINE GeomPipelineReader::
 ~GeomPipelineReader() {
 ~GeomPipelineReader() {
 #ifdef _DEBUG
 #ifdef _DEBUG
-  nassertv(_object->test_ref_count_nonzero());
+  if (_object != nullptr) {
+    nassertv(_object->test_ref_count_nonzero());
+  }
 #endif // _DEBUG
 #endif // _DEBUG
   // _object->_cycler.release_read(_cdata);
   // _object->_cycler.release_read(_cdata);
 
 
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
-  unref_delete((CycleData *)_cdata);
+  if (_cdata != nullptr) {
+    unref_delete((CycleData *)_cdata);
+  }
 #endif  // DO_PIPELINING
 #endif  // DO_PIPELINING
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG
@@ -567,6 +567,30 @@ INLINE GeomPipelineReader::
 #endif  // _DEBUG
 #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;
   int num_changed = 0;
 
 
   CDWriter cdata(_cycler, true, current_thread);
   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);
   PT(GeomVertexData) new_data = new GeomVertexData(*orig_data);
   new_data->clear_rows();
   new_data->clear_rows();
 
 
@@ -247,7 +247,7 @@ make_nonindexed(bool composite_only) {
   Primitives new_prims;
   Primitives new_prims;
   new_prims.reserve(cdata->_primitives.size());
   new_prims.reserve(cdata->_primitives.size());
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) {
   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());
     new_prims.push_back(primitive.p());
 
 
     // GeomPoints are considered "composite" for the purposes of making
     // 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();
   Thread *current_thread = Thread::get_current_thread();
   CDWriter cdata(_cycler, true, current_thread);
   CDWriter cdata(_cycler, true, current_thread);
   nassertv(i >= 0 && i < (int)cdata->_primitives.size());
   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
   // All primitives within a particular Geom must have the same fundamental
   // primitive type (triangles, points, or lines).
   // primitive type (triangles, points, or lines).
@@ -339,7 +339,7 @@ add_primitive(const GeomPrimitive *primitive) {
   Thread *current_thread = Thread::get_current_thread();
   Thread *current_thread = Thread::get_current_thread();
   CDWriter cdata(_cycler, true, 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
   // All primitives within a particular Geom must have the same fundamental
   // primitive type (triangles, points, or lines).
   // primitive type (triangles, points, or lines).
@@ -426,11 +426,11 @@ decompose_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -460,11 +460,11 @@ doubleside_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -494,11 +494,11 @@ reverse_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -528,11 +528,11 @@ rotate_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -596,7 +596,7 @@ unify_in_place(int max_indices, bool preserve_order) {
 
 
   Primitives::const_iterator pi;
   Primitives::const_iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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());
     NewPrims::iterator npi = new_prims.find(primitive->get_type());
     if (npi == new_prims.end()) {
     if (npi == new_prims.end()) {
       // This is the first primitive of this type.
       // 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) {
   for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) {
     GeomPrimitive *prim = (*npi).second;
     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.
     // Each new primitive, naturally, inherits the Geom's overall shade model.
     prim->set_shade_model(cdata->_shade_model);
     prim->set_shade_model(cdata->_shade_model);
@@ -706,11 +706,11 @@ make_lines_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -740,11 +740,11 @@ make_points_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -774,11 +774,11 @@ make_patches_in_place() {
 #endif
 #endif
   Primitives::iterator pi;
   Primitives::iterator pi;
   for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++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();
     (*pi) = (GeomPrimitive *)new_prim.p();
 
 
 #ifndef NDEBUG
 #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;
       all_is_valid = false;
     }
     }
 #endif
 #endif
@@ -865,7 +865,9 @@ get_num_bytes() const {
  */
  */
 bool Geom::
 bool Geom::
 request_resident() const {
 request_resident() const {
-  CDReader cdata(_cycler);
+  Thread *current_thread = Thread::get_current_thread();
+
+  CDReader cdata(_cycler, current_thread);
 
 
   bool resident = true;
   bool resident = true;
 
 
@@ -873,7 +875,7 @@ request_resident() const {
   for (pi = cdata->_primitives.begin();
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        pi != cdata->_primitives.end();
        ++pi) {
        ++pi) {
-    if (!(*pi).get_read_pointer()->request_resident()) {
+    if (!(*pi).get_read_pointer(current_thread)->request_resident()) {
       resident = false;
       resident = false;
     }
     }
   }
   }
@@ -1197,7 +1199,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const {
   int num_vertices = 0;
   int num_vertices = 0;
 
 
   // Get the vertex data, after animation.
   // 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);
   vertex_data = vertex_data->animate_vertices(true, current_thread);
 
 
   // Now actually compute the bounding volume.  We do this by using
   // 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();
     for (pi = cdata->_primitives.begin();
          pi != cdata->_primitives.end();
          pi != cdata->_primitives.end();
          ++pi) {
          ++pi) {
-      CPT(GeomPrimitive) prim = (*pi).get_read_pointer();
+      CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread);
       num_vertices += prim->get_num_vertices();
       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();
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        pi != cdata->_primitives.end();
        ++pi) {
        ++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,
     prim->calc_tight_bounds(min_point, max_point, sq_center_dist,
                             found_any, vertex_data, got_mat, mat,
                             found_any, vertex_data, got_mat, mat,
                             column_name, current_thread);
                             column_name, current_thread);
@@ -1345,7 +1347,7 @@ do_calc_sphere_radius(const LPoint3 &center, PN_stdfloat &sq_radius,
   for (pi = cdata->_primitives.begin();
   for (pi = cdata->_primitives.begin();
        pi != cdata->_primitives.end();
        pi != cdata->_primitives.end();
        ++pi) {
        ++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,
     prim->calc_sphere_radius(center, sq_radius, found_any,
                              vertex_data, current_thread);
                              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);
     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();
   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();
   for (pi = _cdata->_primitives.begin();
        pi != _cdata->_primitives.end();
        pi != _cdata->_primitives.end();
        ++pi) {
        ++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();
     reader.check_minmax();
     if (!reader.check_valid(data_reader)) {
     if (!reader.check_valid(data_reader)) {
       return false;
       return false;
@@ -1707,12 +1710,11 @@ draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger,
     for (pi = _cdata->_primitives.begin();
     for (pi = _cdata->_primitives.begin();
          pi != _cdata->_primitives.end();
          pi != _cdata->_primitives.end();
          ++pi) {
          ++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) {
       if (reader.get_num_vertices() != 0) {
         reader.check_minmax();
         reader.check_minmax();
         nassertr(reader.check_valid(data_reader), false);
         nassertr(reader.check_valid(data_reader), false);
-        if (!primitive->draw(gsg, &reader, force)) {
+        if (!reader.draw(gsg, force)) {
           all_ok = false;
           all_ok = false;
         }
         }
       }
       }

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

@@ -401,15 +401,17 @@ private:
  */
  */
 class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
 class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums {
 public:
 public:
+  INLINE GeomPipelineReader(Thread *current_thread);
   INLINE GeomPipelineReader(const Geom *object, Thread *current_thread);
   INLINE GeomPipelineReader(const Geom *object, Thread *current_thread);
 private:
 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:
 public:
   INLINE ~GeomPipelineReader();
   INLINE ~GeomPipelineReader();
   ALLOC_DELETED_CHAIN(GeomPipelineReader);
   ALLOC_DELETED_CHAIN(GeomPipelineReader);
 
 
+  INLINE void set_object(const Geom *object);
   INLINE const Geom *get_object() const;
   INLINE const Geom *get_object() const;
   INLINE Thread *get_current_thread() const;
   INLINE Thread *get_current_thread() const;
 
 

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

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

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

@@ -235,6 +235,24 @@ get_vertices() const {
   return cdata->_vertices.get_read_pointer();
   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,
  * A convenience function to return the gap between successive index numbers,
  * in bytes, of the index data.
  * in bytes, of the index data.
@@ -414,38 +432,32 @@ CData(const GeomPrimitive::CData &copy) :
  *
  *
  */
  */
 INLINE GeomPrimitivePipelineReader::
 INLINE GeomPrimitivePipelineReader::
-GeomPrimitivePipelineReader(const GeomPrimitive *object,
+GeomPrimitivePipelineReader(CPT(GeomPrimitive) object,
                             Thread *current_thread) :
                             Thread *current_thread) :
-  _object(object),
+  _object(move(object)),
   _current_thread(current_thread),
   _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());
   nassertv(_object->test_ref_count_nonzero());
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
   _cdata->ref();
   _cdata->ref();
 #endif  // DO_PIPELINING
 #endif  // DO_PIPELINING
+
   if (!_cdata->_vertices.is_null()) {
   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);
   unref_delete((CycleData *)_cdata);
 #endif  // DO_PIPELINING
 #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
 #ifdef _DEBUG
-  _vertices_reader = NULL;
   _object = NULL;
   _object = NULL;
   _cdata = NULL;
   _cdata = NULL;
 #endif  // _DEBUG
 #endif  // _DEBUG
@@ -512,7 +533,7 @@ get_index_type() const {
  */
  */
 INLINE bool GeomPrimitivePipelineReader::
 INLINE bool GeomPrimitivePipelineReader::
 is_indexed() const {
 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) {
   if (_cdata->_num_vertices != -1) {
     return _cdata->_num_vertices;
     return _cdata->_num_vertices;
   } else {
   } 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::
 INLINE int GeomPrimitivePipelineReader::
 get_data_size_bytes() const {
 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::
 INLINE int GeomPrimitivePipelineReader::
 get_index_stride() const {
 get_index_stride() const {
   nassertr(is_indexed(), 0);
   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::
 INLINE const unsigned char *GeomPrimitivePipelineReader::
 get_read_pointer(bool force) const {
 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);
   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 &
 INLINE ostream &
 operator << (ostream &out, const GeomPrimitive &obj) {
 operator << (ostream &out, const GeomPrimitive &obj) {
   obj.output(out);
   obj.output(out);

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

@@ -1036,23 +1036,23 @@ get_num_bytes() const {
  * shortly; try again later.
  * shortly; try again later.
  */
  */
 bool GeomPrimitive::
 bool GeomPrimitive::
-request_resident() const {
-  CDReader cdata(_cycler);
+request_resident(Thread *current_thread) const {
+  CDReader cdata(_cycler, current_thread);
 
 
   bool resident = true;
   bool resident = true;
 
 
   if (!cdata->_vertices.is_null() &&
   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;
     resident = false;
   }
   }
 
 
   if (is_composite() && cdata->_got_minmax) {
   if (is_composite() && cdata->_got_minmax) {
     if (!cdata->_mins.is_null() &&
     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;
       resident = false;
     }
     }
     if (!cdata->_maxs.is_null() &&
     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;
       resident = false;
     }
     }
   }
   }
@@ -2178,14 +2178,17 @@ check_minmax() const {
  */
  */
 int GeomPrimitivePipelineReader::
 int GeomPrimitivePipelineReader::
 get_first_vertex() const {
 get_first_vertex() const {
-  if (_cdata->_vertices.is_null()) {
+  if (_vertices.is_null()) {
     return _cdata->_first_vertex;
     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;
     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::
 int GeomPrimitivePipelineReader::
 get_vertex(int i) const {
 get_vertex(int i) const {
-  if (!_cdata->_vertices.is_null()) {
+  if (!_vertices.is_null()) {
     // The indexed case.
     // 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);
     index.set_row_unsafe(i);
     return index.get_data1i();
     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(data_size_bytes, get_data_size_bytes);
   MAKE_PROPERTY(modified, get_modified);
   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;
   INLINE bool check_valid(const GeomVertexData *vertex_data) const;
 
 
@@ -162,7 +162,9 @@ PUBLISHED:
  */
  */
 
 
   INLINE CPT(GeomVertexArrayData) get_vertices() const;
   INLINE CPT(GeomVertexArrayData) get_vertices() const;
+  INLINE CPT(GeomVertexArrayDataHandle) get_vertices_handle(Thread *current_thread) const;
   PT(GeomVertexArrayData) modify_vertices(int num_vertices = -1);
   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_vertices(const GeomVertexArrayData *vertices, int num_vertices = -1);
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
   void set_nonindexed_vertices(int first_vertex, int num_vertices);
 
 
@@ -347,10 +349,10 @@ private:
  */
  */
 class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums {
 class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums {
 public:
 public:
-  INLINE GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread);
+  INLINE GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread);
 private:
 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:
 public:
   INLINE ~GeomPrimitivePipelineReader();
   INLINE ~GeomPrimitivePipelineReader();
@@ -375,7 +377,6 @@ public:
   INLINE UpdateSeq get_modified() const;
   INLINE UpdateSeq get_modified() const;
   bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
   bool check_valid(const GeomVertexDataPipelineReader *data_reader) const;
   INLINE int get_index_stride() 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 const unsigned char *get_read_pointer(bool force) const;
   INLINE int get_strip_cut_index() const;
   INLINE int get_strip_cut_index() const;
   INLINE CPTA_int get_ends() const;
   INLINE CPTA_int get_ends() const;
@@ -384,13 +385,15 @@ public:
 
 
   INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
   INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects,
                                          GraphicsStateGuardianBase *gsg) const;
                                          GraphicsStateGuardianBase *gsg) const;
+  INLINE bool draw(GraphicsStateGuardianBase *gsg, bool force) const;
 
 
 private:
 private:
   CPT(GeomPrimitive) _object;
   CPT(GeomPrimitive) _object;
   Thread *_current_thread;
   Thread *_current_thread;
   const GeomPrimitive::CData *_cdata;
   const GeomPrimitive::CData *_cdata;
 
 
-  CPT(GeomVertexArrayDataHandle) _vertices_reader;
+  CPT(GeomVertexArrayData) _vertices;
+  const GeomVertexArrayData::CData *_vertices_cdata;
 
 
 public:
 public:
   static TypeHandle get_class_type() {
   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.
  * back into memory shortly; try again later.
  */
  */
 INLINE bool GeomVertexArrayData::
 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::
 INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData::
 get_handle(Thread *current_thread) const {
 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::
 INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData::
 modify_handle(Thread *current_thread) {
 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::
 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),
   _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
 #ifdef _DEBUG
   nassertv(_object->test_ref_count_nonzero());
   nassertv(_object->test_ref_count_nonzero());
 #endif // _DEBUG
 #endif // _DEBUG
@@ -265,7 +313,8 @@ GeomVertexArrayDataHandle(const GeomVertexArrayData *object,
  * Don't attempt to copy these objects.
  * Don't attempt to copy these objects.
  */
  */
 INLINE GeomVertexArrayDataHandle::
 INLINE GeomVertexArrayDataHandle::
-GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy) {
+GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &copy)
+  : _current_thread(copy._current_thread) {
   nassertv(false);
   nassertv(false);
 }
 }
 
 
@@ -448,7 +497,7 @@ get_subdata(size_t start, size_t size) const {
  */
  */
 void GeomVertexArrayDataHandle::
 void GeomVertexArrayDataHandle::
 mark_used() const {
 mark_used() const {
-  _object->set_lru_size(_object->get_lru_size());
+  _object->mark_used();
 }
 }
 
 
 INLINE ostream &
 INLINE ostream &

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

@@ -95,7 +95,7 @@ PUBLISHED:
   void output(ostream &out) const;
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) 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 CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const;
   INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread());
   INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread());
@@ -124,6 +124,7 @@ public:
 
 
 private:
 private:
   INLINE void set_lru_size(size_t lru_size);
   INLINE void set_lru_size(size_t lru_size);
+  INLINE void mark_used();
 
 
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
   void reverse_data_endianness(unsigned char *dest,
   void reverse_data_endianness(unsigned char *dest,
@@ -230,6 +231,7 @@ private:
   friend class GeomVertexData;
   friend class GeomVertexData;
   friend class PreparedGraphicsObjects;
   friend class PreparedGraphicsObjects;
   friend class GeomVertexArrayDataHandle;
   friend class GeomVertexArrayDataHandle;
+  friend class GeomPrimitivePipelineReader;
 };
 };
 
 
 /**
 /**
@@ -246,10 +248,10 @@ private:
  */
  */
 class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums {
 class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums {
 private:
 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 GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &);
   INLINE void operator = (const GeomVertexArrayDataHandle &);
   INLINE void operator = (const GeomVertexArrayDataHandle &);
 
 
@@ -261,8 +263,8 @@ public:
 
 
   INLINE Thread *get_current_thread() const;
   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:
 PUBLISHED:
   INLINE const GeomVertexArrayData *get_object() const;
   INLINE const GeomVertexArrayData *get_object() const;
@@ -316,7 +318,7 @@ PUBLISHED:
 
 
 private:
 private:
   PT(GeomVertexArrayData) _object;
   PT(GeomVertexArrayData) _object;
-  Thread *_current_thread;
+  Thread *const _current_thread;
   GeomVertexArrayData::CData *_cdata;
   GeomVertexArrayData::CData *_cdata;
   bool _writable;
   bool _writable;
 
 
@@ -333,6 +335,11 @@ public:
 private:
 private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
+  friend class Geom;
+  friend class GeomPrimitive;
+  friend class GeomVertexData;
+  friend class GeomVertexDataPipelineReader;
+  friend class GeomVertexDataPipelineWriter;
   friend class GeomVertexArrayData;
   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();
   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
  * Returns a modifiable pointer to the indicated vertex array, so that
  * application code may directly manipulate the data.  You should avoid
  * application code may directly manipulate the data.  You should avoid
@@ -162,6 +173,16 @@ modify_array(int i) {
   return writer.modify_array(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
  * 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
  * 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::
 INLINE GeomVertexDataPipelineBase::
 ~GeomVertexDataPipelineBase() {
 ~GeomVertexDataPipelineBase() {
 #ifdef _DEBUG
 #ifdef _DEBUG
-  nassertv(_object->test_ref_count_nonzero());
+  if (_object != nullptr) {
+    nassertv(_object->test_ref_count_nonzero());
+  }
 #endif // _DEBUG
 #endif // _DEBUG
 
 
 #ifdef DO_PIPELINING
 #ifdef DO_PIPELINING
-  unref_delete((CycleData *)_cdata);
+  if (_cdata != nullptr) {
+    unref_delete((CycleData *)_cdata);
+  }
 #endif  // DO_PIPELINING
 #endif  // DO_PIPELINING
 
 
 #ifdef _DEBUG
 #ifdef _DEBUG
@@ -698,41 +734,41 @@ get_modified() const {
  *
  *
  */
  */
 INLINE GeomVertexDataPipelineReader::
 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)
   _got_array_readers(false)
 {
 {
 }
 }
 
 
 /**
 /**
- * Don't attempt to copy these objects.
+ *
  */
  */
 INLINE GeomVertexDataPipelineReader::
 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
 #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) {
         if (keep_data_objects) {
           // Copy the data, but keep the same GeomVertexArrayData object.
           // 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 {
         } else {
           // Copy the GeomVertexArrayData object.
           // Copy the GeomVertexArrayData object.
           if (get_array(dest_i) != source->get_array(source_i)) {
           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.
   // 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.
   // Now go back through and copy any data that's left over.
   for (source_i = 0; source_i < num_arrays; ++source_i) {
   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 unsigned char *array_data = array_handle->get_read_pointer(true);
     const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
     const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
     int num_columns = source_array_format->get_num_columns();
     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)) {
         if (dest_column->is_bytewise_equivalent(*source_column)) {
           // We can do a quick bytewise copy.
           // 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();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
           bytewise_copy(dest_array_data + dest_column->get_start(),
           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() &&
         } else if (dest_column->is_packed_argb() &&
                    source_column->is_uint8_rgba()) {
                    source_column->is_uint8_rgba()) {
           // A common special case: OpenGL color to DirectX color.
           // 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();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
           uint8_rgba_to_packed_argb
           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() &&
         } else if (dest_column->is_uint8_rgba() &&
                    source_column->is_packed_argb()) {
                    source_column->is_packed_argb()) {
           // Another common special case: DirectX color to OpenGL color.
           // 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();
           unsigned char *dest_array_data = dest_handle->get_write_pointer();
 
 
           packed_argb_to_uint8_rgba
           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();
   int num_arrays = source_format->get_num_arrays();
 
 
   for (int i = 0; i < num_arrays; ++i) {
   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();
     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 unsigned char *source_array_data = source_array_handle->get_read_pointer(true);
 
 
     const GeomVertexArrayFormat *array_format = source_format->get_array(i);
     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);
   packer->set_data4f(buffer, color);
 #endif
 #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 *write_ptr = handle->get_write_pointer();
   unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes();
   unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes();
   write_ptr += column->get_start();
   write_ptr += column->get_start();
@@ -1586,7 +1581,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
   }
   }
 
 
   // Then apply the transforms.
   // 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) {
   if (tb_table != (TransformBlendTable *)NULL) {
     // Recompute all the blends up front, so we don't have to test each one
     // Recompute all the blends up front, so we don't have to test each one
     // for staleness at each vertex.
     // 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 &&
     if (blend_array_format->get_stride() == 2 &&
         blend_array_format->get_column(0)->get_component_bytes() == 2) {
         blend_array_format->get_column(0)->get_component_bytes() == 2) {
       // The blend indices are a table of ushorts.  Optimize this common case.
       // 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);
       const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true);
 
 
       size_t ci;
       size_t ci;
@@ -2399,24 +2395,12 @@ make_array_readers() {
   _array_readers.reserve(_cdata->_arrays.size());
   _array_readers.reserve(_cdata->_arrays.size());
   GeomVertexData::Arrays::const_iterator ai;
   GeomVertexData::Arrays::const_iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++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;
   _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();
   _cdata->_animated_vertices_modified = UpdateSeq();
 
 
   if (_got_array_writers) {
   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());
   _array_writers.reserve(_cdata->_arrays.size());
   GeomVertexData::Arrays::iterator ai;
   GeomVertexData::Arrays::iterator ai;
   for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++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();
   _object->clear_cache_stage();

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

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

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

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

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

@@ -212,7 +212,7 @@ private:
 
 
   int _start_row;
   int _start_row;
 
 
-#ifndef NDEBUG
+#ifdef _DEBUG
   // This is defined just for the benefit of having something non-NULL to
   // This is defined just for the benefit of having something non-NULL to
   // return from a nassertr() call.
   // return from a nassertr() call.
   static unsigned char empty_buffer[100];
   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) {
   if (_resident_data != (unsigned char *)NULL) {
     nassertv(_reserved_size != 0);
     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;
     _resident_data = NULL;
   }
   }
   if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) {
   if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) {
     // We only allocate _size bytes, not the full _reserved_size allocated by
     // We only allocate _size bytes, not the full _reserved_size allocated by
     // the original copy.
     // 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);
     memcpy(_resident_data, copy._resident_data, copy._size);
   }
   }
   _size = copy._size;
   _size = copy._size;
@@ -55,17 +53,16 @@ swap(VertexDataBuffer &other) {
   unsigned char *resident_data = _resident_data;
   unsigned char *resident_data = _resident_data;
   size_t size = _size;
   size_t size = _size;
   size_t reserved_size = _reserved_size;
   size_t reserved_size = _reserved_size;
-  PT(VertexDataBlock) block = _block;
+
+  _block.swap(other._block);
 
 
   _resident_data = other._resident_data;
   _resident_data = other._resident_data;
   _size = other._size;
   _size = other._size;
   _reserved_size = other._reserved_size;
   _reserved_size = other._reserved_size;
-  _block = other._block;
 
 
   other._resident_data = resident_data;
   other._resident_data = resident_data;
   other._size = size;
   other._size = size;
   other._reserved_size = reserved_size;
   other._reserved_size = reserved_size;
-  other._block = block;
   nassertv(_reserved_size >= _size);
   nassertv(_reserved_size >= _size);
 }
 }
 
 
@@ -94,13 +91,12 @@ do_clean_realloc(size_t reserved_size) {
       do_page_in();
       do_page_in();
     }
     }
 
 
-    get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size - (int)_reserved_size);
     if (_reserved_size == 0) {
     if (_reserved_size == 0) {
       nassertv(_resident_data == (unsigned char *)NULL);
       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 {
     } else {
       nassertv(_resident_data != (unsigned char *)NULL);
       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);
     nassertv(_resident_data != (unsigned char *)NULL);
     _reserved_size = reserved_size;
     _reserved_size = reserved_size;
@@ -129,16 +125,14 @@ do_unclean_realloc(size_t reserved_size) {
     if (_resident_data != (unsigned char *)NULL) {
     if (_resident_data != (unsigned char *)NULL) {
       nassertv(_reserved_size != 0);
       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;
       _resident_data = NULL;
       _reserved_size = 0;
       _reserved_size = 0;
     }
     }
 
 
     if (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);
       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;
     _reserved_size = reserved_size;
@@ -166,8 +160,7 @@ do_page_out(VertexDataBook &book) {
   if (_size == 0) {
   if (_size == 0) {
     // It's an empty buffer.  Just deallocate it; don't bother to create a
     // It's an empty buffer.  Just deallocate it; don't bother to create a
     // block.
     // 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;
     _resident_data = NULL;
     _reserved_size = 0;
     _reserved_size = 0;
 
 
@@ -180,8 +173,7 @@ do_page_out(VertexDataBook &book) {
     nassertv(pointer != (unsigned char *)NULL);
     nassertv(pointer != (unsigned char *)NULL);
     memcpy(pointer, _resident_data, _size);
     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;
     _resident_data = NULL;
 
 
     _reserved_size = _size;
     _reserved_size = _size;
@@ -205,8 +197,7 @@ do_page_in() {
   nassertv(_block != (VertexDataBlock *)NULL);
   nassertv(_block != (VertexDataBlock *)NULL);
   nassertv(_reserved_size == _size);
   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);
   nassertv(_resident_data != (unsigned char *)NULL);
 
 
   memcpy(_resident_data, _block->get_pointer(true), _size);
   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);
   void operator = (const VertexDataBuffer &copy);
   INLINE ~VertexDataBuffer();
   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_size() const;
   INLINE size_t get_reserved_size() const;
   INLINE size_t get_reserved_size() const;

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

@@ -33,7 +33,7 @@
 TypeHandle MeshDrawer::_type_handle;
 TypeHandle MeshDrawer::_type_handle;
 
 
 PN_stdfloat randFloat() {
 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) {
 void MeshDrawer::generator(int budget) {
   // create enough triangles for budget:
   // create enough triangles for budget:
   _vdata = new GeomVertexData(_root.get_name(), GeomVertexFormat::get_v3n3c4t2(), Geom::UH_static);//UH_dynamic);
   _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
   // 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();
   _prim->close_primitive();
   _geom = new Geom(_vdata);
   _geom = new Geom(_vdata);
   _geom->add_primitive(_prim);
   _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);
   _geomnode->add_geom(_geom);
-  _root.attach_new_node(_geomnode);
   _last_clear_index = budget;
   _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);
   LVector3 cam_stop3d = _camera.get_relative_point(_render, stop);
   LPoint2 cam_stop2d = LVector2();
   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_start3d, cam_start2d);
   lens->project(cam_stop3d, cam_stop2d);
   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);
   state = state->set_attrib(current_shader_attrib, 10000);
 
 
   // Emit chunk
   // 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);
   trav->get_cull_handler()->record_object(object, trav);
 
 
   // After rendering, increment the view index
   // After rendering, increment the view index

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

@@ -58,7 +58,7 @@ private:
 #endif  // HAVE_EIGEN
 #endif  // HAVE_EIGEN
 
 
 // This is as good a place as any to define this alignment macro.
 // 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
 #define ALIGN_LINMATH ALIGN_32BYTE
 #elif defined(LINMATH_ALIGN)
 #elif defined(LINMATH_ALIGN)
 #define ALIGN_LINMATH ALIGN_16BYTE
 #define ALIGN_LINMATH ALIGN_16BYTE

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

@@ -163,7 +163,9 @@ public:
     return _type_handle;
     return _type_handle;
   }
   }
   static void init_type() {
   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 {
   virtual TypeHandle get_type() const {
     return get_class_type();
     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) {
   if (clip_plane_cull) {
     _cull_planes = _cull_planes->apply_state(trav, this,
     _cull_planes = _cull_planes->apply_state(trav, this,
                                              (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()),
                                              (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()));
                                              (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.
  * render state and transform.
  */
  */
 INLINE CullableObject::
 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
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
   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);
   _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:
 public:
   INLINE CullableObject();
   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 CullableObject(const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
   INLINE void operator = (const CullableObject &copy);
@@ -63,6 +63,11 @@ public:
 
 
   INLINE void set_draw_callback(CallbackObject *draw_callback);
   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:
 public:
   ALLOC_DELETED_CHAIN(CullableObject);
   ALLOC_DELETED_CHAIN(CullableObject);
 
 
@@ -82,9 +87,6 @@ private:
   static CPT(RenderState) get_flash_cpu_state();
   static CPT(RenderState) get_flash_cpu_state();
   static CPT(RenderState) get_flash_hardware_state();
   static CPT(RenderState) get_flash_hardware_state();
 
 
-  INLINE void draw_inline(GraphicsStateGuardianBase *gsg,
-                          bool force, Thread *current_thread);
-
 private:
 private:
   // This class is used internally by munge_points_to_quads().
   // This class is used internally by munge_points_to_quads().
   class PointData {
   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);
   CPT(TransformState) internal_transform = data.get_internal_transform(trav);
 
 
   for (int i = 0; i < num_geoms; i++) {
   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()) {
     if (geom->is_empty()) {
       continue;
       continue;
     }
     }
@@ -558,7 +558,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) {
     }
     }
 
 
     CullableObject *object =
     CullableObject *object =
-      new CullableObject(geom, state, internal_transform);
+      new CullableObject(move(geom), move(state), internal_transform);
     trav->get_cull_handler()->record_object(object, trav);
     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::
 void GeomTransformer::NewCollectedData::
 append_vdata(const GeomVertexData *vdata, int vertex_offset) {
 append_vdata(const GeomVertexData *vdata, int vertex_offset) {
   for (int i = 0; i < vdata->get_num_arrays(); ++i) {
   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 stride = (size_t)_new_format->get_array(i)->get_stride();
     size_t start_byte = (size_t)vertex_offset * 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
   // 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;
     return _type_handle;
   }
   }
   static void init_type() {
   static void init_type() {
-    TypedWritable::init_type();
-    ReferenceCount::init_type();
+    TypedWritableReferenceCount::init_type();
     Namable::init_type();
     Namable::init_type();
     register_type(_type_handle, "PandaNode",
     register_type(_type_handle, "PandaNode",
-                  TypedWritable::get_class_type(),
-                  ReferenceCount::get_class_type(),
+                  TypedWritableReferenceCount::get_class_type(),
                   Namable::get_class_type());
                   Namable::get_class_type());
     CData::init_type();
     CData::init_type();
     Down::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.
  * traversal to the next node.
  */
  */
 INLINE WorkingNodePath::
 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);
   nassertv(_node != _next->_node);
 }
 }
 
 

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

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

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

@@ -73,7 +73,16 @@ get_unique_id() const {
  */
  */
 INLINE int Thread::
 INLINE int Thread::
 get_pipeline_stage() const {
 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;
   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.
  * This flavor of the method is written for the non-threaded case.
  */
  */
 INLINE const CopyOnWriteObject *CopyOnWritePointer::
 INLINE const CopyOnWriteObject *CopyOnWritePointer::
-get_read_pointer() const {
+get_read_pointer(Thread *current_thread) const {
   return _cow_object;
   return _cow_object;
 }
 }
 #endif  // COW_THREADED
 #endif  // COW_THREADED
@@ -362,8 +362,14 @@ operator = (PointerTo<T> &&from) NOEXCEPT {
  */
  */
 template<class T>
 template<class T>
 INLINE CPT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<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
 #else  // COW_THREADED
 /**
 /**
@@ -371,8 +377,8 @@ get_read_pointer() const {
  */
  */
 template<class T>
 template<class T>
 INLINE const TYPENAME CopyOnWritePointerTo<T>::To *CopyOnWritePointerTo<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  // COW_THREADED
 #endif  // CPPPARSER
 #endif  // CPPPARSER
@@ -385,7 +391,13 @@ get_read_pointer() const {
 template<class T>
 template<class T>
 INLINE PT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
 INLINE PT(TYPENAME CopyOnWritePointerTo<T>::To) CopyOnWritePointerTo<T>::
 get_write_pointer() {
 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
 #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.
  * This flavor of the method is written for the threaded case.
  */
  */
 CPT(CopyOnWriteObject) CopyOnWritePointer::
 CPT(CopyOnWriteObject) CopyOnWritePointer::
-get_read_pointer() const {
+get_read_pointer(Thread *current_thread) const {
   if (_cow_object == (CopyOnWriteObject *)NULL) {
   if (_cow_object == (CopyOnWriteObject *)NULL) {
     return NULL;
     return NULL;
   }
   }
 
 
-  Thread *current_thread = Thread::get_current_thread();
-
   MutexHolder holder(_cow_object->_lock_mutex);
   MutexHolder holder(_cow_object->_lock_mutex);
   while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
   while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) {
     if (_cow_object->_locking_thread == current_thread) {
     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;
   INLINE bool operator < (const CopyOnWritePointer &other) const;
 
 
 #ifdef COW_THREADED
 #ifdef COW_THREADED
-  CPT(CopyOnWriteObject) get_read_pointer() const;
+  CPT(CopyOnWriteObject) get_read_pointer(Thread *current_thread) const;
   PT(CopyOnWriteObject) get_write_pointer();
   PT(CopyOnWriteObject) get_write_pointer();
 #else
 #else
-  INLINE const CopyOnWriteObject *get_read_pointer() const;
+  INLINE const CopyOnWriteObject *get_read_pointer(Thread *current_thread) const;
   INLINE CopyOnWriteObject *get_write_pointer();
   INLINE CopyOnWriteObject *get_write_pointer();
 #endif  // COW_THREADED
 #endif  // COW_THREADED
 
 
@@ -93,10 +93,10 @@ public:
 #endif
 #endif
 
 
 #ifdef COW_THREADED
 #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();
   INLINE PT(To) get_write_pointer();
 #else
 #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();
   INLINE To *get_write_pointer();
 #endif  // COW_THREADED
 #endif  // COW_THREADED
 
 

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

@@ -1142,7 +1142,6 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) {
     } else {
     } else {
       tris->set_index_type(GeomEnums::NT_uint16);
       tris->set_index_type(GeomEnums::NT_uint16);
     }
     }
-    PT(GeomVertexArrayData) indices = tris->modify_vertices();
 
 
     int i = 0;
     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
     // 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.
     // 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);
       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();
       unsigned char *write_ptr = vtx_handle->get_write_pointer();
       size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32);
       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) {
       if (tris->get_index_type() == GeomEnums::NT_uint32) {
         // 32-bit index case.
         // 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);
         idx_handle->unclean_set_num_rows(quads.size() * 6);
         uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
         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 {
       } else {
         // 16-bit index case.
         // 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);
         idx_handle->unclean_set_num_rows(quads.size() * 6);
         uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();
         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->total_bytecount != total_bytecount) {
     if (gltex->allocated_buffer != NULL) {
     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;
     gltex->total_bytecount = total_bytecount;
-    TinyTextureContext::get_class_type().inc_memory_usage(TypeHandle::MC_array, total_bytecount);
   }
   }
 
 
   char *next_buffer = (char *)gltex->allocated_buffer;
   char *next_buffer = (char *)gltex->allocated_buffer;

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

@@ -24,8 +24,7 @@ TinyTextureContext::
   GLTexture *gltex = &_gltex;
   GLTexture *gltex = &_gltex;
   if (gltex->allocated_buffer != NULL) {
   if (gltex->allocated_buffer != NULL) {
     nassertv(gltex->num_levels != 0);
     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->allocated_buffer = NULL;
     gltex->total_bytecount = 0;
     gltex->total_bytecount = 0;
     gltex->num_levels = 0;
     gltex->num_levels = 0;
@@ -51,8 +50,7 @@ evict_lru() {
   GLTexture *gltex = &_gltex;
   GLTexture *gltex = &_gltex;
   if (gltex->allocated_buffer != NULL) {
   if (gltex->allocated_buffer != NULL) {
     nassertv(gltex->num_levels != 0);
     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->allocated_buffer = NULL;
     gltex->total_bytecount = 0;
     gltex->total_bytecount = 0;
     gltex->num_levels = 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
 from direct.task.Task import Task
 import sys
 import sys
 
 
-# First we define some contants for the colors
+# First we define some constants for the colors
 BLACK = (0, 0, 0, 1)
 BLACK = (0, 0, 0, 1)
 WHITE = (1, 1, 1, 1)
 WHITE = (1, 1, 1, 1)
 HIGHLIGHT = (0, 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
 # 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.
 # 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):
 def PointAtZ(z, point, vec):
     return point + vec * ((z - point.getZ()) / vec.getZ())
     return point + vec * ((z - point.getZ()) / vec.getZ())
 
 
@@ -41,7 +41,7 @@ def PointAtZ(z, point, vec):
 def SquarePos(i):
 def SquarePos(i):
     return LPoint3((i % 8) - 3.5, int(i // 8) - 3.5, 0)
     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
 # The modulo operations (%) generate the every-other pattern of a chess-board
 def SquareColor(i):
 def SquareColor(i):
     if (i + ((i // 8) % 2)) % 2:
     if (i + ((i // 8) % 2)) % 2:
@@ -84,7 +84,7 @@ class ChessboardDemo(ShowBase):
         # relative to it
         # relative to it
         self.pickerNP = camera.attachNewNode(self.pickerNode)
         self.pickerNP = camera.attachNewNode(self.pickerNode)
         # Everything to be picked will use bit 1. This way if we were doing other
         # 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.pickerNode.setFromCollideMask(BitMask32.bit(1))
         self.pickerRay = CollisionRay()  # Make our ray
         self.pickerRay = CollisionRay()  # Make our ray
         # Add it to the collision node
         # Add it to the collision node
@@ -96,7 +96,7 @@ class ChessboardDemo(ShowBase):
         # Now we create the chess board and its pieces
         # 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
         # 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
         # of the scene
         self.squareRoot = render.attachNewNode("squareRoot")
         self.squareRoot = render.attachNewNode("squareRoot")
 
 
@@ -240,7 +240,7 @@ class ChessboardDemo(ShowBase):
         render.setLight(render.attachNewNode(ambientLight))
         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
 # position and color
 class Piece(object):
 class Piece(object):
     def __init__(self, square, color):
     def __init__(self, square, color):

Some files were not shown because too many files changed in this diff