Work towards ABI stability wrt allocation. Let MemoryHook take advantage of dlmalloc's internal bookkeeping.

This commit is contained in:
rdb 2017-02-12 17:24:03 +01:00
parent 29edf55069
commit 8c914a2855
19 changed files with 331 additions and 190 deletions

View File

@ -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) { \

View File

@ -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. */

View File

@ -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) { \

View File

@ -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 * number of bytes that were allocated for it. This may be slightly larger
* with DO_MEMORY_USAGE. * 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
}

View File

@ -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;
} }

View File

@ -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;

View File

@ -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); return (TYPENAME pallocator_array<Type>::pointer)
#ifdef DO_MEMORY_USAGE ASSUME_ALIGNED(_type_handle.allocate_array(n * sizeof(Type)), MEMORY_HOOK_ALIGNMENT);
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
} }
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); _type_handle.deallocate_array((void *)p);
#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
} }

View File

@ -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 {

View File

@ -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);
@ -56,16 +57,16 @@ inc_memory_usage(MemoryClass memory_class, size_t size) {
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 #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 " << *this << ".\n";
abort();
}
}
#endif // DO_MEMORY_USAGE
return ptr;
}
/**
* Reallocates memory, adjusting the total amount of memory allocated for this
* type.
*/
void *TypeHandle::
reallocate_array(void *old_ptr, size_t size) {
TAU_PROFILE("TypeHandle:reallocate_array()", " ", TAU_USER);
#ifdef DO_MEMORY_USAGE
size_t old_size = MemoryHook::get_ptr_size(old_ptr);
void *new_ptr = PANDA_REALLOC_ARRAY(old_ptr, size);
if ((*this) != TypeHandle::none()) {
size_t new_size = MemoryHook::get_ptr_size(new_ptr);
TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
assert(rnode != (TypeRegistryNode *)NULL);
AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)new_size - (AtomicAdjust::Integer)old_size);
assert(rnode->_memory_usage[MC_array] >= 0);
}
#else
void *new_ptr = PANDA_REALLOC_ARRAY(old_ptr, size);
#endif
return new_ptr;
}
/**
* Deallocates memory, subtracting it from the total amount of memory
* allocated for this type.
*/
void TypeHandle::
deallocate_array(void *ptr) {
TAU_PROFILE("TypeHandle:deallocate_array()", " ", TAU_USER);
#ifdef DO_MEMORY_USAGE
size_t alloc_size = MemoryHook::get_ptr_size(ptr);
if ((*this) != TypeHandle::none()) {
TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL);
assert(rnode != (TypeRegistryNode *)NULL);
AtomicAdjust::add(rnode->_memory_usage[MC_array], -(AtomicAdjust::Integer)alloc_size);
assert(rnode->_memory_usage[MC_array] >= 0);
}
#endif // DO_MEMORY_USAGE
PANDA_FREE_ARRAY(ptr);
}
/** /**
* Return the Index of the BEst fit Classs from a set * Return the Index of the BEst fit Classs from a set

View File

@ -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 * The following illustrates the convention for declaring a type that uses
// automatically supplies some type-differentiation functions at the cost of * TypeHandle. In this example, ThisThingie inherits from TypedObject, which
// one virtual function, get_type(); however, this inheritance is optional, * automatically supplies some type-differentiation functions at the cost of
// and may be omitted to avoid the virtual function pointer overhead. (If you * one virtual function, get_type(); however, this inheritance is optional,
// do use TypedObject, be sure to consider whether your destructor should also * and may be omitted to avoid the virtual function pointer overhead. (If you
// be virtual.) * do use TypedObject, be sure to consider whether your destructor should also
* be virtual.)
/* *
* class ThatThingie : public SimpleTypedObject { public: static TypeHandle * @code
* get_class_type() { return _type_handle; } static void init_type() { * class ThatThingie : public SimpleTypedObject {
* register_type(_type_handle, "ThatThingie"); } private: static TypeHandle * public:
* _type_handle; }; class ThisThingie : public ThatThingie, publid TypedObject * static TypeHandle get_class_type() {
* { public: static TypeHandle get_class_type() { return _type_handle; } * return _type_handle;
* static void init_type() { ThatThingie::init_type(); * }
* TypedObject::init_type(); register_type(_type_handle, "ThisThingie", * static void init_type() {
* ThatThingie::get_class_type(), TypedObject::get_class_type()); } virtual * register_type(_type_handle, "ThatThingie");
* TypeHandle get_type() const { return get_class_type(); } private: static * }
* TypeHandle _type_handle; }; *
* 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:

View File

@ -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-

View File

@ -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();

View File

@ -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

View File

@ -261,8 +261,8 @@ public:
INLINE Thread *get_current_thread() const; INLINE Thread *get_current_thread() const;
INLINE const unsigned char *get_read_pointer(bool force) const; INLINE const unsigned char *get_read_pointer(bool force) const RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
unsigned char *get_write_pointer(); unsigned char *get_write_pointer() RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
PUBLISHED: PUBLISHED:
INLINE const GeomVertexArrayData *get_object() const; INLINE const GeomVertexArrayData *get_object() const;

View File

@ -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); get_class_type().deallocate_array(_resident_data);
PANDA_FREE_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 *)get_class_type().allocate_array(copy._size);
_resident_data = (unsigned char *)PANDA_MALLOC_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); get_class_type().deallocate_array(_resident_data);
PANDA_FREE_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); get_class_type().deallocate_array(_resident_data);
PANDA_FREE_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); get_class_type().deallocate_array(_resident_data);
PANDA_FREE_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 *)get_class_type().allocate_array(_size);
_resident_data = (unsigned char *)PANDA_MALLOC_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);

View File

@ -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 const unsigned char *get_read_pointer(bool force) const RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT);
INLINE unsigned char *get_write_pointer(); 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;

View File

@ -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

View File

@ -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().deallocate_array(gltex->allocated_buffer);
TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount);
} }
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;

View File

@ -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); get_class_type().deallocate_array(gltex->allocated_buffer);
PANDA_FREE_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); get_class_type().deallocate_array(gltex->allocated_buffer);
PANDA_FREE_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;