From 29edf55069511e9158bc8c6a37fa7057b193d271 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 12 Feb 2017 17:21:53 +0100 Subject: [PATCH 01/19] GlobPattern: support trailing slash and globstar (eg. **/*.egg) --- dtool/src/dtoolutil/globPattern.cxx | 63 ++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/dtool/src/dtoolutil/globPattern.cxx b/dtool/src/dtoolutil/globPattern.cxx index 2a065e9a86..57a6afdb57 100644 --- a/dtool/src/dtoolutil/globPattern.cxx +++ b/dtool/src/dtoolutil/globPattern.cxx @@ -99,7 +99,7 @@ match_files(vector_string &results, const Filename &cwd) const { pattern = source; } else { pattern = source.substr(0, slash); - suffix = source.substr(slash + 1); + suffix = source.substr(slash); } GlobPattern glob(pattern); @@ -118,11 +118,21 @@ r_match_files(const Filename &prefix, const string &suffix, size_t slash = suffix.find('/'); if (slash == string::npos) { next_pattern = suffix; + } else if (slash + 1 == suffix.size()) { + // If the slash is at the end, we need to keep it, since it indicates that + // we only want to match directories. + next_pattern = suffix.substr(0, slash); + next_suffix = "/"; } else { next_pattern = suffix.substr(0, slash); next_suffix = suffix.substr(slash + 1); } + if (_pattern == "**" && next_pattern == "**") { + // Collapse consecutive globstar patterns. + return r_match_files(prefix, next_suffix, results, cwd); + } + Filename parent_dir; if (prefix.is_local() && !cwd.empty()) { parent_dir = Filename(cwd, prefix); @@ -136,19 +146,24 @@ r_match_files(const Filename &prefix, const string &suffix, if (!has_glob_characters()) { // If there are no special characters in the pattern, it's a literal // match. + Filename fn(parent_dir, _pattern); if (suffix.empty()) { // Time to stop. - Filename single_filename(parent_dir, _pattern); - if (single_filename.exists()) { + if (fn.exists()) { results.push_back(Filename(prefix, _pattern)); return 1; } return 0; + } else if (fn.is_directory()) { + // If the pattern ends with a slash, match a directory only. + if (suffix == "/") { + results.push_back(Filename(prefix, _pattern + "/")); + return 1; + } else { + return next_glob.r_match_files(Filename(prefix, _pattern), + next_suffix, results, cwd); + } } - - return next_glob.r_match_files(Filename(prefix, _pattern), - next_suffix, results, cwd); - } // If there *are* special glob characters, we must attempt to match the @@ -164,18 +179,44 @@ r_match_files(const Filename &prefix, const string &suffix, // the pattern. int num_matched = 0; + // A globstar pattern matches zero or more directories. + if (_pattern == "**") { + // Try to match this directory (as if the globstar wasn't there) + if (suffix.empty()) { + // This is a directory. Add it. + results.push_back(Filename(prefix)); + num_matched++; + } else if (suffix == "/") { + // Keep the trailing slash, but be sure not to duplicate it. + results.push_back(Filename(prefix, "")); + num_matched++; + } else { + num_matched += next_glob.r_match_files(prefix, next_suffix, results, cwd); + } + next_suffix = suffix; + next_glob = *this; + } + vector_string::const_iterator fi; for (fi = dir_files.begin(); fi != dir_files.end(); ++fi) { const string &local_file = (*fi); if (_pattern[0] == '.' || (local_file.empty() || local_file[0] != '.')) { if (matches(local_file)) { // We have a match; continue. - if (suffix.empty()) { + if (Filename(parent_dir, local_file).is_directory()) { + if (suffix.empty() && _pattern != "**") { + results.push_back(Filename(prefix, local_file)); + num_matched++; + } else if (suffix == "/" && _pattern != "**") { + results.push_back(Filename(prefix, local_file + "/")); + num_matched++; + } else { + num_matched += next_glob.r_match_files(Filename(prefix, local_file), + next_suffix, results, cwd); + } + } else if (suffix.empty()) { results.push_back(Filename(prefix, local_file)); num_matched++; - } else { - num_matched += next_glob.r_match_files(Filename(prefix, local_file), - next_suffix, results, cwd); } } } From 8c914a285569d2cf2f00d6fe595d632873bdad88 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 12 Feb 2017 17:24:03 +0100 Subject: [PATCH 02/19] Work towards ABI stability wrt allocation. Let MemoryHook take advantage of dlmalloc's internal bookkeeping. --- dtool/src/dtoolbase/deletedChain.h | 4 +- dtool/src/dtoolbase/dtoolbase.h | 39 +++++++ dtool/src/dtoolbase/memoryBase.h | 4 +- dtool/src/dtoolbase/memoryHook.I | 79 ++----------- dtool/src/dtoolbase/memoryHook.cxx | 110 +++++++++++++++++- dtool/src/dtoolbase/memoryHook.h | 21 ---- dtool/src/dtoolbase/pallocator.T | 30 +---- dtool/src/dtoolbase/pallocator.h | 6 +- dtool/src/dtoolbase/typeHandle.cxx | 86 +++++++++++++- dtool/src/dtoolbase/typeHandle.h | 72 ++++++++---- dtool/src/dtoolutil/pandaSystem.cxx | 13 +++ dtool/src/dtoolutil/pandaSystem.h | 2 + makepanda/makepanda.py | 2 - panda/src/gobj/geomVertexArrayData.h | 4 +- panda/src/gobj/vertexDataBuffer.cxx | 31 ++--- panda/src/gobj/vertexDataBuffer.h | 4 +- panda/src/linmath/lsimpleMatrix.h | 2 +- .../tinydisplay/tinyGraphicsStateGuardian.cxx | 6 +- panda/src/tinydisplay/tinyTextureContext.cxx | 6 +- 19 files changed, 331 insertions(+), 190 deletions(-) diff --git a/dtool/src/dtoolbase/deletedChain.h b/dtool/src/dtoolbase/deletedChain.h index 17a723a89b..a25be5d429 100644 --- a/dtool/src/dtoolbase/deletedChain.h +++ b/dtool/src/dtoolbase/deletedChain.h @@ -77,7 +77,7 @@ public: // Place this macro within a class definition to define appropriate operator // new and delete methods that take advantage of DeletedChain. #define ALLOC_DELETED_CHAIN(Type) \ - inline void *operator new(size_t size) { \ + inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \ return (void *)StaticDeletedChain< Type >::allocate(size, get_type_handle(Type)); \ } \ inline void *operator new(size_t size, void *ptr) { \ @@ -96,7 +96,7 @@ public: // Use this variant of the above macro in cases in which the compiler fails to // unify the static template pointers properly, to prevent leaks. #define ALLOC_DELETED_CHAIN_DECL(Type) \ - inline void *operator new(size_t size) { \ + inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \ return (void *)_deleted_chain.allocate(size, get_type_handle(Type)); \ } \ inline void *operator new(size_t size, void *ptr) { \ diff --git a/dtool/src/dtoolbase/dtoolbase.h b/dtool/src/dtoolbase/dtoolbase.h index 8dd2ec3cf6..965069614e 100644 --- a/dtool/src/dtoolbase/dtoolbase.h +++ b/dtool/src/dtoolbase/dtoolbase.h @@ -76,6 +76,10 @@ #define __has_builtin(x) 0 #endif +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + // Use NODEFAULT to optimize a switch() stmt to tell MSVC to automatically go // to the final untested case after it has failed all the other cases (i.e. // 'assume at least one of the cases is always true') @@ -96,6 +100,12 @@ #define ASSUME_ALIGNED(x, y) (x) #endif +#if __has_attribute(assume_aligned) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) +#define RETURNS_ALIGNED(x) __attribute__((assume_aligned(x))) +#else +#define RETURNS_ALIGNED(x) +#endif + /* include win32 defns for everything up to WinServer2003, and assume I'm smart enough to use GetProcAddress for backward compat on @@ -400,6 +410,35 @@ typedef struct _object PyObject; #endif +#ifdef LINMATH_ALIGN +/* We require 16-byte alignment of certain structures, to support SSE2. We + don't strictly have to align everything, but it's just easier to do so. */ +#if defined(HAVE_EIGEN) && defined(__AVX__) && defined(STDFLOAT_DOUBLE) +/* Eigen uses AVX instructions, but let's only enable this when compiling with + double precision, so that we can keep our ABI a bit more stable. */ +#define MEMORY_HOOK_ALIGNMENT 32 +#else +#define MEMORY_HOOK_ALIGNMENT 16 +#endif +/* Otherwise, align to two words. This seems to be pretty standard to the + point where some code may rely on this being the case. */ +#elif defined(IS_OSX) || NATIVE_WORDSIZE >= 64 +#define MEMORY_HOOK_ALIGNMENT 16 +#else +#define MEMORY_HOOK_ALIGNMENT 8 +#endif + +#ifdef HAVE_EIGEN +/* Make sure that Eigen doesn't assume alignment guarantees we don't offer. */ +#define EIGEN_MAX_ALIGN_BYTES MEMORY_HOOK_ALIGNMENT +#ifndef EIGEN_MPL2_ONLY +#define EIGEN_MPL2_ONLY 1 +#endif +#if !defined(_DEBUG) && !defined(EIGEN_NO_DEBUG) +#define EIGEN_NO_DEBUG 1 +#endif +#endif + /* Determine our memory-allocation requirements. */ #if defined(USE_MEMORY_PTMALLOC2) || defined(USE_MEMORY_DLMALLOC) || defined(DO_MEMORY_USAGE) || defined(MEMORY_HOOK_DO_ALIGN) /* In this case we have some custom memory management requirements. */ diff --git a/dtool/src/dtoolbase/memoryBase.h b/dtool/src/dtoolbase/memoryBase.h index 2f361f1bb1..6d755e695b 100644 --- a/dtool/src/dtoolbase/memoryBase.h +++ b/dtool/src/dtoolbase/memoryBase.h @@ -26,7 +26,7 @@ #ifndef USE_MEMORY_NOWRAPPERS #define ALLOC_MEMORY_BASE \ - inline void *operator new(size_t size) { \ + inline void *operator new(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \ return PANDA_MALLOC_SINGLE(size); \ } \ inline void *operator new(size_t size, void *ptr) { \ @@ -38,7 +38,7 @@ } \ inline void operator delete(void *, void *) { \ } \ - inline void *operator new[](size_t size) { \ + inline void *operator new[](size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT) { \ return PANDA_MALLOC_ARRAY(size); \ } \ inline void *operator new[](size_t size, void *ptr) { \ diff --git a/dtool/src/dtoolbase/memoryHook.I b/dtool/src/dtoolbase/memoryHook.I index c89fe1908b..bd5a55af79 100644 --- a/dtool/src/dtoolbase/memoryHook.I +++ b/dtool/src/dtoolbase/memoryHook.I @@ -63,14 +63,24 @@ round_up_to_page_size(size_t size) const { /** * Given a pointer that was returned by a MemoryHook allocation, returns the - * number of bytes that were allocated for it. Returns 0 if not compiling - * with DO_MEMORY_USAGE. + * number of bytes that were allocated for it. This may be slightly larger + * than the number of bytes requested. + * The behavior of this function is undefined if the given pointer was not + * returned by the MemoryHook allocator or was already freed. + * May return 0 if not compiling with DO_MEMORY_USAGE. + * + * This is only defined publicly so TypeHandle can get at it; it really + * shouldn't be used outside of dtoolbase. */ INLINE size_t MemoryHook:: get_ptr_size(void *ptr) { #if defined(MEMORY_HOOK_DO_ALIGN) uintptr_t *root = (uintptr_t *)ptr; return (size_t)root[-2]; +#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + // If we are using dlmalloc, we know how it stores the size. + size_t *root = (size_t *)ptr; + return (root[-1] & ~0x7) - sizeof(size_t); #elif defined(DO_MEMORY_USAGE) size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT); return *root; @@ -78,68 +88,3 @@ get_ptr_size(void *ptr) { return 0; #endif // DO_MEMORY_USAGE } - -/** - * Increments the amount of requested size as necessary to accommodate the - * extra data we might piggyback on each allocated block. - */ -INLINE size_t MemoryHook:: -inflate_size(size_t size) { -#if defined(MEMORY_HOOK_DO_ALIGN) - // If we're aligning, we need to request the header size, plus extra bytes - // to give us wiggle room to adjust the pointer. - return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1; -#elif defined(DO_MEMORY_USAGE) - // If we're not aligning, but we're tracking memory allocations, we just - // need the header size extra (this gives us a place to store the size of - // the allocated block). However, we do need to make sure that any - // alignment guarantee is kept. - return size + MEMORY_HOOK_ALIGNMENT; -#else - // If we're not doing any of that, we can just allocate the precise - // requested amount. - return size; -#endif // DO_MEMORY_USAGE -} - -/** - * Converts an allocated pointer to a pointer returnable to the application. - * Stuffs size in the first n bytes of the allocated space. - */ -INLINE void *MemoryHook:: -alloc_to_ptr(void *alloc, size_t size) { -#if defined(MEMORY_HOOK_DO_ALIGN) - // Add room for two uintptr_t values. - uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2); - // Align this to the requested boundary. - root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1)); - root[-2] = size; - root[-1] = (uintptr_t)alloc; // Save the pointer we originally allocated. - return (void *)root; -#elif defined(DO_MEMORY_USAGE) - size_t *root = (size_t *)alloc; - root[0] = size; - return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT); -#else - return alloc; -#endif // DO_MEMORY_USAGE -} - -/** - * Converts an application pointer back to the original allocated pointer. - * Extracts size from the first n bytes of the allocated space. - */ -INLINE void *MemoryHook:: -ptr_to_alloc(void *ptr, size_t &size) { -#if defined(MEMORY_HOOK_DO_ALIGN) - uintptr_t *root = (uintptr_t *)ptr; - size = root[-2]; - return (void *)root[-1]; // Get the pointer we originally allocated. -#elif defined(DO_MEMORY_USAGE) - size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT); - size = root[0]; - return (void *)root; -#else - return ptr; -#endif // DO_MEMORY_USAGE -} diff --git a/dtool/src/dtoolbase/memoryHook.cxx b/dtool/src/dtoolbase/memoryHook.cxx index 506ff51005..224fd3107b 100644 --- a/dtool/src/dtoolbase/memoryHook.cxx +++ b/dtool/src/dtoolbase/memoryHook.cxx @@ -14,6 +14,7 @@ #include "memoryHook.h" #include "deletedBufferChain.h" #include +#include "typeRegistry.h" #ifdef WIN32 @@ -104,6 +105,83 @@ static_assert((MEMORY_HOOK_ALIGNMENT & (MEMORY_HOOK_ALIGNMENT - 1)) == 0, #endif // USE_MEMORY_* +/** + * Increments the amount of requested size as necessary to accommodate the + * extra data we might piggyback on each allocated block. + */ +INLINE static size_t +inflate_size(size_t size) { +#if defined(MEMORY_HOOK_DO_ALIGN) + // If we're aligning, we need to request the header size, plus extra bytes + // to give us wiggle room to adjust the pointer. + return size + sizeof(uintptr_t) * 2 + MEMORY_HOOK_ALIGNMENT - 1; +#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + // If we are can access the allocator's bookkeeping to figure out how many + // bytes were allocated, we don't need to add our own information. + return size; +#elif defined(DO_MEMORY_USAGE) + // If we're not aligning, but we're tracking memory allocations, we just + // need the header size extra (this gives us a place to store the size of + // the allocated block). However, we do need to make sure that any + // alignment guarantee is kept. + return size + MEMORY_HOOK_ALIGNMENT; +#else + // If we're not doing any of that, we can just allocate the precise + // requested amount. + return size; +#endif // DO_MEMORY_USAGE +} + +/** + * Converts an allocated pointer to a pointer returnable to the application. + * Stuffs size in the first n bytes of the allocated space. + */ +INLINE static void * +alloc_to_ptr(void *alloc, size_t size) { +#if defined(MEMORY_HOOK_DO_ALIGN) + // Add room for two uintptr_t values. + uintptr_t *root = (uintptr_t *)((char *)alloc + sizeof(uintptr_t) * 2); + // Align this to the requested boundary. + root = (uintptr_t *)(((uintptr_t)root + MEMORY_HOOK_ALIGNMENT - 1) & ~(MEMORY_HOOK_ALIGNMENT - 1)); + root[-2] = size; + root[-1] = (uintptr_t)alloc; // Save the pointer we originally allocated. + return (void *)root; +#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + return alloc; +#elif defined(DO_MEMORY_USAGE) + size_t *root = (size_t *)alloc; + root[0] = size; + return (void *)((char *)root + MEMORY_HOOK_ALIGNMENT); +#else + return alloc; +#endif // DO_MEMORY_USAGE +} + +/** + * Converts an application pointer back to the original allocated pointer. + * Extracts size from the first n bytes of the allocated space, but only if + * DO_MEMORY_USAGE is defined. + */ +INLINE static void * +ptr_to_alloc(void *ptr, size_t &size) { +#if defined(MEMORY_HOOK_DO_ALIGN) + uintptr_t *root = (uintptr_t *)ptr; + size = root[-2]; + return (void *)root[-1]; // Get the pointer we originally allocated. +#elif defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) +#ifdef DO_MEMORY_USAGE + size = MemoryHook::get_ptr_size(ptr); +#endif + return ptr; +#elif defined(DO_MEMORY_USAGE) + size_t *root = (size_t *)((char *)ptr - MEMORY_HOOK_ALIGNMENT); + size = root[0]; + return (void *)root; +#else + return ptr; +#endif // DO_MEMORY_USAGE +} + /** * */ @@ -195,6 +273,11 @@ heap_alloc_single(size_t size) { #ifdef DO_MEMORY_USAGE // In the DO_MEMORY_USAGE case, we want to track the total size of allocated // bytes on the heap. +#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + // dlmalloc may slightly overallocate, however. + size = get_ptr_size(alloc); + inflated_size = size; +#endif AtomicAdjust::add(_total_heap_single_size, (AtomicAdjust::Integer)size); if ((size_t)AtomicAdjust::get(_total_heap_single_size) + (size_t)AtomicAdjust::get(_total_heap_array_size) > @@ -204,8 +287,10 @@ heap_alloc_single(size_t size) { #endif // DO_MEMORY_USAGE void *ptr = alloc_to_ptr(alloc, size); +#ifdef _DEBUG assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0); assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size); +#endif return ptr; } @@ -265,6 +350,11 @@ heap_alloc_array(size_t size) { #ifdef DO_MEMORY_USAGE // In the DO_MEMORY_USAGE case, we want to track the total size of allocated // bytes on the heap. +#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + // dlmalloc may slightly overallocate, however. + size = get_ptr_size(alloc); + inflated_size = size; +#endif AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size); if ((size_t)AtomicAdjust::get(_total_heap_single_size) + (size_t)AtomicAdjust::get(_total_heap_array_size) > @@ -274,8 +364,10 @@ heap_alloc_array(size_t size) { #endif // DO_MEMORY_USAGE void *ptr = alloc_to_ptr(alloc, size); +#ifdef _DEBUG assert(((uintptr_t)ptr % MEMORY_HOOK_ALIGNMENT) == 0); assert(ptr >= alloc && (char *)ptr + size <= (char *)alloc + inflated_size); +#endif return ptr; } @@ -287,11 +379,6 @@ heap_realloc_array(void *ptr, size_t size) { size_t orig_size; void *alloc = ptr_to_alloc(ptr, orig_size); -#ifdef DO_MEMORY_USAGE - assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size); - AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size); -#endif // DO_MEMORY_USAGE - size_t inflated_size = inflate_size(size); void *alloc1 = alloc; @@ -318,6 +405,16 @@ heap_realloc_array(void *ptr, size_t size) { #endif } +#ifdef DO_MEMORY_USAGE +#if defined(USE_MEMORY_DLMALLOC) || defined(USE_MEMORY_PTMALLOC2) + // dlmalloc may slightly overallocate, however. + size = get_ptr_size(alloc1); + inflated_size = size; +#endif + assert((AtomicAdjust::Integer)orig_size <= _total_heap_array_size); + AtomicAdjust::add(_total_heap_array_size, (AtomicAdjust::Integer)size-(AtomicAdjust::Integer)orig_size); +#endif // DO_MEMORY_USAGE + // Align this to the requested boundary. #ifdef MEMORY_HOOK_DO_ALIGN // This copies the code from alloc_to_ptr, since we can't write the size and @@ -337,8 +434,11 @@ heap_realloc_array(void *ptr, size_t size) { #else void *ptr1 = alloc_to_ptr(alloc1, size); #endif + +#ifdef _DEBUG assert(ptr1 >= alloc1 && (char *)ptr1 + size <= (char *)alloc1 + inflated_size); assert(((uintptr_t)ptr1 % MEMORY_HOOK_ALIGNMENT) == 0); +#endif return ptr1; } diff --git a/dtool/src/dtoolbase/memoryHook.h b/dtool/src/dtoolbase/memoryHook.h index b8eac26f54..687e348aef 100644 --- a/dtool/src/dtoolbase/memoryHook.h +++ b/dtool/src/dtoolbase/memoryHook.h @@ -20,22 +20,6 @@ #include "mutexImpl.h" #include -#ifdef LINMATH_ALIGN -// We require 16-byte alignment of certain structures, to support SSE2. We -// don't strictly have to align *everything*, but it's just easier to do so. -#ifdef __AVX__ -#define MEMORY_HOOK_ALIGNMENT 32 -#else -#define MEMORY_HOOK_ALIGNMENT 16 -#endif -// Otherwise, align to two words. This seems to be pretty standard to the -// point where some code may rely on this being the case. -#elif defined(IS_OSX) || NATIVE_WORDSIZE >= 64 -#define MEMORY_HOOK_ALIGNMENT 16 -#else -#define MEMORY_HOOK_ALIGNMENT 8 -#endif - class DeletedBufferChain; /** @@ -83,11 +67,6 @@ public: INLINE static size_t get_ptr_size(void *ptr); -private: - INLINE static size_t inflate_size(size_t size); - INLINE static void *alloc_to_ptr(void *alloc, size_t size); - INLINE static void *ptr_to_alloc(void *ptr, size_t &size); - #ifdef DO_MEMORY_USAGE protected: TVOLATILE AtomicAdjust::Integer _total_heap_single_size; diff --git a/dtool/src/dtoolbase/pallocator.T b/dtool/src/dtoolbase/pallocator.T index 38bc87135c..e9bfd3f98e 100644 --- a/dtool/src/dtoolbase/pallocator.T +++ b/dtool/src/dtoolbase/pallocator.T @@ -19,7 +19,7 @@ pallocator_single(TypeHandle type_handle) NOEXCEPT : } template -INLINE TYPENAME pallocator_single::pointer pallocator_single:: +INLINE Type *pallocator_single:: allocate(TYPENAME pallocator_single::size_type n, TYPENAME allocator::const_pointer) { TAU_PROFILE("pallocator_single:allocate()", " ", TAU_USER); // This doesn't support allocating arrays. @@ -43,34 +43,14 @@ pallocator_array(TypeHandle type_handle) NOEXCEPT : } template -INLINE TYPENAME pallocator_array::pointer pallocator_array:: +INLINE Type *pallocator_array:: allocate(TYPENAME pallocator_array::size_type n, TYPENAME allocator::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::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::pointer)ASSUME_ALIGNED(ptr, MEMORY_HOOK_ALIGNMENT); -#else - return (TYPENAME pallocator_array::pointer)PANDA_MALLOC_ARRAY(n * sizeof(Type)); -#endif // DO_MEMORY_USAGE + return (TYPENAME pallocator_array::pointer) + ASSUME_ALIGNED(_type_handle.allocate_array(n * sizeof(Type)), MEMORY_HOOK_ALIGNMENT); } template INLINE void pallocator_array:: deallocate(TYPENAME pallocator_array::pointer p, TYPENAME pallocator_array::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); } diff --git a/dtool/src/dtoolbase/pallocator.h b/dtool/src/dtoolbase/pallocator.h index b735bb7b3e..3c91b6cc7e 100644 --- a/dtool/src/dtoolbase/pallocator.h +++ b/dtool/src/dtoolbase/pallocator.h @@ -59,7 +59,8 @@ public: INLINE pallocator_single(const pallocator_single ©) NOEXCEPT : _type_handle(copy._type_handle) { } - INLINE pointer allocate(size_type n, allocator::const_pointer hint = 0); + INLINE Type *allocate(size_type n, allocator::const_pointer hint = 0) + RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); INLINE void deallocate(pointer p, size_type n); template struct rebind { @@ -87,7 +88,8 @@ public: INLINE pallocator_array(const pallocator_array ©) NOEXCEPT : _type_handle(copy._type_handle) { } - INLINE pointer allocate(size_type n, allocator::const_pointer hint = 0); + INLINE Type *allocate(size_type n, allocator::const_pointer hint = 0) + RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); INLINE void deallocate(pointer p, size_type n); template struct rebind { diff --git a/dtool/src/dtoolbase/typeHandle.cxx b/dtool/src/dtoolbase/typeHandle.cxx index ea3a51d6a1..6f4d7bc1d1 100644 --- a/dtool/src/dtoolbase/typeHandle.cxx +++ b/dtool/src/dtoolbase/typeHandle.cxx @@ -18,7 +18,6 @@ // This is initialized to zero by static initialization. TypeHandle TypeHandle::_none; -#ifdef DO_MEMORY_USAGE /** * Returns the total allocated memory used by objects of this type, for the * indicated memory class. This is only updated if track-memory-usage is set @@ -26,6 +25,7 @@ TypeHandle TypeHandle::_none; */ size_t TypeHandle:: get_memory_usage(MemoryClass memory_class) const { +#ifdef DO_MEMORY_USAGE assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); if ((*this) == TypeHandle::none()) { return 0; @@ -34,16 +34,17 @@ get_memory_usage(MemoryClass memory_class) const { assert(rnode != (TypeRegistryNode *)NULL); return (size_t)AtomicAdjust::get(rnode->_memory_usage[memory_class]); } -} #endif // DO_MEMORY_USAGE + return 0; +} -#ifdef DO_MEMORY_USAGE /** * Adds the indicated amount to the record for the total allocated memory for * objects of this type. */ void TypeHandle:: inc_memory_usage(MemoryClass memory_class, size_t size) { +#ifdef DO_MEMORY_USAGE assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); @@ -56,16 +57,16 @@ inc_memory_usage(MemoryClass memory_class, size_t size) { abort(); } } -} #endif // DO_MEMORY_USAGE +} -#ifdef DO_MEMORY_USAGE /** * Subtracts the indicated amount from the record for the total allocated * memory for objects of this type. */ void TypeHandle:: dec_memory_usage(MemoryClass memory_class, size_t size) { +#ifdef DO_MEMORY_USAGE assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); @@ -75,8 +76,81 @@ dec_memory_usage(MemoryClass memory_class, size_t size) { // rnode->_memory_usage[memory_class] << "\n"; assert(rnode->_memory_usage[memory_class] >= 0); } -} #endif // DO_MEMORY_USAGE +} + +/** + * Allocates memory, adding it to the total amount of memory allocated for + * this type. + */ +void *TypeHandle:: +allocate_array(size_t size) { + TAU_PROFILE("TypeHandle:allocate_array()", " ", TAU_USER); + + void *ptr = PANDA_MALLOC_ARRAY(size); +#ifdef DO_MEMORY_USAGE + if ((*this) != TypeHandle::none()) { + size_t alloc_size = MemoryHook::get_ptr_size(ptr); +#ifdef _DEBUG + assert(size <= alloc_size); +#endif + TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); + assert(rnode != (TypeRegistryNode *)NULL); + AtomicAdjust::add(rnode->_memory_usage[MC_array], (AtomicAdjust::Integer)alloc_size); + if (rnode->_memory_usage[MC_array] < 0) { + cerr << "Memory usage overflow for type " << *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 diff --git a/dtool/src/dtoolbase/typeHandle.h b/dtool/src/dtoolbase/typeHandle.h index fe611c2fd1..f770b1810b 100644 --- a/dtool/src/dtoolbase/typeHandle.h +++ b/dtool/src/dtoolbase/typeHandle.h @@ -18,25 +18,49 @@ #include -// The following illustrates the convention for declaring a type that uses -// TypeHandle. In this example, ThisThingie inherits from TypedObject, which -// automatically supplies some type-differentiation functions at the cost of -// one virtual function, get_type(); however, this inheritance is optional, -// and may be omitted to avoid the virtual function pointer overhead. (If you -// do use TypedObject, be sure to consider whether your destructor should also -// be virtual.) - -/* - * class ThatThingie : public SimpleTypedObject { public: static TypeHandle - * get_class_type() { return _type_handle; } static void init_type() { - * register_type(_type_handle, "ThatThingie"); } private: static TypeHandle - * _type_handle; }; class ThisThingie : public ThatThingie, publid TypedObject - * { public: static TypeHandle get_class_type() { return _type_handle; } - * static void init_type() { ThatThingie::init_type(); - * TypedObject::init_type(); register_type(_type_handle, "ThisThingie", - * ThatThingie::get_class_type(), TypedObject::get_class_type()); } virtual - * TypeHandle get_type() const { return get_class_type(); } private: static - * TypeHandle _type_handle; }; +/** + * The following illustrates the convention for declaring a type that uses + * TypeHandle. In this example, ThisThingie inherits from TypedObject, which + * automatically supplies some type-differentiation functions at the cost of + * one virtual function, get_type(); however, this inheritance is optional, + * and may be omitted to avoid the virtual function pointer overhead. (If you + * do use TypedObject, be sure to consider whether your destructor should also + * be virtual.) + * + * @code + * class ThatThingie : public SimpleTypedObject { + * public: + * static TypeHandle get_class_type() { + * return _type_handle; + * } + * static void init_type() { + * register_type(_type_handle, "ThatThingie"); + * } + * + * private: + * static TypeHandle _type_handle; + * }; + * + * class ThisThingie : public ThatThingie, publid TypedObject { + * public: + * static TypeHandle get_class_type() { + * return _type_handle; + * } + * static void init_type() { + * ThatThingie::init_type(); + * TypedObject::init_type(); + * register_type(_type_handle, "ThisThingie", + * ThatThingie::get_class_type(), + * TypedObject::get_class_type()); + * } + * virtual TypeHandle get_type() const { + * return get_class_type(); + * } + * + * private: + * static TypeHandle _type_handle; + * }; + * @endcode */ class TypedObject; @@ -97,15 +121,9 @@ PUBLISHED: int get_best_parent_from_Set(const std::set< int > &legal_vals) const; -#ifdef DO_MEMORY_USAGE size_t get_memory_usage(MemoryClass memory_class) const; void inc_memory_usage(MemoryClass memory_class, size_t size); void dec_memory_usage(MemoryClass memory_class, size_t size); -#else - static CONSTEXPR size_t get_memory_usage(MemoryClass) { return 0; } - INLINE void inc_memory_usage(MemoryClass, size_t) { } - INLINE void dec_memory_usage(MemoryClass, size_t) { } -#endif // DO_MEMORY_USAGE INLINE int get_index() const; INLINE void output(ostream &out) const; @@ -118,6 +136,10 @@ PUBLISHED: MAKE_SEQ_PROPERTY(child_classes, get_num_child_classes, get_child_class); public: + void *allocate_array(size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); + void *reallocate_array(void *ptr, size_t size) RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); + void deallocate_array(void *ptr); + INLINE static TypeHandle from_index(int index); private: diff --git a/dtool/src/dtoolutil/pandaSystem.cxx b/dtool/src/dtoolutil/pandaSystem.cxx index cef04eb37b..79e5aa7762 100644 --- a/dtool/src/dtoolutil/pandaSystem.cxx +++ b/dtool/src/dtoolutil/pandaSystem.cxx @@ -45,6 +45,11 @@ PandaSystem() : #else set_system_tag("eigen", "vectorize", "0"); #endif +#ifdef __AVX__ + set_system_tag("eigen", "avx", "1"); +#else + set_system_tag("eigen", "avx", "0"); +#endif #endif // HAVE_EIGEN #ifdef USE_MEMORY_DLMALLOC @@ -189,6 +194,14 @@ is_official_version() { #endif } +/** + * Returns the memory alignment that Panda's allocators are using. + */ +int PandaSystem:: +get_memory_alignment() { + return MEMORY_HOOK_ALIGNMENT; +} + /** * Returns the string defined by the distributor of this version of Panda, or * "homebuilt" if this version was built directly from the sources by the end- diff --git a/dtool/src/dtoolutil/pandaSystem.h b/dtool/src/dtoolutil/pandaSystem.h index d88e3b92a3..bed5f2c073 100644 --- a/dtool/src/dtoolutil/pandaSystem.h +++ b/dtool/src/dtoolutil/pandaSystem.h @@ -39,6 +39,8 @@ PUBLISHED: static int get_sequence_version(); static bool is_official_version(); + static int get_memory_alignment(); + static string get_distributor(); static string get_compiler(); static string get_build_date(); diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 564ee8e4e9..e159e864d8 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -973,9 +973,7 @@ if GetTarget() == 'android': DefSymbol("ALWAYS", "ANDROID") if not PkgSkip("EIGEN"): - DefSymbol("ALWAYS", "EIGEN_MPL2_ONLY") if GetOptimize() >= 3: - DefSymbol("ALWAYS", "EIGEN_NO_DEBUG") if COMPILER == "MSVC": # Squeeze out a bit more performance on MSVC builds... # Only do this if EIGEN_NO_DEBUG is also set, otherwise it diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index e52876d376..9766a9cbd1 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -261,8 +261,8 @@ public: INLINE Thread *get_current_thread() const; - INLINE const unsigned char *get_read_pointer(bool force) const; - unsigned char *get_write_pointer(); + INLINE const unsigned char *get_read_pointer(bool force) const RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); + unsigned char *get_write_pointer() RETURNS_ALIGNED(MEMORY_HOOK_ALIGNMENT); PUBLISHED: INLINE const GeomVertexArrayData *get_object() const; diff --git a/panda/src/gobj/vertexDataBuffer.cxx b/panda/src/gobj/vertexDataBuffer.cxx index 1e3b884893..19f50b3013 100644 --- a/panda/src/gobj/vertexDataBuffer.cxx +++ b/panda/src/gobj/vertexDataBuffer.cxx @@ -27,15 +27,13 @@ operator = (const VertexDataBuffer ©) { if (_resident_data != (unsigned char *)NULL) { nassertv(_reserved_size != 0); - get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size); - PANDA_FREE_ARRAY(_resident_data); + get_class_type().deallocate_array(_resident_data); _resident_data = NULL; } if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) { // We only allocate _size bytes, not the full _reserved_size allocated by // the original copy. - get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)copy._size); - _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(copy._size); + _resident_data = (unsigned char *)get_class_type().allocate_array(copy._size); memcpy(_resident_data, copy._resident_data, copy._size); } _size = copy._size; @@ -55,17 +53,16 @@ swap(VertexDataBuffer &other) { unsigned char *resident_data = _resident_data; size_t size = _size; size_t reserved_size = _reserved_size; - PT(VertexDataBlock) block = _block; + + _block.swap(other._block); _resident_data = other._resident_data; _size = other._size; _reserved_size = other._reserved_size; - _block = other._block; other._resident_data = resident_data; other._size = size; other._reserved_size = reserved_size; - other._block = block; nassertv(_reserved_size >= _size); } @@ -94,13 +91,12 @@ do_clean_realloc(size_t reserved_size) { do_page_in(); } - get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size - (int)_reserved_size); if (_reserved_size == 0) { nassertv(_resident_data == (unsigned char *)NULL); - _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size); + _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size); } else { nassertv(_resident_data != (unsigned char *)NULL); - _resident_data = (unsigned char *)PANDA_REALLOC_ARRAY(_resident_data, reserved_size); + _resident_data = (unsigned char *)get_class_type().reallocate_array(_resident_data, reserved_size); } nassertv(_resident_data != (unsigned char *)NULL); _reserved_size = reserved_size; @@ -129,16 +125,14 @@ do_unclean_realloc(size_t reserved_size) { if (_resident_data != (unsigned char *)NULL) { nassertv(_reserved_size != 0); - get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size); - PANDA_FREE_ARRAY(_resident_data); + get_class_type().deallocate_array(_resident_data); _resident_data = NULL; _reserved_size = 0; } if (reserved_size != 0) { - get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size); nassertv(_resident_data == (unsigned char *)NULL); - _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size); + _resident_data = (unsigned char *)get_class_type().allocate_array(reserved_size); } _reserved_size = reserved_size; @@ -166,8 +160,7 @@ do_page_out(VertexDataBook &book) { if (_size == 0) { // It's an empty buffer. Just deallocate it; don't bother to create a // block. - get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size); - PANDA_FREE_ARRAY(_resident_data); + get_class_type().deallocate_array(_resident_data); _resident_data = NULL; _reserved_size = 0; @@ -180,8 +173,7 @@ do_page_out(VertexDataBook &book) { nassertv(pointer != (unsigned char *)NULL); memcpy(pointer, _resident_data, _size); - get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size); - PANDA_FREE_ARRAY(_resident_data); + get_class_type().deallocate_array(_resident_data); _resident_data = NULL; _reserved_size = _size; @@ -205,8 +197,7 @@ do_page_in() { nassertv(_block != (VertexDataBlock *)NULL); nassertv(_reserved_size == _size); - get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size); - _resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(_size); + _resident_data = (unsigned char *)get_class_type().allocate_array(_size); nassertv(_resident_data != (unsigned char *)NULL); memcpy(_resident_data, _block->get_pointer(true), _size); diff --git a/panda/src/gobj/vertexDataBuffer.h b/panda/src/gobj/vertexDataBuffer.h index 2a18aeda45..f698669f52 100644 --- a/panda/src/gobj/vertexDataBuffer.h +++ b/panda/src/gobj/vertexDataBuffer.h @@ -57,8 +57,8 @@ public: void operator = (const 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_reserved_size() const; diff --git a/panda/src/linmath/lsimpleMatrix.h b/panda/src/linmath/lsimpleMatrix.h index 5669e18be3..3228caf5bb 100644 --- a/panda/src/linmath/lsimpleMatrix.h +++ b/panda/src/linmath/lsimpleMatrix.h @@ -58,7 +58,7 @@ private: #endif // HAVE_EIGEN // This is as good a place as any to define this alignment macro. -#if defined(LINMATH_ALIGN) && defined(HAVE_EIGEN) && defined(__AVX__) +#if defined(LINMATH_ALIGN) && defined(HAVE_EIGEN) && defined(__AVX__) && defined(STDFLOAT_DOUBLE) #define ALIGN_LINMATH ALIGN_32BYTE #elif defined(LINMATH_ALIGN) #define ALIGN_LINMATH ALIGN_16BYTE diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index 6818ea65a0..db600e14de 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -2612,12 +2612,10 @@ setup_gltex(GLTexture *gltex, int x_size, int y_size, int num_levels) { if (gltex->total_bytecount != total_bytecount) { if (gltex->allocated_buffer != NULL) { - PANDA_FREE_ARRAY(gltex->allocated_buffer); - TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount); + TinyTextureContext::get_class_type().deallocate_array(gltex->allocated_buffer); } - gltex->allocated_buffer = PANDA_MALLOC_ARRAY(total_bytecount); + gltex->allocated_buffer = TinyTextureContext::get_class_type().allocate_array(total_bytecount); gltex->total_bytecount = total_bytecount; - TinyTextureContext::get_class_type().inc_memory_usage(TypeHandle::MC_array, total_bytecount); } char *next_buffer = (char *)gltex->allocated_buffer; diff --git a/panda/src/tinydisplay/tinyTextureContext.cxx b/panda/src/tinydisplay/tinyTextureContext.cxx index 87427ac365..5a3ae3414d 100644 --- a/panda/src/tinydisplay/tinyTextureContext.cxx +++ b/panda/src/tinydisplay/tinyTextureContext.cxx @@ -24,8 +24,7 @@ TinyTextureContext:: GLTexture *gltex = &_gltex; if (gltex->allocated_buffer != NULL) { nassertv(gltex->num_levels != 0); - TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount); - PANDA_FREE_ARRAY(gltex->allocated_buffer); + get_class_type().deallocate_array(gltex->allocated_buffer); gltex->allocated_buffer = NULL; gltex->total_bytecount = 0; gltex->num_levels = 0; @@ -51,8 +50,7 @@ evict_lru() { GLTexture *gltex = &_gltex; if (gltex->allocated_buffer != NULL) { nassertv(gltex->num_levels != 0); - TinyTextureContext::get_class_type().dec_memory_usage(TypeHandle::MC_array, gltex->total_bytecount); - PANDA_FREE_ARRAY(gltex->allocated_buffer); + get_class_type().deallocate_array(gltex->allocated_buffer); gltex->allocated_buffer = NULL; gltex->total_bytecount = 0; gltex->num_levels = 0; From 78e4c712023ad32f82625b182d543d5c6fae60d0 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 17 Feb 2017 12:57:34 +0100 Subject: [PATCH 03/19] Fix issue with taking screenshots from an FBO --- panda/src/display/displayRegion.cxx | 6 ++++++ panda/src/glstuff/glGraphicsBuffer_src.cxx | 3 +++ 2 files changed, 9 insertions(+) diff --git a/panda/src/display/displayRegion.cxx b/panda/src/display/displayRegion.cxx index c8f7626468..4ffa29285c 100644 --- a/panda/src/display/displayRegion.cxx +++ b/panda/src/display/displayRegion.cxx @@ -491,6 +491,12 @@ get_screenshot() { return NULL; } + { + // Make sure that the correct viewport is active. + DisplayRegionPipelineReader dr_reader(this, current_thread); + gsg->prepare_display_region(&dr_reader); + } + PT(Texture) tex = new Texture; RenderBuffer buffer = gsg->get_render_buffer(get_screenshot_buffer_type(), diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index ad09596f9c..3a73d175c4 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -269,6 +269,9 @@ begin_frame(FrameMode mode, Thread *current_thread) { } } #endif + } else if (mode == FM_refresh) { + // Just bind the FBO. + rebuild_bitplanes(); } _gsg->set_current_properties(&get_fb_properties()); From 21a42f62dfeb62a590f957ae5d3aa0ca5b32f373 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 17 Feb 2017 12:59:50 +0100 Subject: [PATCH 04/19] Fix FreeBSD compile error --- panda/src/display/graphicsPipe.cxx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/panda/src/display/graphicsPipe.cxx b/panda/src/display/graphicsPipe.cxx index 5c00b204a3..bb6fdae3a4 100644 --- a/panda/src/display/graphicsPipe.cxx +++ b/panda/src/display/graphicsPipe.cxx @@ -23,11 +23,8 @@ #include #endif -#ifdef IS_OSX +#if defined(IS_OSX) || defined(IS_FREEBSD) #include -#endif - -#ifdef IS_FREEBSD #include #endif From f5f51c5d5b82e19993fe002282884a08bc694a10 Mon Sep 17 00:00:00 2001 From: rdb Date: Fri, 17 Feb 2017 16:15:04 +0100 Subject: [PATCH 05/19] Remove OpenSSL includes from headers, so C++ users don't need to have OpenSSL --- dtool/src/parser-inc/openssl/evp.h | 3 +- dtool/src/parser-inc/openssl/ssl.h | 15 ++-- dtool/src/parser-inc/openssl/x509.h | 4 +- dtool/src/prc/encryptStreamBuf.cxx | 1 + dtool/src/prc/encryptStreamBuf.h | 2 +- dtool/src/prc/prcKeyRegistry.cxx | 4 + dtool/src/prc/prcKeyRegistry.h | 4 +- panda/src/downloader/bioPtr.I | 8 -- panda/src/downloader/bioPtr.cxx | 13 ++- panda/src/downloader/bioPtr.h | 10 +-- panda/src/downloader/bioStreamBuf.h | 6 -- panda/src/downloader/bioStreamPtr.h | 6 -- panda/src/downloader/httpChannel.cxx | 2 + panda/src/downloader/httpChannel.h | 8 +- panda/src/downloader/httpClient.cxx | 126 ++++++++++++++------------- panda/src/downloader/httpClient.h | 12 ++- panda/src/express/multifile.cxx | 39 +-------- panda/src/express/multifile.h | 7 +- 18 files changed, 112 insertions(+), 158 deletions(-) diff --git a/dtool/src/parser-inc/openssl/evp.h b/dtool/src/parser-inc/openssl/evp.h index a9ef1fd091..9cc780cb19 100644 --- a/dtool/src/parser-inc/openssl/evp.h +++ b/dtool/src/parser-inc/openssl/evp.h @@ -2,7 +2,6 @@ #ifndef EVP_H #define EVP_H -struct EVP_CIPHER_CTX; -struct EVP_PKEY; +#include #endif diff --git a/dtool/src/parser-inc/openssl/ssl.h b/dtool/src/parser-inc/openssl/ssl.h index d43aca6090..50fe63c4bc 100644 --- a/dtool/src/parser-inc/openssl/ssl.h +++ b/dtool/src/parser-inc/openssl/ssl.h @@ -2,13 +2,14 @@ #ifndef SSL_H #define SSL_H -struct BIO; -struct SSL_CTX; -struct EVP_CIPHER_CTX; -struct EVP_PKEY; -struct X509; -struct X509_STORE; -struct X509_NAME; +typedef struct bio_st BIO; +typedef struct ssl_ctx_st SSL_CTX; +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; +typedef struct evp_pkey_st EVP_PKEY; +typedef struct x509_st X509; +typedef struct x509_store_st X509_STORE; +typedef struct X509_name_st X509_NAME; +typedef struct ssl_cipher_st SSL_CIPHER; struct SSL; #define STACK_OF(type) struct stack_st_##type diff --git a/dtool/src/parser-inc/openssl/x509.h b/dtool/src/parser-inc/openssl/x509.h index bbd2598dfc..d2bfcbaa5c 100644 --- a/dtool/src/parser-inc/openssl/x509.h +++ b/dtool/src/parser-inc/openssl/x509.h @@ -2,9 +2,7 @@ #ifndef X509_H #define X509_H -struct X509; -struct X509_STORE; -struct X509_NAME; +#include #endif diff --git a/dtool/src/prc/encryptStreamBuf.cxx b/dtool/src/prc/encryptStreamBuf.cxx index 6cb0ee6b39..3d428852d2 100644 --- a/dtool/src/prc/encryptStreamBuf.cxx +++ b/dtool/src/prc/encryptStreamBuf.cxx @@ -21,6 +21,7 @@ #ifdef HAVE_OPENSSL #include "openssl/rand.h" +#include "openssl/evp.h" #ifndef HAVE_STREAMSIZE // Some compilers (notably SGI) don't define this for us diff --git a/dtool/src/prc/encryptStreamBuf.h b/dtool/src/prc/encryptStreamBuf.h index 4861a89240..b7d95424c2 100644 --- a/dtool/src/prc/encryptStreamBuf.h +++ b/dtool/src/prc/encryptStreamBuf.h @@ -19,7 +19,7 @@ // This module is not compiled if OpenSSL is not available. #ifdef HAVE_OPENSSL -#include "openssl/evp.h" +typedef struct evp_cipher_ctx_st EVP_CIPHER_CTX; /** * The streambuf object that implements IDecompressStream and OCompressStream. diff --git a/dtool/src/prc/prcKeyRegistry.cxx b/dtool/src/prc/prcKeyRegistry.cxx index 9b760ac53d..6329a8abbd 100644 --- a/dtool/src/prc/prcKeyRegistry.cxx +++ b/dtool/src/prc/prcKeyRegistry.cxx @@ -19,8 +19,12 @@ #ifdef HAVE_OPENSSL +#include "openssl/evp.h" #include "openssl/pem.h" +// Some versions of OpenSSL appear to define this as a macro. Yucky. +#undef set_key + PrcKeyRegistry *PrcKeyRegistry::_global_ptr = NULL; /** diff --git a/dtool/src/prc/prcKeyRegistry.h b/dtool/src/prc/prcKeyRegistry.h index 1b53287215..69e25d949e 100644 --- a/dtool/src/prc/prcKeyRegistry.h +++ b/dtool/src/prc/prcKeyRegistry.h @@ -22,10 +22,8 @@ #ifdef HAVE_OPENSSL #include -#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 diff --git a/panda/src/downloader/bioPtr.I b/panda/src/downloader/bioPtr.I index f09ee7bbc8..a1e1f13e1d 100644 --- a/panda/src/downloader/bioPtr.I +++ b/panda/src/downloader/bioPtr.I @@ -18,14 +18,6 @@ INLINE BioPtr:: BioPtr(BIO *bio) : _bio(bio) { } -/** - * - */ -INLINE bool BioPtr:: -should_retry() const { - return (_bio != NULL) && BIO_should_retry(_bio); -} - /** * */ diff --git a/panda/src/downloader/bioPtr.cxx b/panda/src/downloader/bioPtr.cxx index 15fe997c02..b86f37f816 100644 --- a/panda/src/downloader/bioPtr.cxx +++ b/panda/src/downloader/bioPtr.cxx @@ -18,6 +18,9 @@ #include "urlSpec.h" #include "config_downloader.h" +#include "openSSLWrapper.h" // must be included before any other openssl. +#include "openssl/ssl.h" + #ifdef _WIN32 #include #else @@ -199,7 +202,7 @@ connect() { if (result != 0 && BIO_sock_should_retry(-1)) { // It's still in progress; we should retry later. This causes - // should_reply() to return true. + // should_retry() to return true. BIO_set_flags(_bio, BIO_FLAGS_SHOULD_RETRY); _connecting = true; return false; @@ -218,6 +221,14 @@ connect() { return true; } +/** + * + */ +bool BioPtr:: +should_retry() const { + return (_bio != NULL) && BIO_should_retry(_bio); +} + /** * */ diff --git a/panda/src/downloader/bioPtr.h b/panda/src/downloader/bioPtr.h index 332a1fc715..090ae20608 100644 --- a/panda/src/downloader/bioPtr.h +++ b/panda/src/downloader/bioPtr.h @@ -19,13 +19,7 @@ // This module is not compiled if OpenSSL is not available. #ifdef HAVE_OPENSSL -#ifndef OPENSSL_NO_KRB5 -#define OPENSSL_NO_KRB5 -#endif - #include "referenceCount.h" -#include "openSSLWrapper.h" // must be included before any other openssl. -#include "openssl/ssl.h" #ifdef _WIN32 #include @@ -35,6 +29,8 @@ #include #endif +typedef struct bio_st BIO; + class URLSpec; /** @@ -52,7 +48,7 @@ public: void set_nbio(bool nbio); bool connect(); - INLINE bool should_retry() const; + bool should_retry() const; INLINE BIO &operator *() const; INLINE BIO *operator -> () const; diff --git a/panda/src/downloader/bioStreamBuf.h b/panda/src/downloader/bioStreamBuf.h index c9174b30b1..0378d9db65 100644 --- a/panda/src/downloader/bioStreamBuf.h +++ b/panda/src/downloader/bioStreamBuf.h @@ -19,14 +19,8 @@ // This module is not compiled if OpenSSL is not available. #ifdef HAVE_OPENSSL -#ifndef OPENSSL_NO_KRB5 -#define OPENSSL_NO_KRB5 -#endif - #include "bioPtr.h" #include "pointerTo.h" -#include "openSSLWrapper.h" // must be included before any other openssl. -#include "openssl/ssl.h" /** * The streambuf object that implements IBioStream. diff --git a/panda/src/downloader/bioStreamPtr.h b/panda/src/downloader/bioStreamPtr.h index aa5c8a28bf..3f23040d20 100644 --- a/panda/src/downloader/bioStreamPtr.h +++ b/panda/src/downloader/bioStreamPtr.h @@ -19,14 +19,8 @@ // This module is not compiled if OpenSSL is not available. #ifdef HAVE_OPENSSL -#ifndef OPENSSL_NO_KRB5 -#define OPENSSL_NO_KRB5 -#endif - #include "bioStream.h" #include "referenceCount.h" -#include "openSSLWrapper.h" // must be included before any other openssl. -#include "openssl/ssl.h" /** * A wrapper around an BioStream object to make a reference-counting pointer diff --git a/panda/src/downloader/httpChannel.cxx b/panda/src/downloader/httpChannel.cxx index 3c90d63c3c..a7eb5f58d3 100644 --- a/panda/src/downloader/httpChannel.cxx +++ b/panda/src/downloader/httpChannel.cxx @@ -27,6 +27,8 @@ #ifdef HAVE_OPENSSL +#include "openSSLWrapper.h" + #if defined(WIN32_VC) || defined(WIN64_VC) #include #include // for select() diff --git a/panda/src/downloader/httpChannel.h b/panda/src/downloader/httpChannel.h index 4c4ddfa312..b9131eba9a 100644 --- a/panda/src/downloader/httpChannel.h +++ b/panda/src/downloader/httpChannel.h @@ -22,10 +22,6 @@ #ifdef HAVE_OPENSSL -#ifndef OPENSSL_NO_KRB5 -#define OPENSSL_NO_KRB5 -#endif - #include "httpClient.h" #include "httpEnum.h" #include "urlSpec.h" @@ -37,10 +33,10 @@ #include "pointerTo.h" #include "config_downloader.h" #include "filename.h" -#include "openSSLWrapper.h" // must be included before any other openssl. -#include "openssl/ssl.h" #include "typedReferenceCount.h" +typedef struct bio_st BIO; + class Ramfile; class HTTPClient; diff --git a/panda/src/downloader/httpClient.cxx b/panda/src/downloader/httpClient.cxx index 129d5fb6be..4770d6916d 100644 --- a/panda/src/downloader/httpClient.cxx +++ b/panda/src/downloader/httpClient.cxx @@ -24,6 +24,8 @@ #ifdef HAVE_OPENSSL +#include "openSSLWrapper.h" + PT(HTTPClient) HTTPClient::_global_ptr; /** @@ -68,6 +70,68 @@ tokenize(const string &str, vector_string &words, const string &delimiters) { words.push_back(string()); } +#ifndef NDEBUG +/** + * This method is attached as a callback for SSL messages only when debug + * output is enabled. + */ +static void +ssl_msg_callback(int write_p, int version, int content_type, + const void *, size_t len, SSL *, void *) { + ostringstream describe; + if (write_p) { + describe << "sent "; + } else { + describe << "received "; + } + switch (version) { + case SSL2_VERSION: + describe << "SSL 2.0 "; + break; + + case SSL3_VERSION: + describe << "SSL 3.0 "; + break; + + case TLS1_VERSION: + describe << "TLS 1.0 "; + break; + + default: + describe << "unknown protocol "; + } + + describe << "message: "; + + if (version != SSL2_VERSION) { + switch (content_type) { + case 20: + describe << "change cipher spec, "; + break; + + case 21: + describe << "alert, "; + break; + + case 22: + describe << "handshake, "; + break; + + case 23: + describe << "application data, "; + break; + + default: + describe << "unknown content type, "; + } + } + + describe << len << " bytes.\n"; + + downloader_cat.debug() << describe.str(); +} +#endif // !defined(NDEBUG) + /** * */ @@ -1564,68 +1628,6 @@ split_whitespace(string &a, string &b, const string &c) { b = c.substr(p); } -#ifndef NDEBUG -/** - * This method is attached as a callback for SSL messages only when debug - * output is enabled. - */ -void HTTPClient:: -ssl_msg_callback(int write_p, int version, int content_type, - const void *, size_t len, SSL *, void *) { - ostringstream describe; - if (write_p) { - describe << "sent "; - } else { - describe << "received "; - } - switch (version) { - case SSL2_VERSION: - describe << "SSL 2.0 "; - break; - - case SSL3_VERSION: - describe << "SSL 3.0 "; - break; - - case TLS1_VERSION: - describe << "TLS 1.0 "; - break; - - default: - describe << "unknown protocol "; - } - - describe << "message: "; - - if (version != SSL2_VERSION) { - switch (content_type) { - case 20: - describe << "change cipher spec, "; - break; - - case 21: - describe << "alert, "; - break; - - case 22: - describe << "handshake, "; - break; - - case 23: - describe << "application data, "; - break; - - default: - describe << "unknown content type, "; - } - } - - describe << len << " bytes.\n"; - - downloader_cat.debug() << describe.str(); -} -#endif // !defined(NDEBUG) - /** * */ diff --git a/panda/src/downloader/httpClient.h b/panda/src/downloader/httpClient.h index d901066357..1efab58460 100644 --- a/panda/src/downloader/httpClient.h +++ b/panda/src/downloader/httpClient.h @@ -32,7 +32,11 @@ #include "pmap.h" #include "pset.h" #include "referenceCount.h" -#include "openSSLWrapper.h" + +typedef struct ssl_ctx_st SSL_CTX; +typedef struct x509_st X509; +typedef struct X509_name_st X509_NAME; +typedef struct evp_pkey_st EVP_PKEY; class Filename; class HTTPChannel; @@ -155,12 +159,6 @@ private: static void split_whitespace(string &a, string &b, const string &c); -#ifndef NDEBUG - static void ssl_msg_callback(int write_p, int version, int content_type, - const void *buf, size_t len, SSL *ssl, - void *arg); -#endif - typedef pvector Proxies; typedef pmap ProxiesByScheme; ProxiesByScheme _proxies_by_scheme; diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index 2f7cda439b..0d98849efe 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -26,6 +26,8 @@ #include #include +#include "openSSLWrapper.h" + // This sequence of bytes begins each Multifile to identify it as a Multifile. const char Multifile::_header[] = "pmf\0\n\r"; const size_t Multifile::_header_size = 6; @@ -768,43 +770,6 @@ add_signature(const Filename &composite, const string &password) { } #endif // HAVE_OPENSSL -#ifdef HAVE_OPENSSL -/** - * Adds a new signature to the Multifile. This signature associates the - * indicated certificate with the current contents of the Multifile. When the - * Multifile is read later, the signature will still be present only if the - * Multifile is unchanged; any subsequent changes to the Multifile will - * automatically invalidate and remove the signature. - * - * If chain is non-NULL, it represents the certificate chain that validates - * the certificate. - * - * The specified private key must match the certificate, and the Multifile - * must be open in read-write mode. The private key is only used for - * generating the signature; it is not written to the Multifile and cannot be - * retrieved from the Multifile later. (However, the certificate *can* be - * retrieved from the Multifile later, to identify the entity that created the - * signature.) - * - * This implicitly causes a repack() operation if one is needed. Returns true - * on success, false on failure. - */ -bool Multifile:: -add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey) { - // Convert the certificate and chain into our own CertChain structure. - CertChain cert_chain; - cert_chain.push_back(CertRecord(certificate)); - if (chain != NULL) { - int num = sk_X509_num(chain); - for (int i = 0; i < num; ++i) { - cert_chain.push_back(CertRecord((X509 *)sk_X509_value(chain, i))); - } - } - - return add_signature(cert_chain, pkey); -} -#endif // HAVE_OPENSSL - #ifdef HAVE_OPENSSL /** * Adds a new signature to the Multifile. This signature associates the diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index 578ac70d6d..5c6ec16feb 100644 --- a/panda/src/express/multifile.h +++ b/panda/src/express/multifile.h @@ -24,7 +24,11 @@ #include "indirectLess.h" #include "referenceCount.h" #include "pvector.h" -#include "openSSLWrapper.h" + +#ifdef HAVE_OPENSSL +typedef struct x509_st X509; +typedef struct evp_pkey_st EVP_PKEY; +#endif /** * A file that contains a set of files. @@ -148,7 +152,6 @@ public: }; typedef pvector CertChain; - bool add_signature(X509 *certificate, STACK_OF(X509) *chain, EVP_PKEY *pkey); bool add_signature(const CertChain &chain, EVP_PKEY *pkey); const CertChain &get_signature(int n) const; From 4cc2009a940781837dc1b00447a6accfae6964d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E7=BE=A4?= <517067180@qq.com> Date: Sat, 18 Feb 2017 16:24:58 +0800 Subject: [PATCH 06/19] Correct several spelling mistakes in comments --- samples/chessboard/main.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/chessboard/main.py b/samples/chessboard/main.py index 7da1d97a14..5c8b68302d 100755 --- a/samples/chessboard/main.py +++ b/samples/chessboard/main.py @@ -20,7 +20,7 @@ from direct.showbase.DirectObject import DirectObject from direct.task.Task import Task import sys -# First we define some contants for the colors +# First we define some constants for the colors BLACK = (0, 0, 0, 1) WHITE = (1, 1, 1, 1) HIGHLIGHT = (0, 1, 1, 1) @@ -33,7 +33,7 @@ PIECEBLACK = (.15, .15, .15, 1) # This is how we know where to position an object in 3D space based on a 2D mouse # position. It also assumes that we are dragging in the XY plane. # -# This is derived from the mathmatical of a plane, solved for a given point +# This is derived from the mathematical of a plane, solved for a given point def PointAtZ(z, point, vec): return point + vec * ((z - point.getZ()) / vec.getZ()) @@ -41,7 +41,7 @@ def PointAtZ(z, point, vec): def SquarePos(i): return LPoint3((i % 8) - 3.5, int(i // 8) - 3.5, 0) -# Helper function for determining wheter a square should be white or black +# Helper function for determining whether a square should be white or black # The modulo operations (%) generate the every-other pattern of a chess-board def SquareColor(i): if (i + ((i // 8) % 2)) % 2: @@ -84,7 +84,7 @@ class ChessboardDemo(ShowBase): # relative to it self.pickerNP = camera.attachNewNode(self.pickerNode) # Everything to be picked will use bit 1. This way if we were doing other - # collision we could seperate it + # collision we could separate it self.pickerNode.setFromCollideMask(BitMask32.bit(1)) self.pickerRay = CollisionRay() # Make our ray # Add it to the collision node @@ -96,7 +96,7 @@ class ChessboardDemo(ShowBase): # Now we create the chess board and its pieces # We will attach all of the squares to their own root. This way we can do the - # collision pass just on the sqaures and save the time of checking the rest + # collision pass just on the squares and save the time of checking the rest # of the scene self.squareRoot = render.attachNewNode("squareRoot") @@ -240,7 +240,7 @@ class ChessboardDemo(ShowBase): render.setLight(render.attachNewNode(ambientLight)) -# Class for a piece. This just handels loading the model and setting initial +# Class for a piece. This just handles loading the model and setting initial # position and color class Piece(object): def __init__(self, square, color): From aa00138b34c8ce350e7754a8bab9028119bb02c8 Mon Sep 17 00:00:00 2001 From: Jose Luis Cercos Pita Date: Sun, 19 Feb 2017 20:13:03 +0100 Subject: [PATCH 07/19] Support core-only OpenGL contexts in the default build. This is a squashed commit of the following, as well as my own (rdb's) revisions: commit 80662759a18607743316f75ee6aa4a63c3f8d8e6 Author: Jose Luis Cercos Pita Date: Thu Dec 1 15:07:29 2016 +0100 Removed some useless fixed pipeline checks commit 563b5dbe93b451006ddbf3797aabdda7482ef3de Author: Jose Luis Cercos Pita Date: Thu Dec 1 14:19:21 2016 +0100 Improved the LUMINANCE check system commit 596036a8bb59d627f703bccfdc399dc31e1723a9 Author: Jose Luis Cercos Pita Date: Thu Dec 1 13:30:45 2016 +0100 Removed some useless fixed pipeline checks commit 0f7fa7cd33860c3cde1b4594731271170301b42d Author: Jose Luis Cercos Pita Date: Thu Dec 1 13:26:07 2016 +0100 Don't try to check if fixed pipeline is available before the context has been generated commit 56ed18e29dcb0a7cb0feccd0d50038416637427f Author: Jose Luis Cercos Pita Date: Thu Dec 1 13:14:49 2016 +0100 Assuming the fixed pipeline is available in GL 3.1 contexts commit 73075ead73be21c8ce9a468ed92eb2c8c7d548c4 Author: Jose Luis Cercos Pita Date: Fri Nov 4 12:59:45 2016 +0100 Fixed errors while quering for GL_TEXTURE_LUMINANCE_SIZE and GL_TEXTURE_INTENSITY_SIZE in GL >= 4.0 core profile contexts commit 3f799ed20be22f6f82de13445c5f9515a424ef9f Author: Jose Luis Cercos Pita Date: Fri Dec 16 10:01:03 2016 +0100 Added fixed functions pipeline support check at runtime Closes: 128 --- panda/src/display/graphicsStateGuardian.I | 8 + panda/src/display/graphicsStateGuardian.cxx | 3 + panda/src/display/graphicsStateGuardian.h | 3 + panda/src/glstuff/glCgShaderContext_src.cxx | 19 +- panda/src/glstuff/glGraphicsBuffer_src.cxx | 6 +- .../src/glstuff/glGraphicsStateGuardian_src.I | 29 +- .../glstuff/glGraphicsStateGuardian_src.cxx | 543 ++++++++++-------- .../src/glstuff/glGraphicsStateGuardian_src.h | 6 + 8 files changed, 383 insertions(+), 234 deletions(-) diff --git a/panda/src/display/graphicsStateGuardian.I b/panda/src/display/graphicsStateGuardian.I index 15f95a19f4..94188b85be 100644 --- a/panda/src/display/graphicsStateGuardian.I +++ b/panda/src/display/graphicsStateGuardian.I @@ -538,6 +538,14 @@ get_supports_depth_stencil() const { return _supports_depth_stencil; } +/** + * Returns true if this particular GSG supports luminance textures. + */ +INLINE bool GraphicsStateGuardian:: +get_supports_luminance_texture() const { + return _supports_luminance_texture; +} + /** * Returns true if this particular GSG supports the filter mode FT_shadow for * depth textures. diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 7f87e87d8e..5b46251ba8 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -253,6 +253,9 @@ GraphicsStateGuardian(CoordinateSystem internal_coordinate_system, _supports_geometry_instancing = false; _supports_indirect_draw = false; + // We are safe assuming it has luminance support + _supports_luminance_texture = true; + // Assume a maximum of 1 render target in absence of MRT. _max_color_targets = 1; _supports_dual_source_blending = false; diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index 81643a1f11..a5dbce4a11 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -154,6 +154,7 @@ PUBLISHED: INLINE bool get_supports_generate_mipmap() const; INLINE bool get_supports_depth_texture() const; INLINE bool get_supports_depth_stencil() const; + INLINE bool get_supports_luminance_texture() const; INLINE bool get_supports_shadow_filter() const; INLINE bool get_supports_sampler_objects() const; INLINE bool get_supports_basic_shaders() const; @@ -203,6 +204,7 @@ PUBLISHED: MAKE_PROPERTY(supports_generate_mipmap, get_supports_generate_mipmap); MAKE_PROPERTY(supports_depth_texture, get_supports_depth_texture); MAKE_PROPERTY(supports_depth_stencil, get_supports_depth_stencil); + MAKE_PROPERTY(supports_luminance_texture, get_supports_luminance_texture); MAKE_PROPERTY(supports_shadow_filter, get_supports_shadow_filter); MAKE_PROPERTY(supports_sampler_objects, get_supports_sampler_objects); MAKE_PROPERTY(supports_basic_shaders, get_supports_basic_shaders); @@ -597,6 +599,7 @@ protected: bool _supports_generate_mipmap; bool _supports_depth_texture; bool _supports_depth_stencil; + bool _supports_luminance_texture; bool _supports_shadow_filter; bool _supports_sampler_objects; bool _supports_basic_shaders; diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index c857948b97..8497c7de71 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -145,7 +145,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte if (cgGetParameterBaseResource(p) == CG_ATTR0) { // The Cg toolkit claims that it is bound to a generic vertex attribute. - if (_glsl_program != 0) { + if (_glgsg->has_fixed_function_pipeline() && _glsl_program != 0) { // This is where the Cg glslv compiler lies, making the stupid // assumption that we're using an NVIDIA card where generic attributes // are aliased with conventional vertex attributes. Instead, it @@ -246,7 +246,7 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte // A conventional texture coordinate set. loc = CA_texcoord + cgGetParameterResourceIndex(p); - } else { + } else if (_glgsg->has_fixed_function_pipeline()) { // Some other conventional vertex attribute. switch (res) { case CG_POSITION0: @@ -276,6 +276,14 @@ CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderConte GLCAT.error(false) << ".\n"; loc = CA_unknown; } + } else { + GLCAT.error() + << "Cg varying " << cgGetParameterName(p); + if (cgGetParameterSemantic(p)) { + GLCAT.error(false) << " : " << cgGetParameterSemantic(p); + } + GLCAT.error(false) << " is bound to a conventional vertex attribute, " + "but the compatibility profile is not enabled.\n"; } #ifndef NDEBUG @@ -916,8 +924,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { } else { // There is no vertex column with this name; disable the attribute // array. -#ifdef SUPPORT_FIXED_FUNCTION - if (p == 0) { + if (_glgsg->has_fixed_function_pipeline() && p == 0) { // NOTE: if we disable attribute 0 in compatibility profile, the // object will disappear. In GLSL we fix this by forcing the vertex // column to be at 0, but we don't have control over that with Cg. @@ -930,9 +937,7 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) { _glgsg->_glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); } - } else -#endif // SUPPORT_FIXED_FUNCTION - if (p >= 0) { + } else if (p >= 0) { _glgsg->disable_vertex_attrib_array(p); if (p == _color_attrib_index) { diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 3a73d175c4..706bb03049 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -1165,8 +1165,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) { glgsg->apply_texture(gtc); #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) - GLclampf priority = 1.0f; - glPrioritizeTextures(1, >c->_index, &priority); + if (glgsg->has_fixed_function_pipeline()) { + GLclampf priority = 1.0f; + glPrioritizeTextures(1, >c->_index, &priority); + } #endif #ifndef OPENGLES diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.I b/panda/src/glstuff/glGraphicsStateGuardian_src.I index 221aff21b9..5ce7902917 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.I +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.I @@ -130,6 +130,33 @@ get_gl_version_minor() const { return _gl_version_minor; } +/** + * Returns whether a core profile or a compatibility mode is considered. + */ +/*INLINE bool CLP(GraphicsStateGuardian):: +has_core_profile() const { + return _core_profile; +}*/ + +/** + * Returns whether the fixed function pipeline is supported. + */ +INLINE bool CLP(GraphicsStateGuardian):: +has_fixed_function_pipeline() const { +#ifndef SUPPORT_FIXED_FUNCTION + return false; +#elif defined(OPENGLES_1) + return true; +#elif defined(OPENGLES) + return false; +#else + // Otherwise, we can just check whether we are using a core profile or a + // compatibility mode. The variable _core_profile is already taking into + // account if a GL < 3.2 is considered (becoming false) + return !_core_profile; +#endif +} + /** * Calls glFinish() if the config variable gl-finish is set True. */ @@ -363,7 +390,7 @@ enable_line_smooth(bool val) { INLINE void CLP(GraphicsStateGuardian):: enable_point_smooth(bool val) { #ifdef SUPPORT_FIXED_FUNCTION - if (_point_smooth_enabled != val) { + if (has_fixed_function_pipeline() && _point_smooth_enabled != val) { _state_mask.clear_bit(TransparencyAttrib::get_class_slot()); _point_smooth_enabled = val; if (val) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 98c21610c5..c83c9e52c0 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -369,6 +369,12 @@ CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) : _gl_shadlang_ver_major = 0; _gl_shadlang_ver_minor = 0; + // Let's say we have a core profile, to be checked later (Otherwise, if we are + // wrong the user may ask for some non-available functions) +#ifndef OPENGLES + _core_profile = true; +#endif + // Hack. Turn on the flag that we turned off at a higher level, since we // know this works properly in OpenGL, and we want the performance benefit // it gives us. @@ -547,6 +553,7 @@ reset() { GLCAT.debug() << "Using compatibility profile\n"; } } + _core_profile = core_profile; #elif defined(OPENGLES_1) static const bool core_profile = false; #else @@ -723,7 +730,7 @@ reset() { #endif #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) - if (is_at_least_gl_version(1, 4)) { + if (has_fixed_function_pipeline() && is_at_least_gl_version(1, 4)) { _glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC) get_extension_func("glSecondaryColorPointer"); @@ -1105,12 +1112,13 @@ reset() { _supports_rescale_normal = true; #else _supports_rescale_normal = - !core_profile && gl_support_rescale_normal && + has_fixed_function_pipeline() && gl_support_rescale_normal && (is_at_least_gl_version(1, 2) || has_extension("GL_EXT_rescale_normal")); #endif #ifndef OPENGLES - _use_separate_specular_color = gl_separate_specular_color && + _use_separate_specular_color = + has_fixed_function_pipeline() && gl_separate_specular_color && (is_at_least_gl_version(1, 2) || has_extension("GL_EXT_separate_specular_color")); #endif #endif // SUPPORT_FIXED_FUNCTION @@ -1162,8 +1170,10 @@ reset() { get_extension_func("glActiveTexture"); #ifdef SUPPORT_FIXED_FUNCTION - _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC) - get_extension_func("glClientActiveTexture"); + if (has_fixed_function_pipeline()) { + _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC) + get_extension_func("glClientActiveTexture"); + } #endif #ifdef SUPPORT_IMMEDIATE_MODE @@ -1192,8 +1202,10 @@ reset() { get_extension_func("glActiveTextureARB"); #ifdef SUPPORT_FIXED_FUNCTION - _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC) - get_extension_func("glClientActiveTextureARB"); + if (has_fixed_function_pipeline()) { + _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC) + get_extension_func("glClientActiveTextureARB"); + } #endif #ifdef SUPPORT_IMMEDIATE_MODE @@ -1221,7 +1233,7 @@ reset() { if (supports_multitexture) { if (_glActiveTexture == NULL #ifdef SUPPORT_FIXED_FUNCTION - || _glClientActiveTexture == NULL + || (has_fixed_function_pipeline() && _glClientActiveTexture == NULL) #endif #ifdef SUPPORT_IMMEDIATE_MODE || GLf(_glMultiTexCoord1) == NULL || GLf(_glMultiTexCoord2) == NULL @@ -1240,7 +1252,7 @@ reset() { } #ifdef SUPPORT_FIXED_FUNCTION - if (!supports_multitexture || core_profile) { + if (!supports_multitexture || !has_fixed_function_pipeline()) { _glClientActiveTexture = null_glActiveTexture; } #endif @@ -1251,6 +1263,7 @@ reset() { _supports_depth_stencil = has_extension("GL_OES_packed_depth_stencil"); _supports_depth24 = has_extension("GL_OES_depth24"); _supports_depth32 = has_extension("GL_OES_depth32"); + _supports_luminance_texture = true; #elif defined(OPENGLES) if (is_at_least_gles_version(3, 0)) { @@ -1271,12 +1284,16 @@ reset() { _supports_depth24 = has_extension("GL_OES_depth24"); _supports_depth32 = has_extension("GL_OES_depth32"); } + _supports_luminance_texture = true; #else _supports_depth_texture = (is_at_least_gl_version(1, 4) || has_extension("GL_ARB_depth_texture")); _supports_depth_stencil = (is_at_least_gl_version(3, 0) || has_extension("GL_ARB_framebuffer_object") || has_extension("GL_EXT_packed_depth_stencil")); + + // OpenGL 3 deprecates luminance, luminance-alpha and alpha textures. + _supports_luminance_texture = !core_profile; #endif #ifdef OPENGLES_2 @@ -1300,12 +1317,11 @@ reset() { _supports_shadow_filter = false; }*/ -#ifndef SUPPORT_FIXED_FUNCTION _supports_texture_combine = false; _supports_texture_saved_result = false; _supports_texture_dot3 = false; -#else - if (!core_profile) { +#ifdef SUPPORT_FIXED_FUNCTION + if (has_fixed_function_pipeline()) { _supports_texture_combine = is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1) || @@ -1786,12 +1802,8 @@ reset() { // We need to have a default shader to apply in case something didn't happen // to have a shader applied, or if it failed to compile. This default // shader just outputs a red color, indicating that something went wrong. -#ifndef SUPPORT_FIXED_FUNCTION - if (_default_shader == NULL) { - _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader); - } -#elif !defined(OPENGLES) - if (_default_shader == NULL && core_profile) { +#ifndef OPENGLES_1 + if (_default_shader == NULL && !has_fixed_function_pipeline()) { _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader); } #endif @@ -2943,7 +2955,7 @@ reset() { glDisable(GL_LINE_SMOOTH); #endif #ifdef SUPPORT_FIXED_FUNCTION - if (!core_profile) { + if (has_fixed_function_pipeline()) { glDisable(GL_POINT_SMOOTH); } #endif @@ -2995,7 +3007,7 @@ reset() { // Count the max number of lights _max_lights = 0; #ifdef SUPPORT_FIXED_FUNCTION - if (!core_profile) { + if (has_fixed_function_pipeline()) { GLint max_lights = 0; glGetIntegerv(GL_MAX_LIGHTS, &max_lights); _max_lights = max_lights; @@ -3010,7 +3022,7 @@ reset() { // Count the max number of clipping planes _max_clip_planes = 0; #ifdef SUPPORT_FIXED_FUNCTION - if (!core_profile) { + if (has_fixed_function_pipeline()) { GLint max_clip_planes = 0; glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes); _max_clip_planes = max_clip_planes; @@ -3024,7 +3036,7 @@ reset() { _max_texture_stages = 1; #ifdef SUPPORT_FIXED_FUNCTION - if (supports_multitexture && !core_profile) { + if (supports_multitexture && has_fixed_function_pipeline()) { GLint max_texture_stages = 0; glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_stages); _max_texture_stages = max_texture_stages; @@ -3057,7 +3069,7 @@ reset() { report_my_gl_errors(); #ifdef SUPPORT_FIXED_FUNCTION - if (!core_profile) { + if (has_fixed_function_pipeline()) { if (gl_cheap_textures) { GLCAT.info() << "Setting glHint() for fastest textures.\n"; @@ -3070,7 +3082,7 @@ reset() { #endif #ifdef SUPPORT_FIXED_FUNCTION - if (!core_profile) { + if (has_fixed_function_pipeline()) { GLint num_red_bits = 0; glGetIntegerv(GL_RED_BITS, &num_red_bits); if (num_red_bits < 8) { @@ -3538,7 +3550,9 @@ prepare_display_region(DisplayRegionPipelineReader *dr) { void CLP(GraphicsStateGuardian):: clear_before_callback() { #ifdef SUPPORT_FIXED_FUNCTION - disable_standard_vertex_arrays(); + if (has_fixed_function_pipeline()) { + disable_standard_vertex_arrays(); + } #endif #ifndef OPENGLES_1 if (_vertex_array_shader_context != 0) { @@ -3620,16 +3634,18 @@ calc_projection_mat(const Lens *lens) { bool CLP(GraphicsStateGuardian):: prepare_lens() { #ifdef SUPPORT_FIXED_FUNCTION - if (GLCAT.is_spam()) { - GLCAT.spam() - << "glMatrixMode(GL_PROJECTION): " << _projection_mat->get_mat() << endl; + if (has_fixed_function_pipeline()) { + if (GLCAT.is_spam()) { + GLCAT.spam() + << "glMatrixMode(GL_PROJECTION): " << _projection_mat->get_mat() << endl; + } + + glMatrixMode(GL_PROJECTION); + call_glLoadMatrix(_projection_mat->get_mat()); + report_my_gl_errors(); + + do_point_size(); } - - glMatrixMode(GL_PROJECTION); - call_glLoadMatrix(_projection_mat->get_mat()); - report_my_gl_errors(); - - do_point_size(); #endif #ifndef OPENGLES_1 @@ -3762,7 +3778,7 @@ end_frame(Thread *current_thread) { // will just mean that we'll count everything as resident until the user // connects PStats, at which point it will then correct the assessment. No // harm done. - if (PStatClient::is_connected()) { + if (has_fixed_function_pipeline() && PStatClient::is_connected()) { check_nonresident_texture(_prepared_objects->_texture_residency.get_inactive_resident()); check_nonresident_texture(_prepared_objects->_texture_residency.get_active_resident()); @@ -3813,7 +3829,7 @@ end_frame(Thread *current_thread) { // Now is a good time to delete any pending display lists. #ifndef OPENGLES #ifdef SUPPORT_FIXED_FUNCTION - if (display_lists) { + if (has_fixed_function_pipeline() && display_lists) { LightMutexHolder holder(_lock); if (!_deleted_display_lists.empty()) { DeletedNames::iterator ddli; @@ -3922,11 +3938,13 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, } #endif // NDEBUG -#ifndef SUPPORT_FIXED_FUNCTION - // We can't draw without a shader bound in OpenGL ES 2. This shouldn't - // happen anyway unless the default shader failed to compile somehow. - if (_current_shader_context == NULL) { - return false; +#ifndef OPENGLES_1 + if (!has_fixed_function_pipeline()) { + // We can't draw without a shader bound in OpenGL ES 2. This shouldn't + // happen anyway unless the default shader failed to compile somehow. + if (_current_shader_context == NULL) { + return false; + } } #endif @@ -3967,7 +3985,7 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, } #ifdef SUPPORT_FIXED_FUNCTION - if (_data_reader->is_vertex_transformed()) { + if (has_fixed_function_pipeline() && _data_reader->is_vertex_transformed()) { // If the vertex data claims to be already transformed into clip // coordinates, wipe out the current projection and modelview matrix (so // we don't attempt to transform it again). @@ -3981,7 +3999,8 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, #endif #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) // Display lists not supported by OpenGL ES. - if (/*geom_reader->get_usage_hint() == Geom::UH_static &&*/ + if (has_fixed_function_pipeline() && + /*geom_reader->get_usage_hint() == Geom::UH_static &&*/ _data_reader->get_usage_hint() == Geom::UH_static && display_lists) { // If the geom claims to be totally static, try to build it into a display @@ -4072,33 +4091,35 @@ begin_draw_primitives(const GeomPipelineReader *geom_reader, _vertex_array_shader_context->disable_shader_vertex_arrays(); } #ifdef SUPPORT_FIXED_FUNCTION - if (!update_standard_vertex_arrays(force)) { + if (has_fixed_function_pipeline() && !update_standard_vertex_arrays(force)) { return false; } #endif } else { #ifdef SUPPORT_FIXED_FUNCTION - // Shader. - if (_vertex_array_shader_context == 0 || - _vertex_array_shader_context->uses_standard_vertex_arrays()) { - // Previous shader used standard arrays. - if (_current_shader_context->uses_standard_vertex_arrays()) { - // So does the current, so update them. - if (!update_standard_vertex_arrays(force)) { - return false; + if (has_fixed_function_pipeline()) { + // Shader. + if (_vertex_array_shader_context == 0 || + _vertex_array_shader_context->uses_standard_vertex_arrays()) { + // Previous shader used standard arrays. + if (_current_shader_context->uses_standard_vertex_arrays()) { + // So does the current, so update them. + if (!update_standard_vertex_arrays(force)) { + return false; + } + } else { + // The current shader does not, so disable them entirely. + disable_standard_vertex_arrays(); } - } else { - // The current shader does not, so disable them entirely. - disable_standard_vertex_arrays(); } - } #ifdef HAVE_CG - else if (_vertex_array_shader_context->is_of_type(CLP(CgShaderContext)::get_class_type())) { - // The previous shader was a Cg shader, which can leave a messy - // situation. - _vertex_array_shader_context->disable_shader_vertex_arrays(); - } + else if (_vertex_array_shader_context->is_of_type(CLP(CgShaderContext)::get_class_type())) { + // The previous shader was a Cg shader, which can leave a messy + // situation. + _vertex_array_shader_context->disable_shader_vertex_arrays(); + } #endif + } #endif // SUPPORT_FIXED_FUNCTION // Now update the vertex arrays for the current shader. if (!_current_shader_context-> @@ -4334,7 +4355,9 @@ unbind_buffers() { #endif #ifdef SUPPORT_FIXED_FUNCTION - disable_standard_vertex_arrays(); + if (has_fixed_function_pipeline()) { + disable_standard_vertex_arrays(); + } #endif } @@ -5040,7 +5063,7 @@ draw_points(const GeomPrimitivePipelineReader *reader, bool force) { void CLP(GraphicsStateGuardian):: end_draw_primitives() { #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) // Display lists not supported by OpenGL ES. - if (_geom_display_list != 0) { + if (has_fixed_function_pipeline() && _geom_display_list != 0) { // If we were building a display list, close it now. glEndList(); _load_display_list_pcollector.stop(); @@ -5054,12 +5077,12 @@ end_draw_primitives() { #endif #ifdef SUPPORT_FIXED_FUNCTION - if (_transform_stale) { + if (has_fixed_function_pipeline() && _transform_stale) { glMatrixMode(GL_MODELVIEW); call_glLoadMatrix(_internal_transform->get_mat()); } - if (_data_reader->is_vertex_transformed()) { + if (has_fixed_function_pipeline() && _data_reader->is_vertex_transformed()) { // Restore the matrices that we pushed above. glMatrixMode(GL_PROJECTION); glPopMatrix(); @@ -5436,7 +5459,9 @@ prepare_geom(Geom *geom) { void CLP(GraphicsStateGuardian):: release_geom(GeomContext *gc) { CLP(GeomContext) *ggc = DCAST(CLP(GeomContext), gc); - ggc->release_display_lists(); + if (has_fixed_function_pipeline()) { + ggc->release_display_lists(); + } report_my_gl_errors(); delete ggc; @@ -6594,17 +6619,19 @@ apply_fog(Fog *fog) { void CLP(GraphicsStateGuardian):: do_issue_transform() { #ifdef SUPPORT_FIXED_FUNCTION - // OpenGL ES 2 does not support glLoadMatrix. + if (has_fixed_function_pipeline()) { + // OpenGL ES 2 does not support glLoadMatrix. - const TransformState *transform = _internal_transform; - if (GLCAT.is_spam()) { - GLCAT.spam() - << "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl; + const TransformState *transform = _internal_transform; + if (GLCAT.is_spam()) { + GLCAT.spam() + << "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl; + } + + DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1)); + glMatrixMode(GL_MODELVIEW); + call_glLoadMatrix(transform->get_mat()); } - - DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1)); - glMatrixMode(GL_MODELVIEW); - call_glLoadMatrix(transform->get_mat()); #endif _transform_stale = false; @@ -6643,13 +6670,11 @@ do_issue_shader() { ShaderContext *context = 0; Shader *shader = (Shader *)_target_shader->get_shader(); -#ifndef SUPPORT_FIXED_FUNCTION // If we don't have a shader, apply the default shader. - if (!shader) { + if (!has_fixed_function_pipeline() && !shader) { shader = _default_shader; nassertv(shader != NULL); } -#endif if (shader) { if (_current_shader != shader) { @@ -6659,9 +6684,9 @@ do_issue_shader() { } } -#ifndef SUPPORT_FIXED_FUNCTION // If it failed, try applying the default shader. - if (shader != _default_shader && (context == 0 || !context->valid())) { + if (_default_shader != nullptr && shader != _default_shader && + (context == 0 || !context->valid())) { shader = _default_shader; nassertv(shader != NULL); if (_current_shader != shader) { @@ -6670,7 +6695,6 @@ do_issue_shader() { context = _current_shader_context; } } -#endif if (context == 0 || !context->valid()) { if (_current_shader_context != 0) { @@ -6762,7 +6786,9 @@ do_issue_render_mode() { report_my_gl_errors(); #ifdef SUPPORT_FIXED_FUNCTION - do_point_size(); + if (has_fixed_function_pipeline()) { + do_point_size(); + } #endif } @@ -7372,6 +7398,8 @@ do_issue_blending() { */ void CLP(GraphicsStateGuardian):: bind_light(PointLight *light_obj, const NodePath &light, int light_id) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_bind_point_pcollector("Draw:Set // State:Light:Bind:Point"); PStatGPUTimer timer(this, @@ -7416,6 +7444,8 @@ bind_light(PointLight *light_obj, const NodePath &light, int light_id) { */ void CLP(GraphicsStateGuardian):: bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_bind_directional_pcollector("Draw:Set // State:Light:Bind:Directional"); PStatGPUTimer timer(this, @@ -7467,6 +7497,8 @@ bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) { */ void CLP(GraphicsStateGuardian):: bind_light(Spotlight *light_obj, const NodePath &light, int light_id) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_bind_spotlight_pcollector("Draw:Set // State:Light:Bind:Spotlight"); PStatGPUTimer timer(this, @@ -8701,10 +8733,10 @@ get_external_image_format(Texture *tex) const { #endif case Texture::F_alpha: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) +#ifdef OPENGLES return GL_ALPHA; #else - return GL_RED; + return _supports_luminance_texture ? GL_ALPHA : GL_RED; #endif #ifndef OPENGLES_1 @@ -8744,18 +8776,18 @@ get_external_image_format(Texture *tex) const { case Texture::F_luminance: case Texture::F_sluminance: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) +#ifdef OPENGLES return GL_LUMINANCE; #else - return GL_RED; + return _supports_luminance_texture ? GL_LUMINANCE : GL_RED; #endif case Texture::F_luminance_alphamask: case Texture::F_luminance_alpha: case Texture::F_sluminance_alpha: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) +#ifdef OPENGLES return GL_LUMINANCE_ALPHA; #else - return GL_RG; + return _supports_luminance_texture ? GL_LUMINANCE_ALPHA : GL_RG; #endif #ifndef OPENGLES_1 @@ -9402,42 +9434,76 @@ get_internal_image_format(Texture *tex, bool force_sized) const { #endif case Texture::F_alpha: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) +#ifdef OPENGLES return force_sized ? GL_ALPHA8 : GL_ALPHA; #else - return force_sized ? GL_R8 : GL_RED; + if (_supports_luminance_texture) { + return force_sized ? GL_ALPHA8 : GL_ALPHA; + } else { + return force_sized ? GL_R8 : GL_RED; + } #endif case Texture::F_luminance: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) -#ifndef OPENGLES - if (tex->get_component_type() == Texture::T_float) { - return GL_LUMINANCE16F_ARB; - } else if (tex->get_component_type() == Texture::T_short) { - return GL_LUMINANCE16_SNORM; - } else if (tex->get_component_type() == Texture::T_unsigned_short) { - return GL_LUMINANCE16; - } else -#endif // OPENGLES - { - return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE; - } +#ifdef OPENGLES + return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE; #else - return force_sized ? GL_R8 : GL_RED; + if (_supports_luminance_texture) { + switch (tex->get_component_type()) { + case Texture::T_float: + case Texture::T_half_float: + return GL_LUMINANCE16F_ARB; + case Texture::T_short: + return GL_LUMINANCE16_SNORM; + case Texture::T_unsigned_short: + return GL_LUMINANCE16; + default: + return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE; + } + } else { + switch (tex->get_component_type()) { + case Texture::T_float: + case Texture::T_half_float: + return GL_R16F; + case Texture::T_short: + return GL_R16_SNORM; + case Texture::T_unsigned_short: + return GL_R16; + default: + return force_sized ? GL_R8 : GL_RED; + } + } #endif case Texture::F_luminance_alpha: case Texture::F_luminance_alphamask: -#if defined(SUPPORT_FIXED_FUNCTION) || defined(OPENGLES) -#ifndef OPENGLES - if (tex->get_component_type() == Texture::T_float || tex->get_component_type() == Texture::T_unsigned_short) { - return GL_LUMINANCE_ALPHA16F_ARB; - } else -#endif // OPENGLES - { - return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA; - } +#ifdef OPENGLES + return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA; #else - return force_sized ? GL_RG8 : GL_RG; + if (_supports_luminance_texture) { + switch (tex->get_component_type()) { + case Texture::T_float: + case Texture::T_half_float: + return GL_LUMINANCE_ALPHA16F_ARB; + case Texture::T_short: + return GL_LUMINANCE16_SNORM; + case Texture::T_unsigned_short: + return GL_LUMINANCE16_ALPHA16; + default: + return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA; + } + } else { + switch (tex->get_component_type()) { + case Texture::T_float: + case Texture::T_half_float: + return GL_RG16F; + case Texture::T_short: + return GL_RG16_SNORM; + case Texture::T_unsigned_short: + return GL_RG16; + default: + return force_sized ? GL_RG8 : GL_RG; + } + } #endif #ifndef OPENGLES_1 @@ -10019,6 +10085,8 @@ reissue_transforms() { */ void CLP(GraphicsStateGuardian):: enable_lighting(bool enable) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_enable_lighting_pcollector("Draw:Set // State:Light:Enable lighting"); PStatGPUTimer timer(this, @@ -10040,6 +10108,8 @@ enable_lighting(bool enable) { */ void CLP(GraphicsStateGuardian):: set_ambient_light(const LColor &color) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector _draw_set_state_light_ambient_pcollector("Draw:Set // State:Light:Ambient"); PStatGPUTimer timer(this, // _draw_set_state_light_ambient_pcollector); @@ -10061,6 +10131,8 @@ set_ambient_light(const LColor &color) { */ void CLP(GraphicsStateGuardian):: enable_light(int light_id, bool enable) { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_enable_light_pcollector("Draw:Set // State:Light:Enable light"); PStatGPUTimer timer(this, @@ -10085,6 +10157,8 @@ enable_light(int light_id, bool enable) { */ void CLP(GraphicsStateGuardian):: begin_bind_lights() { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector // _draw_set_state_light_begin_bind_pcollector("Draw:Set State:Light:Begin // bind"); PStatGPUTimer timer(this, @@ -10115,6 +10189,8 @@ begin_bind_lights() { */ void CLP(GraphicsStateGuardian):: end_bind_lights() { + nassertv(has_fixed_function_pipeline()); + // static PStatCollector _draw_set_state_light_end_bind_pcollector("Draw:Set // State:Light:End bind"); PStatGPUTimer timer(this, // _draw_set_state_light_end_bind_pcollector); @@ -10132,6 +10208,8 @@ end_bind_lights() { */ void CLP(GraphicsStateGuardian):: enable_clip_plane(int plane_id, bool enable) { + nassertv(has_fixed_function_pipeline()); + if (enable) { glEnable(get_clip_plane_id(plane_id)); } else { @@ -10151,6 +10229,8 @@ enable_clip_plane(int plane_id, bool enable) { */ void CLP(GraphicsStateGuardian):: begin_bind_clip_planes() { + nassertv(has_fixed_function_pipeline()); + // We need to temporarily load a new matrix so we can define the clip_plane // in a known coordinate system. We pick the transform of the root. // (Alternatively, we could leave the current transform where it is and @@ -10175,6 +10255,8 @@ begin_bind_clip_planes() { */ void CLP(GraphicsStateGuardian):: bind_clip_plane(const NodePath &plane, int plane_id) { + nassertv(has_fixed_function_pipeline()); + GLenum id = get_clip_plane_id(plane_id); CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root().get_parent()); @@ -10205,6 +10287,8 @@ bind_clip_plane(const NodePath &plane, int plane_id) { */ void CLP(GraphicsStateGuardian):: end_bind_clip_planes() { + nassertv(has_fixed_function_pipeline()); + glMatrixMode(GL_MODELVIEW); glPopMatrix(); } @@ -10259,12 +10343,10 @@ set_state_and_transform(const RenderState *target, _state_shader = _target_shader; _state_mask.clear_bit(TextureAttrib::get_class_slot()); } -#ifndef SUPPORT_FIXED_FUNCTION - else if (_current_shader == NULL) { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything. + else if (!has_fixed_function_pipeline() && _current_shader == NULL) { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything. do_issue_shader(); _state_mask.clear_bit(TextureAttrib::get_class_slot()); } -#endif // Update all of the state that is bound to the shader program. if (_current_shader_context != NULL) { @@ -10273,17 +10355,19 @@ set_state_and_transform(const RenderState *target, #endif #ifdef SUPPORT_FIXED_FUNCTION - int alpha_test_slot = AlphaTestAttrib::get_class_slot(); - if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) || - !_state_mask.get_bit(alpha_test_slot) + if (has_fixed_function_pipeline()) { + int alpha_test_slot = AlphaTestAttrib::get_class_slot(); + if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) || + !_state_mask.get_bit(alpha_test_slot) #ifndef OPENGLES_1 - || (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test) != - _state_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) + || (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test) != + _state_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) #endif - ) { - // PStatGPUTimer timer(this, _draw_set_state_alpha_test_pcollector); - do_issue_alpha_test(); - _state_mask.set_bit(alpha_test_slot); + ) { + // PStatGPUTimer timer(this, _draw_set_state_alpha_test_pcollector); + do_issue_alpha_test(); + _state_mask.set_bit(alpha_test_slot); + } } #endif @@ -10357,22 +10441,22 @@ set_state_and_transform(const RenderState *target, } #ifdef SUPPORT_FIXED_FUNCTION - int rescale_normal_slot = RescaleNormalAttrib::get_class_slot(); - if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) || - !_state_mask.get_bit(rescale_normal_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_rescale_normal_pcollector); - do_issue_rescale_normal(); - _state_mask.set_bit(rescale_normal_slot); - } -#endif + if (has_fixed_function_pipeline()) { + int rescale_normal_slot = RescaleNormalAttrib::get_class_slot(); + if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) || + !_state_mask.get_bit(rescale_normal_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_rescale_normal_pcollector); + do_issue_rescale_normal(); + _state_mask.set_bit(rescale_normal_slot); + } -#ifdef SUPPORT_FIXED_FUNCTION - int shade_model_slot = ShadeModelAttrib::get_class_slot(); - if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) || - !_state_mask.get_bit(shade_model_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_shade_model_pcollector); - do_issue_shade_model(); - _state_mask.set_bit(shade_model_slot); + int shade_model_slot = ShadeModelAttrib::get_class_slot(); + if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) || + !_state_mask.get_bit(shade_model_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_shade_model_pcollector); + do_issue_shade_model(); + _state_mask.set_bit(shade_model_slot); + } } #endif @@ -10444,7 +10528,9 @@ set_state_and_transform(const RenderState *target, !_state_mask.get_bit(tex_matrix_slot)) { // PStatGPUTimer timer(this, _draw_set_state_tex_matrix_pcollector); #ifdef SUPPORT_FIXED_FUNCTION - do_issue_tex_matrix(); + if (has_fixed_function_pipeline()) { + do_issue_tex_matrix(); + } #endif _state_mask.set_bit(tex_matrix_slot); #ifndef OPENGLES_1 @@ -10455,35 +10541,41 @@ set_state_and_transform(const RenderState *target, } #ifdef SUPPORT_FIXED_FUNCTION - int tex_gen_slot = TexGenAttrib::get_class_slot(); - if (_target_tex_gen != _state_tex_gen || - !_state_mask.get_bit(tex_gen_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_tex_gen_pcollector); - do_issue_tex_gen(); - _state_tex_gen = _target_tex_gen; - _state_mask.set_bit(tex_gen_slot); - } -#endif + if (has_fixed_function_pipeline()) { + int tex_gen_slot = TexGenAttrib::get_class_slot(); + if (_target_tex_gen != _state_tex_gen || + !_state_mask.get_bit(tex_gen_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_tex_gen_pcollector); + do_issue_tex_gen(); + _state_tex_gen = _target_tex_gen; + _state_mask.set_bit(tex_gen_slot); + } - int material_slot = MaterialAttrib::get_class_slot(); - if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) || - !_state_mask.get_bit(material_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_material_pcollector); -#ifdef SUPPORT_FIXED_FUNCTION - do_issue_material(); -#endif - _state_mask.set_bit(material_slot); - } + int material_slot = MaterialAttrib::get_class_slot(); + if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) || + !_state_mask.get_bit(material_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_material_pcollector); + do_issue_material(); + _state_mask.set_bit(material_slot); + } - int light_slot = LightAttrib::get_class_slot(); - if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) || - !_state_mask.get_bit(light_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_light_pcollector); -#ifdef SUPPORT_FIXED_FUNCTION - do_issue_light(); -#endif - _state_mask.set_bit(light_slot); + int light_slot = LightAttrib::get_class_slot(); + if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) || + !_state_mask.get_bit(light_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_light_pcollector); + do_issue_light(); + _state_mask.set_bit(light_slot); + } + + int fog_slot = FogAttrib::get_class_slot(); + if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) || + !_state_mask.get_bit(fog_slot)) { + // PStatGPUTimer timer(this, _draw_set_state_fog_pcollector); + do_issue_fog(); + _state_mask.set_bit(fog_slot); + } } +#endif int stencil_slot = StencilAttrib::get_class_slot(); if (_target_rs->get_attrib(stencil_slot) != _state_rs->get_attrib(stencil_slot) || @@ -10493,16 +10585,6 @@ set_state_and_transform(const RenderState *target, _state_mask.set_bit(stencil_slot); } - int fog_slot = FogAttrib::get_class_slot(); - if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) || - !_state_mask.get_bit(fog_slot)) { - // PStatGPUTimer timer(this, _draw_set_state_fog_pcollector); -#ifdef SUPPORT_FIXED_FUNCTION - do_issue_fog(); -#endif - _state_mask.set_bit(fog_slot); - } - int scissor_slot = ScissorAttrib::get_class_slot(); if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) || !_state_mask.get_bit(scissor_slot)) { @@ -10546,12 +10628,16 @@ do_issue_texture() { _texture_binding_shader_context->disable_shader_texture_bindings(); } #ifdef SUPPORT_FIXED_FUNCTION - update_standard_texture_bindings(); + if (has_fixed_function_pipeline()) { + update_standard_texture_bindings(); + } #endif } else { if (_texture_binding_shader_context == 0) { #ifdef SUPPORT_FIXED_FUNCTION - disable_standard_texture_bindings(); + if (has_fixed_function_pipeline()) { + disable_standard_texture_bindings(); + } #endif _current_shader_context->update_shader_texture_bindings(NULL); } else { @@ -10881,20 +10967,22 @@ update_show_usage_texture_bindings(int show_stage_index) { } #ifdef SUPPORT_FIXED_FUNCTION - // Disable all texture stages. - for (i = 0; i < _num_active_texture_stages; i++) { - set_active_texture_stage(i); + if (has_fixed_function_pipeline()) { + // Disable all texture stages. + for (i = 0; i < _num_active_texture_stages; i++) { + set_active_texture_stage(i); #ifndef OPENGLES - glDisable(GL_TEXTURE_1D); + glDisable(GL_TEXTURE_1D); #endif // OPENGLES - glDisable(GL_TEXTURE_2D); - if (_supports_3d_texture) { + glDisable(GL_TEXTURE_2D); + if (_supports_3d_texture) { #ifndef OPENGLES_1 - glDisable(GL_TEXTURE_3D); + glDisable(GL_TEXTURE_3D); #endif // OPENGLES_1 - } - if (_supports_cube_map) { - glDisable(GL_TEXTURE_CUBE_MAP); + } + if (_supports_cube_map) { + glDisable(GL_TEXTURE_CUBE_MAP); + } } } #endif @@ -10917,7 +11005,9 @@ update_show_usage_texture_bindings(int show_stage_index) { // Choose the corresponding usage texture and apply it. set_active_texture_stage(i); #ifdef SUPPORT_FIXED_FUNCTION - glEnable(GL_TEXTURE_2D); + if (has_fixed_function_pipeline()) { + glEnable(GL_TEXTURE_2D); + } #endif UsageTextureKey key(texture->get_x_size(), texture->get_y_size()); @@ -11445,7 +11535,9 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) { tex->get_format() == Texture::F_depth_component24 || tex->get_format() == Texture::F_depth_component32) { #ifdef SUPPORT_FIXED_FUNCTION - glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); + if (has_fixed_function_pipeline()) { + glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY); + } #endif if (_supports_shadow_filter) { if ((sampler.get_magfilter() == SamplerState::FT_shadow) || @@ -11893,33 +11985,35 @@ upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) { } #endif -#if !defined(SUPPORT_FIXED_FUNCTION) && !defined(OPENGLES) - // Do we need to apply a swizzle mask to emulate these deprecated texture - // formats? - switch (tex->get_format()) { - case Texture::F_alpha: - glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_ZERO); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_ZERO); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ZERO); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED); - break; +#ifndef OPENGLES + if (!_supports_luminance_texture) { + // Do we need to apply a swizzle mask to emulate these deprecated texture + // formats? + switch (tex->get_format()) { + case Texture::F_alpha: + glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_ZERO); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_ZERO); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ZERO); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED); + break; - case Texture::F_luminance: - glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_ONE); - break; + case Texture::F_luminance: + glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_ONE); + break; - case Texture::F_luminance_alpha: - glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_GREEN); - break; + case Texture::F_luminance_alpha: + glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_GREEN); + break; - default: - break; + default: + break; + } } #endif @@ -12676,9 +12770,8 @@ get_texture_memory_size(CLP(TextureContext) *gtc) { } // OK, get the noncompressed size. - GLint red_size, green_size, blue_size, alpha_size, - luminance_size, intensity_size; - GLint depth_size = 0; + GLint red_size, green_size, blue_size, alpha_size; + GLint depth_size = 0, luminance_size = 0, intensity_size = 0; glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_RED_SIZE, &red_size); glGetTexLevelParameteriv(page_target, 0, @@ -12687,11 +12780,13 @@ get_texture_memory_size(CLP(TextureContext) *gtc) { GL_TEXTURE_BLUE_SIZE, &blue_size); glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_ALPHA_SIZE, &alpha_size); - glGetTexLevelParameteriv(page_target, 0, - GL_TEXTURE_LUMINANCE_SIZE, &luminance_size); - glGetTexLevelParameteriv(page_target, 0, - GL_TEXTURE_INTENSITY_SIZE, &intensity_size); - if (_supports_depth_texture) { + if (get_supports_luminance_texture()) { + glGetTexLevelParameteriv(page_target, 0, + GL_TEXTURE_LUMINANCE_SIZE, &luminance_size); + glGetTexLevelParameteriv(page_target, 0, + GL_TEXTURE_INTENSITY_SIZE, &intensity_size); + } + if (get_supports_depth_texture()) { glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_DEPTH_SIZE, &depth_size); } diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 85290cd6f2..bf95facb90 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -399,6 +399,7 @@ public: INLINE const string &get_gl_version() const; INLINE int get_gl_version_major() const; INLINE int get_gl_version_minor() const; + INLINE bool has_fixed_function_pipeline() const; virtual void set_state_and_transform(const RenderState *state, const TransformState *transform); @@ -719,6 +720,11 @@ protected: pset _extensions; +#ifndef OPENGLES + // True for non-compatibility GL 3.2+ contexts. + bool _core_profile; +#endif + public: bool _supports_point_parameters; PFNGLPOINTPARAMETERFVPROC _glPointParameterfv; From 4a8819b0bd7517cf8ad0fe1eed0666b324cadc14 Mon Sep 17 00:00:00 2001 From: rdb Date: Sun, 19 Feb 2017 22:16:49 +0100 Subject: [PATCH 08/19] MeshDrawer fixes and improvements: * Fix random number generator on Windows (LP 1663895) * Assert instead of crash when passing in non-Camera to begin() (LP 1663900) * Prevent repeated calls to generator()/set_budget() from leaking GeomNodes (LP 1663903) * Make the generator more efficient --- panda/src/grutil/meshDrawer.cxx | 59 ++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/panda/src/grutil/meshDrawer.cxx b/panda/src/grutil/meshDrawer.cxx index 02b63e938a..57ac0d9590 100644 --- a/panda/src/grutil/meshDrawer.cxx +++ b/panda/src/grutil/meshDrawer.cxx @@ -33,7 +33,7 @@ TypeHandle MeshDrawer::_type_handle; PN_stdfloat randFloat() { - return ((PN_stdfloat) rand() / (PN_stdfloat) 0x7fffffff); + return ((PN_stdfloat)rand() / (PN_stdfloat)RAND_MAX); } /** @@ -42,39 +42,43 @@ PN_stdfloat randFloat() { void MeshDrawer::generator(int budget) { // create enough triangles for budget: _vdata = new GeomVertexData(_root.get_name(), GeomVertexFormat::get_v3n3c4t2(), Geom::UH_static);//UH_dynamic); - GeomVertexWriter *tvertex = new GeomVertexWriter(_vdata, "vertex"); - GeomVertexWriter *tnormal = new GeomVertexWriter(_vdata, "normal"); - GeomVertexWriter *tuv = new GeomVertexWriter(_vdata, "texcoord"); - GeomVertexWriter *tcolor = new GeomVertexWriter(_vdata, "color"); - _prim = new GeomTriangles(Geom::UH_static); + _vdata->unclean_set_num_rows(budget * 3); - // 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); + { + GeomVertexWriter tvertex(_vdata, "vertex"); + GeomVertexWriter tnormal(_vdata, "normal"); + GeomVertexWriter tuv(_vdata, "texcoord"); + GeomVertexWriter tcolor(_vdata, "color"); + + // iterate and fill _up a geom with random data so that it will not be + // optimized out by panda3d system + for (int i = 0; i < budget; i++) { + for (int vert = 0; vert < 3; vert++) { + LVector3 vec3 = LVector3(randFloat()+1000,randFloat(),randFloat())*.001; + LVector4 vec4 = LVector4(1,1,1,randFloat()); + LVector2 vec2 = LVector2(0,randFloat()); + tvertex.set_data3(vec3); + tcolor.set_data4(vec4); + tuv.set_data2(vec2); + tnormal.set_data3(vec3); + } } - _prim->add_vertices(i * 3, i * 3 + 1, i * 3 + 2); } + // create our node and attach it to this node path + _prim = new GeomTriangles(Geom::UH_static); + _prim->add_next_vertices(budget * 3); _prim->close_primitive(); _geom = new Geom(_vdata); _geom->add_primitive(_prim); - _geomnode = new GeomNode("__MeshDrawer_GeomNode"); + if (_geomnode == NULL) { + _geomnode = new GeomNode("__MeshDrawer_GeomNode"); + _root.attach_new_node(_geomnode); + } else { + _geomnode->remove_all_geoms(); + } _geomnode->add_geom(_geom); - _root.attach_new_node(_geomnode); _last_clear_index = budget; - - delete tvertex; - delete tnormal; - delete tuv; - delete tcolor; } /** @@ -451,8 +455,9 @@ link_segment(const LVector3 &pos, const LVector4 &frame, LVector3 cam_stop3d = _camera.get_relative_point(_render, stop); LPoint2 cam_stop2d = LVector2(); - PT(Camera) camera = DCAST(Camera, _camera.node()); - PT(Lens) lens = camera->get_lens(); + const Camera *camera; + DCAST_INTO_V(camera, _camera.node()); + const Lens *lens = camera->get_lens(); lens->project(cam_start3d, cam_start2d); lens->project(cam_stop3d, cam_stop2d); From 53258af8768325bbc54ddca825e7191169dab8ef Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Feb 2017 00:23:21 +0100 Subject: [PATCH 09/19] display: reduce GraphicsEngine traversal overhead a bit --- panda/src/display/graphicsEngine.cxx | 168 +++++++++++---------------- panda/src/display/graphicsEngine.h | 9 +- 2 files changed, 75 insertions(+), 102 deletions(-) diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index ad3aa3caa6..045c534ebe 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -1328,21 +1328,24 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr, GraphicsStateGuardian *gsg = win->get_gsg(); nassertv(gsg != (GraphicsStateGuardian *)NULL); - DisplayRegionPipelineReader *dr_reader = - new DisplayRegionPipelineReader(dr, current_thread); + PT(SceneSetup) scene_setup; - win->change_scenes(dr_reader); - gsg->prepare_display_region(dr_reader); + { + DisplayRegionPipelineReader dr_reader(dr, current_thread); + win->change_scenes(&dr_reader); + gsg->prepare_display_region(&dr_reader); - if (dr_reader->is_any_clear_active()) { - gsg->clear(dr); + if (dr_reader.is_any_clear_active()) { + gsg->clear(dr); + } + + scene_setup = setup_scene(gsg, &dr_reader); } - PT(SceneSetup) scene_setup = setup_scene(gsg, dr_reader); if (scene_setup == (SceneSetup *)NULL) { // Never mind. - } else if (dr_reader->get_object()->is_stereo()) { + } else if (dr->is_stereo()) { // Don't draw stereo DisplayRegions directly. } else if (!gsg->set_scene(scene_setup)) { @@ -1353,9 +1356,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr, } else { DrawCullHandler cull_handler(gsg); if (gsg->begin_scene()) { - delete dr_reader; - dr_reader = NULL; - CallbackObject *cbobj = dr->get_cull_callback(); if (cbobj != (CallbackObject *)NULL) { // Issue the cull callback on this DisplayRegion. @@ -1372,10 +1372,6 @@ cull_and_draw_together(GraphicsOutput *win, DisplayRegion *dr, gsg->end_scene(); } } - - if (dr_reader != (DisplayRegionPipelineReader *)NULL) { - delete dr_reader; - } } /** @@ -1399,27 +1395,41 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { for (size_t wi = 0; wi < wlist_size; ++wi) { GraphicsOutput *win = wlist[wi]; if (win->is_active() && win->get_gsg()->is_active()) { + GraphicsStateGuardian *gsg = win->get_gsg(); PStatTimer timer(win->get_cull_window_pcollector(), current_thread); int num_display_regions = win->get_num_active_display_regions(); for (int i = 0; i < num_display_regions; ++i) { DisplayRegion *dr = win->get_active_display_region(i); - if (dr != (DisplayRegion *)NULL) { - DisplayRegionPipelineReader *dr_reader = - new DisplayRegionPipelineReader(dr, current_thread); - + if (dr != nullptr) { + PT(SceneSetup) scene_setup; + PT(CullResult) cull_result; CullKey key; - key._gsg = win->get_gsg(); - key._camera = dr_reader->get_camera(); - key._lens_index = dr_reader->get_lens_index(); + { + PStatTimer timer(_cull_setup_pcollector, current_thread); + DisplayRegionPipelineReader dr_reader(dr, current_thread); + scene_setup = setup_scene(gsg, &dr_reader); + if (scene_setup == nullptr) { + continue; + } - AlreadyCulled::iterator aci = already_culled.insert(AlreadyCulled::value_type(key, (DisplayRegion *)NULL)).first; - if ((*aci).second == NULL) { + 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(move(key), nullptr)).first; + if ((*aci).second == nullptr) { // We have not used this camera already in this thread. Perform // the cull operation. - delete dr_reader; - dr_reader = NULL; + cull_result = dr->get_cull_result(current_thread); + if (cull_result != nullptr) { + cull_result = cull_result->make_next(); + } else { + // This DisplayRegion has no cull results; draw it. + cull_result = new CullResult(gsg, dr->get_draw_region_pcollector()); + } (*aci).second = dr; - cull_to_bins(win, dr, current_thread); + cull_to_bins(win, gsg, dr, scene_setup, cull_result, current_thread); } else { // We have already culled a scene using this camera in this @@ -1429,14 +1439,11 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { // image.) Of course, the cull result will be the same, so just // use the result from the other DisplayRegion. DisplayRegion *other_dr = (*aci).second; - dr->set_cull_result(other_dr->get_cull_result(current_thread), - setup_scene(win->get_gsg(), dr_reader), - current_thread); + cull_result = other_dr->get_cull_result(current_thread); } - if (dr_reader != (DisplayRegionPipelineReader *)NULL) { - delete dr_reader; - } + // Save the results for next frame. + dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread); } } } @@ -1447,50 +1454,26 @@ cull_to_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { * Called only within the inner loop of cull_to_bins(), above. */ void GraphicsEngine:: -cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) { - GraphicsStateGuardian *gsg = win->get_gsg(); - if (gsg == (GraphicsStateGuardian *)NULL) { - return; +cull_to_bins(GraphicsOutput *win, GraphicsStateGuardian *gsg, + DisplayRegion *dr, SceneSetup *scene_setup, + CullResult *cull_result, Thread *current_thread) { + + 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. + + } else { + // Perform the cull normally. + dr->do_cull(&cull_handler, scene_setup, gsg, current_thread); } - 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(); - - } 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); - - // 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); - } - - // Save the results for next frame. - dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread); + PStatTimer timer(_cull_sort_pcollector, current_thread); + cull_result->finish_cull(scene_setup, current_thread); } /** @@ -1538,7 +1521,7 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { for (int i = 0; i < num_display_regions; ++i) { DisplayRegion *dr = win->get_active_display_region(i); if (dr != (DisplayRegion *)NULL) { - draw_bins(win, dr, current_thread); + do_draw(win, gsg, dr, current_thread); } } } @@ -1582,22 +1565,6 @@ draw_bins(const GraphicsEngine::Windows &wlist, Thread *current_thread) { } } -/** - * This variant on draw_bins() is only called from draw_bins(), above. It - * draws the cull result for a particular DisplayRegion. - */ -void GraphicsEngine:: -draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) { - GraphicsStateGuardian *gsg = win->get_gsg(); - if (gsg == (GraphicsStateGuardian *)NULL) { - return; - } - - PT(CullResult) cull_result = dr->get_cull_result(current_thread); - PT(SceneSetup) scene_setup = dr->get_scene_setup(current_thread); - do_draw(cull_result, scene_setup, win, dr, current_thread); -} - /** * Called in the draw thread, this calls make_context() on each window on the * list to guarantee its gsg and graphics context both get created. @@ -1899,15 +1866,20 @@ setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr) { * Draws the previously-culled scene. */ void GraphicsEngine:: -do_draw(CullResult *cull_result, SceneSetup *scene_setup, - GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) { - - CallbackObject *cbobj; - GraphicsStateGuardian *gsg = win->get_gsg(); - +do_draw(GraphicsOutput *win, GraphicsStateGuardian *gsg, DisplayRegion *dr, Thread *current_thread) { // Statistics PStatGPUTimer timer(gsg, dr->get_draw_region_pcollector(), current_thread); + PT(CullResult) cull_result; + PT(SceneSetup) scene_setup; + { + DisplayRegion::CDCullReader cdata(dr->_cycler_cull, current_thread); + cull_result = cdata->_cull_result; + scene_setup = cdata->_scene_setup; + } + + CallbackObject *cbobj; + { DisplayRegionPipelineReader dr_reader(dr, current_thread); win->change_scenes(&dr_reader); diff --git a/panda/src/display/graphicsEngine.h b/panda/src/display/graphicsEngine.h index 89cfb7c616..04f0993dfa 100644 --- a/panda/src/display/graphicsEngine.h +++ b/panda/src/display/graphicsEngine.h @@ -147,9 +147,10 @@ private: Thread *current_thread); void cull_to_bins(const Windows &wlist, Thread *current_thread); - void cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread); + void cull_to_bins(GraphicsOutput *win, GraphicsStateGuardian *gsg, + DisplayRegion *dr, SceneSetup *scene_setup, + CullResult *cull_result, Thread *current_thread); void draw_bins(const Windows &wlist, Thread *current_thread); - void draw_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread); void make_contexts(const Windows &wlist, Thread *current_thread); void process_events(const Windows &wlist, Thread *current_thread); @@ -162,8 +163,8 @@ private: PT(SceneSetup) setup_scene(GraphicsStateGuardian *gsg, DisplayRegionPipelineReader *dr); - void do_draw(CullResult *cull_result, SceneSetup *scene_setup, - GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread); + void do_draw(GraphicsOutput *win, GraphicsStateGuardian *gsg, + DisplayRegion *dr, Thread *current_thread); void do_add_window(GraphicsOutput *window, const GraphicsThreadingModel &threading_model); From b113d9db550ab7e475081c394c28f6b85285e212 Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Feb 2017 00:32:05 +0100 Subject: [PATCH 10/19] Fix incorrect type hierarchy of HermiteCurve, PandaNode, ShaderGenerator --- panda/src/parametrics/hermiteCurve.h | 4 +++- panda/src/pgraph/pandaNode.h | 6 ++---- panda/src/pgraphnodes/shaderGenerator.h | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/panda/src/parametrics/hermiteCurve.h b/panda/src/parametrics/hermiteCurve.h index 806ab47ff1..5a3d350b82 100644 --- a/panda/src/parametrics/hermiteCurve.h +++ b/panda/src/parametrics/hermiteCurve.h @@ -163,7 +163,9 @@ public: return _type_handle; } static void init_type() { - register_type(_type_handle, "HermiteCurve"); + PiecewiseCurve::init_type(); + register_type(_type_handle, "HermiteCurve", + PiecewiseCurve::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 0bbc984117..e9f3204ccd 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -799,12 +799,10 @@ public: return _type_handle; } static void init_type() { - TypedWritable::init_type(); - ReferenceCount::init_type(); + TypedWritableReferenceCount::init_type(); Namable::init_type(); register_type(_type_handle, "PandaNode", - TypedWritable::get_class_type(), - ReferenceCount::get_class_type(), + TypedWritableReferenceCount::get_class_type(), Namable::get_class_type()); CData::init_type(); Down::init_type(); diff --git a/panda/src/pgraphnodes/shaderGenerator.h b/panda/src/pgraphnodes/shaderGenerator.h index 9564bd6120..a1d83f0919 100644 --- a/panda/src/pgraphnodes/shaderGenerator.h +++ b/panda/src/pgraphnodes/shaderGenerator.h @@ -151,9 +151,9 @@ public: return _type_handle; } static void init_type() { - TypedObject::init_type(); + TypedReferenceCount::init_type(); register_type(_type_handle, "ShaderGenerator", - TypedObject::get_class_type()); + TypedReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); @@ -173,9 +173,9 @@ public: return _type_handle; } static void init_type() { - TypedObject::init_type(); + TypedReferenceCount::init_type(); register_type(_type_handle, "ShaderGenerator", - TypedObject::get_class_type()); + TypedReferenceCount::get_class_type()); } virtual TypeHandle get_type() const { return get_class_type(); From 6104e75eb0ef3602575f8c426f831718493bfecb Mon Sep 17 00:00:00 2001 From: rdb Date: Mon, 20 Feb 2017 15:09:11 +0100 Subject: [PATCH 11/19] bam2egg: generate a sphere from polygon with four vertices instead of two --- panda/src/egg2pg/eggSaver.cxx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/panda/src/egg2pg/eggSaver.cxx b/panda/src/egg2pg/eggSaver.cxx index 3976aa0714..133bddc874 100644 --- a/panda/src/egg2pg/eggSaver.cxx +++ b/panda/src/egg2pg/eggSaver.cxx @@ -482,7 +482,7 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path, } else if (child->is_of_type(CollisionSphere::get_class_type())) { CPT(CollisionSphere) sphere = DCAST(CollisionSphere, child); LPoint3 center = sphere->get_center(); - LVector3 offset(sphere->get_radius(), 0, 0); + PN_stdfloat radius = sphere->get_radius(); EggGroup *egg_sphere; if (num_solids == 1) { @@ -499,15 +499,19 @@ convert_collision_node(CollisionNode *node, const WorkingNodePath &node_path, } egg_sphere->set_collide_flags(flags); - EggVertex ev1, ev2; - ev1.set_pos(LCAST(double, (center + offset) * net_mat)); - ev2.set_pos(LCAST(double, (center - offset) * net_mat)); + EggVertex ev1, ev2, ev3, ev4; + ev1.set_pos(LCAST(double, (center + LVector3(radius, 0, 0)) * net_mat)); + ev2.set_pos(LCAST(double, (center + LVector3(0, radius, 0)) * net_mat)); + ev3.set_pos(LCAST(double, (center + LVector3(-radius, 0, 0)) * net_mat)); + ev4.set_pos(LCAST(double, (center + LVector3(0, -radius, 0)) * net_mat)); EggPolygon *egg_poly = new EggPolygon; egg_sphere->add_child(egg_poly); egg_poly->add_vertex(cvpool->create_unique_vertex(ev1)); egg_poly->add_vertex(cvpool->create_unique_vertex(ev2)); + egg_poly->add_vertex(cvpool->create_unique_vertex(ev3)); + egg_poly->add_vertex(cvpool->create_unique_vertex(ev4)); } else if (child->is_of_type(CollisionPlane::get_class_type())) { LPlane plane = DCAST(CollisionPlane, child)->get_plane(); From f6e2e2ea05c6e683c6dfab2401bd6583d07fd916 Mon Sep 17 00:00:00 2001 From: deflected Date: Mon, 20 Feb 2017 15:10:15 +0100 Subject: [PATCH 12/19] Fix compile issue on FreeBSD 11 --- dtool/src/dtoolutil/executionEnvironment.cxx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dtool/src/dtoolutil/executionEnvironment.cxx b/dtool/src/dtoolutil/executionEnvironment.cxx index bcf4584ab0..cf7ecac50e 100644 --- a/dtool/src/dtoolutil/executionEnvironment.cxx +++ b/dtool/src/dtoolutil/executionEnvironment.cxx @@ -591,8 +591,8 @@ read_args() { dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map); while (map != NULL) { - char *tail = strrchr(map->l_name, '/'); - char *head = strchr(map->l_name, '/'); + const char *tail = strrchr(map->l_name, '/'); + const char *head = strchr(map->l_name, '/'); if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0 || strcmp(tail, "/libp3dtool.so") == 0)) { _dtool_name = head; @@ -615,8 +615,8 @@ read_args() { char buffer[PATH_MAX]; buffer[0] = 0; maps.getline(buffer, PATH_MAX); - char *tail = strrchr(buffer, '/'); - char *head = strchr(buffer, '/'); + const char *tail = strrchr(buffer, '/'); + const char *head = strchr(buffer, '/'); if (tail && head && (strcmp(tail, "/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0 || strcmp(tail, "/libp3dtool.so") == 0)) { _dtool_name = head; From edb83fe89ac874bfa94127b01903518f9fedaa0b Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 21 Feb 2017 02:20:06 +0100 Subject: [PATCH 13/19] Various optimizations to reduce performance overhead of rendering --- dtool/src/dtoolbase/typeHandle.cxx | 4 +- dtool/src/dtoolbase/typeRegistry.I | 13 +++ dtool/src/dtoolbase/typeRegistry.cxx | 15 +-- dtool/src/dtoolbase/typeRegistry.h | 2 +- makepanda/makepanda.py | 2 +- panda/src/cull/cullBinBackToFront.cxx | 19 +++- panda/src/cull/cullBinFixed.cxx | 19 +++- panda/src/cull/cullBinFrontToBack.cxx | 19 +++- panda/src/cull/cullBinStateSorted.cxx | 19 +++- panda/src/cull/cullBinUnsorted.cxx | 19 +++- panda/src/glstuff/glGraphicsBuffer_src.cxx | 36 +++---- panda/src/gobj/geom.I | 62 ++++++++---- panda/src/gobj/geom.cxx | 68 +++++++------- panda/src/gobj/geom.h | 8 +- panda/src/gobj/geomCacheEntry.cxx | 4 +- panda/src/gobj/geomPrimitive.I | 96 ++++++++++++------- panda/src/gobj/geomPrimitive.cxx | 31 +++--- panda/src/gobj/geomPrimitive.h | 17 ++-- panda/src/gobj/geomVertexArrayData.I | 80 ++++++++++++---- panda/src/gobj/geomVertexArrayData.h | 19 ++-- panda/src/gobj/geomVertexData.I | 104 ++++++++++++--------- panda/src/gobj/geomVertexData.cxx | 57 ++++------- panda/src/gobj/geomVertexData.h | 17 ++-- panda/src/gobj/geomVertexWriter.cxx | 2 +- panda/src/gobj/geomVertexWriter.h | 2 +- panda/src/grutil/shaderTerrainMesh.cxx | 2 +- panda/src/pgraph/cullTraverserData.cxx | 2 +- panda/src/pgraph/cullableObject.I | 25 ++++- panda/src/pgraph/cullableObject.h | 12 ++- panda/src/pgraph/geomNode.cxx | 4 +- panda/src/pgraph/geomTransformer.cxx | 12 +-- panda/src/pgraph/workingNodePath.I | 8 +- panda/src/pipeline/thread.I | 11 ++- panda/src/putil/copyOnWritePointer.I | 24 +++-- panda/src/putil/copyOnWritePointer.cxx | 4 +- panda/src/putil/copyOnWritePointer.h | 8 +- panda/src/text/textAssembler.cxx | 8 +- 37 files changed, 537 insertions(+), 317 deletions(-) diff --git a/dtool/src/dtoolbase/typeHandle.cxx b/dtool/src/dtoolbase/typeHandle.cxx index 6f4d7bc1d1..4bbdbcbbb1 100644 --- a/dtool/src/dtoolbase/typeHandle.cxx +++ b/dtool/src/dtoolbase/typeHandle.cxx @@ -53,7 +53,7 @@ inc_memory_usage(MemoryClass memory_class, size_t size) { // cerr << *this << ".inc(" << memory_class << ", " << size << ") -> " << // rnode->_memory_usage[memory_class] << "\n"; if (rnode->_memory_usage[memory_class] < 0) { - cerr << "Memory usage overflow for type " << *this << ".\n"; + cerr << "Memory usage overflow for type " << rnode->_name << ".\n"; abort(); } } @@ -98,7 +98,7 @@ allocate_array(size_t size) { 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"; + cerr << "Memory usage overflow for type " << rnode->_name << ".\n"; abort(); } } diff --git a/dtool/src/dtoolbase/typeRegistry.I b/dtool/src/dtoolbase/typeRegistry.I index f0105c1eda..e35f37c207 100644 --- a/dtool/src/dtoolbase/typeRegistry.I +++ b/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. */ diff --git a/dtool/src/dtoolbase/typeRegistry.cxx b/dtool/src/dtoolbase/typeRegistry.cxx index 7349d20dd4..01b8ec498a 100644 --- a/dtool/src/dtoolbase/typeRegistry.cxx +++ b/dtool/src/dtoolbase/typeRegistry.cxx @@ -488,20 +488,6 @@ write(ostream &out) const { _lock->release(); } -/** - * Returns the pointer to the global TypeRegistry object. - */ -TypeRegistry *TypeRegistry:: -ptr() { - init_lock(); - _lock->acquire(); - if (_global_pointer == NULL) { - init_global_pointer(); - } - _lock->release(); - return _global_pointer; -} - /** * */ @@ -531,6 +517,7 @@ TypeRegistry() { */ void TypeRegistry:: init_global_pointer() { + init_lock(); init_memory_hook(); _global_pointer = new TypeRegistry; } diff --git a/dtool/src/dtoolbase/typeRegistry.h b/dtool/src/dtoolbase/typeRegistry.h index 828cee6c8c..651eb1904b 100644 --- a/dtool/src/dtoolbase/typeRegistry.h +++ b/dtool/src/dtoolbase/typeRegistry.h @@ -77,7 +77,7 @@ PUBLISHED: void write(ostream &out) const; // ptr() returns the pointer to the global TypeRegistry object. - static TypeRegistry *ptr(); + static INLINE TypeRegistry *ptr(); MAKE_SEQ_PROPERTY(typehandles, get_num_typehandles, get_typehandle); MAKE_SEQ_PROPERTY(root_classes, get_num_root_classes, get_root_class); diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index e159e864d8..adc2064f21 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1290,7 +1290,7 @@ def CompileCxx(obj,src,opts): cmd += " -fno-strict-aliasing" if optlevel >= 3: - cmd += " -ffast-math" + cmd += " -ffast-math -fno-stack-protector -fno-stack-check" if optlevel == 3: # Fast math is nice, but we'd like to see NaN in dev builds. cmd += " -fno-finite-math-only" diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index e472d0811d..57168aa866 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinBackToFront:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinFixed.cxx b/panda/src/cull/cullBinFixed.cxx index 3db9b9f7fb..6bbce5ed78 100644 --- a/panda/src/cull/cullBinFixed.cxx +++ b/panda/src/cull/cullBinFixed.cxx @@ -70,10 +70,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinFixed:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 1800b5636a..a532fef811 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -84,10 +84,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinFrontToBack:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinStateSorted.cxx b/panda/src/cull/cullBinStateSorted.cxx index c7ba58c295..07f3f9c9a3 100644 --- a/panda/src/cull/cullBinStateSorted.cxx +++ b/panda/src/cull/cullBinStateSorted.cxx @@ -69,10 +69,27 @@ finish_cull(SceneSetup *, Thread *current_thread) { void CullBinStateSorted:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::const_iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi)._object; - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/cull/cullBinUnsorted.cxx b/panda/src/cull/cullBinUnsorted.cxx index e9de061fb1..c9a68401b6 100644 --- a/panda/src/cull/cullBinUnsorted.cxx +++ b/panda/src/cull/cullBinUnsorted.cxx @@ -54,10 +54,27 @@ add_object(CullableObject *object, Thread *current_thread) { void CullBinUnsorted:: draw(bool force, Thread *current_thread) { PStatTimer timer(_draw_this_pcollector, current_thread); + + GeomPipelineReader geom_reader(current_thread); + GeomVertexDataPipelineReader data_reader(current_thread); + Objects::iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { CullableObject *object = (*oi); - CullHandler::draw(object, _gsg, force, current_thread); + + if (object->_draw_callback == nullptr) { + nassertd(object->_geom != nullptr) continue; + + _gsg->set_state_and_transform(object->_state, object->_internal_transform); + data_reader.set_object(object->_munged_data); + data_reader.check_array_readers(); + geom_reader.set_object(object->_geom); + geom_reader.draw(_gsg, object->_munger, &data_reader, force); + } else { + // It has a callback associated. + object->draw_callback(_gsg, force, current_thread); + // Now the callback has taken care of drawing. + } } } diff --git a/panda/src/glstuff/glGraphicsBuffer_src.cxx b/panda/src/glstuff/glGraphicsBuffer_src.cxx index 706bb03049..a4daaf3931 100644 --- a/panda/src/glstuff/glGraphicsBuffer_src.cxx +++ b/panda/src/glstuff/glGraphicsBuffer_src.cxx @@ -95,8 +95,7 @@ clear(Thread *current_thread) { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (glgsg->_glClearBufferfv == NULL) { // We can't efficiently clear the buffer. Fall back to the inefficient @@ -254,8 +253,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { // until we call glBlitFramebuffer. #ifndef OPENGLES_1 if (gl_enable_memory_barriers && _fbo_multisample == 0) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_R(glgsg, _gsg, false); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); TextureContexts::iterator it; for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) { @@ -285,8 +283,7 @@ begin_frame(FrameMode mode, Thread *current_thread) { */ bool CLP(GraphicsBuffer):: check_fbo() { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_R(glgsg, _gsg, false); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); GLenum status = glgsg->_glCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); if (status != GL_FRAMEBUFFER_COMPLETE_EXT) { @@ -341,8 +338,7 @@ rebuild_bitplanes() { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (!_needs_rebuild) { if (_fbo_multisample != 0) { @@ -685,8 +681,7 @@ rebuild_bitplanes() { */ void CLP(GraphicsBuffer):: bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); Texture *tex = attach[slot]; @@ -1020,8 +1015,7 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot, */ void CLP(GraphicsBuffer):: bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if ((_rbm[slot] != 0)&&(!rb_resize)) { return; @@ -1144,8 +1138,7 @@ bind_slot_multisample(bool rb_resize, Texture **attach, RenderTexturePlane slot, */ void CLP(GraphicsBuffer):: attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); if (view >= attach->get_num_views()) { attach->set_num_views(view + 1); @@ -1215,8 +1208,7 @@ generate_mipmaps() { return; } - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); // PStatGPUTimer timer(glgsg, _generate_mipmap_pcollector); @@ -1253,8 +1245,7 @@ end_frame(FrameMode mode, Thread *current_thread) { // Unbind the FBO. TODO: calling bind_fbo is slow, so we should probably // move this to begin_frame to prevent unnecessary calls. - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); glgsg->bind_fbo(0); _bound_tex_page = -1; @@ -1293,8 +1284,7 @@ void CLP(GraphicsBuffer):: select_target_tex_page(int page) { nassertv(page >= 0 && page < _fbo.size()); - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); bool switched_page = (_bound_tex_page != page); @@ -1689,8 +1679,7 @@ report_my_errors(int line, const char *file) { GLCAT.error() << file << ", line " << line << ": GL error " << (int)error_code << "\n"; } } else { - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); glgsg->report_my_errors(line, file); } } @@ -1723,8 +1712,7 @@ void CLP(GraphicsBuffer):: resolve_multisamples() { nassertv(_fbo.size() > 0); - CLP(GraphicsStateGuardian) *glgsg; - DCAST_INTO_V(glgsg, _gsg); + CLP(GraphicsStateGuardian) *glgsg = (CLP(GraphicsStateGuardian) *)_gsg.p(); PStatGPUTimer timer(glgsg, _resolve_multisample_pcollector); diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index 33132b3be5..3457a8b265 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -51,7 +51,7 @@ get_geom_rendering() const { INLINE CPT(GeomVertexData) Geom:: get_vertex_data(Thread *current_thread) const { CDReader cdata(_cycler, current_thread); - return cdata->_data.get_read_pointer(); + return cdata->_data.get_read_pointer(current_thread); } /** @@ -514,6 +514,18 @@ CData(const Geom::CData ©) : { } + +/** + * + */ +INLINE GeomPipelineReader:: +GeomPipelineReader(Thread *current_thread) : + _object(nullptr), + _current_thread(current_thread), + _cdata(nullptr) +{ +} + /** * */ @@ -531,34 +543,22 @@ GeomPipelineReader(const Geom *object, Thread *current_thread) : #endif // DO_PIPELINING } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomPipelineReader:: -GeomPipelineReader(const GeomPipelineReader &) { - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomPipelineReader:: -operator = (const GeomPipelineReader &) { - nassertv(false); -} - /** * */ INLINE GeomPipelineReader:: ~GeomPipelineReader() { #ifdef _DEBUG - nassertv(_object->test_ref_count_nonzero()); + if (_object != nullptr) { + nassertv(_object->test_ref_count_nonzero()); + } #endif // _DEBUG // _object->_cycler.release_read(_cdata); #ifdef DO_PIPELINING - unref_delete((CycleData *)_cdata); + if (_cdata != nullptr) { + unref_delete((CycleData *)_cdata); + } #endif // DO_PIPELINING #ifdef _DEBUG @@ -567,6 +567,30 @@ INLINE GeomPipelineReader:: #endif // _DEBUG } +/** + * + */ +INLINE void GeomPipelineReader:: +set_object(const Geom *object) { + if (object != _object) { + // _object->_cycler.release_read(_cdata); + +#ifdef DO_PIPELINING + if (_cdata != NULL) { + unref_delete((CycleData *)_cdata); + } +#endif // DO_PIPELINING + + _cdata = object->_cycler.read_unlocked(_current_thread); + +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + + _object = object; + } +} + /** * */ diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index 1d3e0a2a45..eb44a46abb 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -236,7 +236,7 @@ make_nonindexed(bool composite_only) { int num_changed = 0; CDWriter cdata(_cycler, true, current_thread); - CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(); + CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(current_thread); PT(GeomVertexData) new_data = new GeomVertexData(*orig_data); new_data->clear_rows(); @@ -247,7 +247,7 @@ make_nonindexed(bool composite_only) { Primitives new_prims; new_prims.reserve(cdata->_primitives.size()); for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy(); + PT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread)->make_copy(); new_prims.push_back(primitive.p()); // GeomPoints are considered "composite" for the purposes of making @@ -298,7 +298,7 @@ set_primitive(int i, const GeomPrimitive *primitive) { Thread *current_thread = Thread::get_current_thread(); CDWriter cdata(_cycler, true, current_thread); nassertv(i >= 0 && i < (int)cdata->_primitives.size()); - nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); + nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread))); // All primitives within a particular Geom must have the same fundamental // primitive type (triangles, points, or lines). @@ -339,7 +339,7 @@ add_primitive(const GeomPrimitive *primitive) { Thread *current_thread = Thread::get_current_thread(); CDWriter cdata(_cycler, true, current_thread); - nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); + nassertv(primitive->check_valid(cdata->_data.get_read_pointer(current_thread))); // All primitives within a particular Geom must have the same fundamental // primitive type (triangles, points, or lines). @@ -426,11 +426,11 @@ decompose_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->decompose(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -460,11 +460,11 @@ doubleside_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->doubleside(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -494,11 +494,11 @@ reverse_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->reverse(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -528,11 +528,11 @@ rotate_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->rotate(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -596,7 +596,7 @@ unify_in_place(int max_indices, bool preserve_order) { Primitives::const_iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); + CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(current_thread); NewPrims::iterator npi = new_prims.find(primitive->get_type()); if (npi == new_prims.end()) { // This is the first primitive of this type. @@ -648,7 +648,7 @@ unify_in_place(int max_indices, bool preserve_order) { for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) { GeomPrimitive *prim = (*npi).second; - nassertv(prim->check_valid(cdata->_data.get_read_pointer())); + nassertv(prim->check_valid(cdata->_data.get_read_pointer(current_thread))); // Each new primitive, naturally, inherits the Geom's overall shade model. prim->set_shade_model(cdata->_shade_model); @@ -706,11 +706,11 @@ make_lines_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_lines(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_lines(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -740,11 +740,11 @@ make_points_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_points(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -774,11 +774,11 @@ make_patches_in_place() { #endif Primitives::iterator pi; for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_patches(); + CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer(current_thread)->make_patches(); (*pi) = (GeomPrimitive *)new_prim.p(); #ifndef NDEBUG - if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { + if (!new_prim->check_valid(cdata->_data.get_read_pointer(current_thread))) { all_is_valid = false; } #endif @@ -865,7 +865,9 @@ get_num_bytes() const { */ bool Geom:: request_resident() const { - CDReader cdata(_cycler); + Thread *current_thread = Thread::get_current_thread(); + + CDReader cdata(_cycler, current_thread); bool resident = true; @@ -873,7 +875,7 @@ request_resident() const { for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - if (!(*pi).get_read_pointer()->request_resident()) { + if (!(*pi).get_read_pointer(current_thread)->request_resident()) { resident = false; } } @@ -1197,7 +1199,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { int num_vertices = 0; // Get the vertex data, after animation. - CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(); + CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(current_thread); vertex_data = vertex_data->animate_vertices(true, current_thread); // Now actually compute the bounding volume. We do this by using @@ -1296,7 +1298,7 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); num_vertices += prim->get_num_vertices(); } @@ -1327,7 +1329,7 @@ do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); prim->calc_tight_bounds(min_point, max_point, sq_center_dist, found_any, vertex_data, got_mat, mat, column_name, current_thread); @@ -1345,7 +1347,7 @@ do_calc_sphere_radius(const LPoint3 ¢er, PN_stdfloat &sq_radius, for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); + CPT(GeomPrimitive) prim = (*pi).get_read_pointer(current_thread); prim->calc_sphere_radius(center, sq_radius, found_any, vertex_data, current_thread); } @@ -1469,8 +1471,10 @@ combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim, a_prim->append_unused_vertices(a_vertices, b_vertex); } - PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread); - CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread); + PT(GeomVertexArrayDataHandle) a_handle = + new GeomVertexArrayDataHandle(move(a_vertices), current_thread); + CPT(GeomVertexArrayDataHandle) b_handle = + new GeomVertexArrayDataHandle(move(b_vertices), current_thread); size_t orig_a_vertices = a_handle->get_num_rows(); @@ -1683,8 +1687,7 @@ check_valid(const GeomVertexDataPipelineReader *data_reader) const { for (pi = _cdata->_primitives.begin(); pi != _cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); - GeomPrimitivePipelineReader reader(primitive, _current_thread); + GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread); reader.check_minmax(); if (!reader.check_valid(data_reader)) { return false; @@ -1707,12 +1710,11 @@ draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, for (pi = _cdata->_primitives.begin(); pi != _cdata->_primitives.end(); ++pi) { - CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); - GeomPrimitivePipelineReader reader(primitive, _current_thread); + GeomPrimitivePipelineReader reader((*pi).get_read_pointer(_current_thread), _current_thread); if (reader.get_num_vertices() != 0) { reader.check_minmax(); nassertr(reader.check_valid(data_reader), false); - if (!primitive->draw(gsg, &reader, force)) { + if (!reader.draw(gsg, force)) { all_ok = false; } } diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index cd02493d79..0ed8cc5193 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -401,15 +401,17 @@ private: */ class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums { public: + INLINE GeomPipelineReader(Thread *current_thread); INLINE GeomPipelineReader(const Geom *object, Thread *current_thread); private: - INLINE GeomPipelineReader(const GeomPipelineReader ©); - INLINE void operator = (const GeomPipelineReader ©); + GeomPipelineReader(const GeomPipelineReader ©) DELETED; + GeomPipelineReader &operator = (const GeomPipelineReader ©) DELETED_ASSIGN; public: INLINE ~GeomPipelineReader(); ALLOC_DELETED_CHAIN(GeomPipelineReader); + INLINE void set_object(const Geom *object); INLINE const Geom *get_object() const; INLINE Thread *get_current_thread() const; @@ -433,7 +435,7 @@ public: private: const Geom *_object; - Thread *_current_thread; + Thread *const _current_thread; const Geom::CData *_cdata; public: diff --git a/panda/src/gobj/geomCacheEntry.cxx b/panda/src/gobj/geomCacheEntry.cxx index 27ab5a9e20..d16a7f6a08 100644 --- a/panda/src/gobj/geomCacheEntry.cxx +++ b/panda/src/gobj/geomCacheEntry.cxx @@ -95,8 +95,8 @@ PT(GeomCacheEntry) GeomCacheEntry:: erase() { nassertr(_next != (GeomCacheEntry *)NULL && _prev != (GeomCacheEntry *)NULL, NULL); - PT(GeomCacheEntry) keepme = this; - unref(); + PT(GeomCacheEntry) keepme; + keepme.cheat() = this; if (gobj_cat.is_debug()) { gobj_cat.debug() diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 029063f864..1dceada335 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -235,6 +235,24 @@ get_vertices() const { return cdata->_vertices.get_read_pointer(); } +/** + * Equivalent to get_vertices().get_handle(). + */ +INLINE CPT(GeomVertexArrayDataHandle) GeomPrimitive:: +get_vertices_handle(Thread *current_thread) const { + CDReader cdata(_cycler, current_thread); + return new GeomVertexArrayDataHandle(cdata->_vertices.get_read_pointer(current_thread), current_thread); +} + +/** + * Equivalent to modify_vertices().get_handle(). + */ +INLINE PT(GeomVertexArrayDataHandle) GeomPrimitive:: +modify_vertices_handle(Thread *current_thread) { + CDWriter cdata(_cycler, true, current_thread); + return new GeomVertexArrayDataHandle(do_modify_vertices(cdata), current_thread); +} + /** * A convenience function to return the gap between successive index numbers, * in bytes, of the index data. @@ -414,38 +432,32 @@ CData(const GeomPrimitive::CData ©) : * */ INLINE GeomPrimitivePipelineReader:: -GeomPrimitivePipelineReader(const GeomPrimitive *object, +GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread) : - _object(object), + _object(move(object)), _current_thread(current_thread), - _cdata(object->_cycler.read_unlocked(current_thread)), - _vertices_reader(NULL) +#ifndef CPPPARSER + _cdata(_object->_cycler.read_unlocked(current_thread)), +#endif + _vertices_cdata(NULL) { nassertv(_object->test_ref_count_nonzero()); #ifdef DO_PIPELINING _cdata->ref(); #endif // DO_PIPELINING + if (!_cdata->_vertices.is_null()) { - _vertices_reader = _cdata->_vertices.get_read_pointer()->get_handle(); + _vertices = _cdata->_vertices.get_read_pointer(current_thread); + _vertices_cdata = _vertices->_cycler.read_unlocked(current_thread); +#ifdef DO_PIPELINING + _vertices_cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _vertices_cdata->_rw_lock.acquire(); } } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomPrimitivePipelineReader:: -GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader &) { - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomPrimitivePipelineReader:: -operator = (const GeomPrimitivePipelineReader &) { - nassertv(false); -} - /** * */ @@ -460,8 +472,17 @@ INLINE GeomPrimitivePipelineReader:: unref_delete((CycleData *)_cdata); #endif // DO_PIPELINING + if (_vertices_cdata != nullptr) { + // We must release the lock *before* we decrement the reference count, + // below. + _vertices_cdata->_rw_lock.release(); + +#ifdef DO_PIPELINING + unref_delete((CycleData *)_vertices_cdata); +#endif // DO_PIPELINING + } + #ifdef _DEBUG - _vertices_reader = NULL; _object = NULL; _cdata = NULL; #endif // _DEBUG @@ -512,7 +533,7 @@ get_index_type() const { */ INLINE bool GeomPrimitivePipelineReader:: is_indexed() const { - return (!_cdata->_vertices.is_null()); + return (!_vertices.is_null()); } /** @@ -523,8 +544,10 @@ get_num_vertices() const { if (_cdata->_num_vertices != -1) { return _cdata->_num_vertices; } else { - nassertr(!_cdata->_vertices.is_null(), 0); - return _vertices_reader->get_num_rows(); + nassertr(!_vertices.is_null(), 0); + size_t stride = _vertices->_array_format->get_stride(); + nassertr(stride != 0, 0); + return get_data_size_bytes() / stride; } } @@ -551,7 +574,7 @@ get_max_vertex() const { */ INLINE int GeomPrimitivePipelineReader:: get_data_size_bytes() const { - return _vertices_reader->get_data_size_bytes(); + return _vertices_cdata->_buffer.get_size(); } /** @@ -568,15 +591,7 @@ get_modified() const { INLINE int GeomPrimitivePipelineReader:: get_index_stride() const { nassertr(is_indexed(), 0); - return _cdata->_vertices.get_read_pointer()->get_array_format()->get_stride(); -} - -/** - * - */ -INLINE const GeomVertexArrayDataHandle *GeomPrimitivePipelineReader:: -get_vertices_reader() const { - return _vertices_reader; + return _vertices->_array_format->get_stride(); } /** @@ -584,7 +599,8 @@ get_vertices_reader() const { */ INLINE const unsigned char *GeomPrimitivePipelineReader:: get_read_pointer(bool force) const { - return _vertices_reader->get_read_pointer(force); + ((GeomVertexArrayData *)_vertices.p())->mark_used(); + return _vertices_cdata->_buffer.get_read_pointer(force); } /** @@ -632,6 +648,14 @@ prepare_now(PreparedGraphicsObjects *prepared_objects, return ((GeomPrimitive *)_object.p())->prepare_now(prepared_objects, gsg); } +/** + * Calls the appropriate method on the GSG to draw the primitive. + */ +INLINE bool GeomPrimitivePipelineReader:: +draw(GraphicsStateGuardianBase *gsg, bool force) const { + return _object->draw(gsg, this, force); +} + INLINE ostream & operator << (ostream &out, const GeomPrimitive &obj) { obj.output(out); diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index 6f918eefdb..b96249cc83 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -1036,23 +1036,23 @@ get_num_bytes() const { * shortly; try again later. */ bool GeomPrimitive:: -request_resident() const { - CDReader cdata(_cycler); +request_resident(Thread *current_thread) const { + CDReader cdata(_cycler, current_thread); bool resident = true; if (!cdata->_vertices.is_null() && - !cdata->_vertices.get_read_pointer()->request_resident()) { + !cdata->_vertices.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } if (is_composite() && cdata->_got_minmax) { if (!cdata->_mins.is_null() && - !cdata->_mins.get_read_pointer()->request_resident()) { + !cdata->_mins.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } if (!cdata->_maxs.is_null() && - !cdata->_maxs.get_read_pointer()->request_resident()) { + !cdata->_maxs.get_read_pointer(current_thread)->request_resident(current_thread)) { resident = false; } } @@ -2178,14 +2178,17 @@ check_minmax() const { */ int GeomPrimitivePipelineReader:: get_first_vertex() const { - if (_cdata->_vertices.is_null()) { + if (_vertices.is_null()) { return _cdata->_first_vertex; - } else if (_vertices_reader->get_num_rows() == 0) { - return 0; - } else { - GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0); - return index.get_data1i(); } + + size_t size = _vertices_cdata->_buffer.get_size(); + if (size == 0) { + return 0; + } + + GeomVertexReader index(_vertices, 0); + return index.get_data1i(); } /** @@ -2193,11 +2196,11 @@ get_first_vertex() const { */ int GeomPrimitivePipelineReader:: get_vertex(int i) const { - if (!_cdata->_vertices.is_null()) { + if (!_vertices.is_null()) { // The indexed case. - nassertr(i >= 0 && i < _vertices_reader->get_num_rows(), -1); + nassertr(i >= 0 && i < get_num_vertices(), -1); - GeomVertexReader index(_cdata->_vertices.get_read_pointer(), 0); + GeomVertexReader index(_vertices, 0); index.set_row_unsafe(i); return index.get_data1i(); diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 9c24af0c45..41c575acd4 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -142,7 +142,7 @@ PUBLISHED: MAKE_PROPERTY(data_size_bytes, get_data_size_bytes); MAKE_PROPERTY(modified, get_modified); - bool request_resident() const; + bool request_resident(Thread *current_thread = Thread::get_current_thread()) const; INLINE bool check_valid(const GeomVertexData *vertex_data) const; @@ -162,7 +162,9 @@ PUBLISHED: */ INLINE CPT(GeomVertexArrayData) get_vertices() const; + INLINE CPT(GeomVertexArrayDataHandle) get_vertices_handle(Thread *current_thread) const; PT(GeomVertexArrayData) modify_vertices(int num_vertices = -1); + INLINE PT(GeomVertexArrayDataHandle) modify_vertices_handle(Thread *current_thread); void set_vertices(const GeomVertexArrayData *vertices, int num_vertices = -1); void set_nonindexed_vertices(int first_vertex, int num_vertices); @@ -347,10 +349,10 @@ private: */ class EXPCL_PANDA_GOBJ GeomPrimitivePipelineReader : public GeomEnums { public: - INLINE GeomPrimitivePipelineReader(const GeomPrimitive *object, Thread *current_thread); + INLINE GeomPrimitivePipelineReader(CPT(GeomPrimitive) object, Thread *current_thread); private: - INLINE GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader ©); - INLINE void operator = (const GeomPrimitivePipelineReader ©); + GeomPrimitivePipelineReader(const GeomPrimitivePipelineReader ©) DELETED; + GeomPrimitivePipelineReader &operator = (const GeomPrimitivePipelineReader ©) DELETED_ASSIGN; public: INLINE ~GeomPrimitivePipelineReader(); @@ -375,7 +377,6 @@ public: INLINE UpdateSeq get_modified() const; bool check_valid(const GeomVertexDataPipelineReader *data_reader) const; INLINE int get_index_stride() const; - INLINE const GeomVertexArrayDataHandle *get_vertices_reader() const; INLINE const unsigned char *get_read_pointer(bool force) const; INLINE int get_strip_cut_index() const; INLINE CPTA_int get_ends() const; @@ -384,13 +385,15 @@ public: INLINE IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg) const; + INLINE bool draw(GraphicsStateGuardianBase *gsg, bool force) const; private: CPT(GeomPrimitive) _object; - Thread *_current_thread; + Thread *const _current_thread; const GeomPrimitive::CData *_cdata; - CPT(GeomVertexArrayDataHandle) _vertices_reader; + CPT(GeomVertexArrayData) _vertices; + const GeomVertexArrayData::CData *_vertices_cdata; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index 3ee8d9311f..0c2b9904ea 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -130,9 +130,20 @@ get_modified() const { * back into memory shortly; try again later. */ INLINE bool GeomVertexArrayData:: -request_resident() const { - CPT(GeomVertexArrayDataHandle) handle = get_handle(); - return handle->request_resident(); +request_resident(Thread *current_thread) const { +#ifdef DO_PIPELINING + CPT(GeomVertexArrayData::CData) cdata = _cycler.read_unlocked(current_thread); +#else + const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread); +#endif + + cdata->_rw_lock.acquire(); + + ((GeomVertexArrayData *)this)->mark_used(); + bool is_resident = (cdata->_buffer.get_read_pointer(false) != nullptr); + + cdata->_rw_lock.release(); + return is_resident; } /** @@ -143,9 +154,7 @@ request_resident() const { */ INLINE CPT(GeomVertexArrayDataHandle) GeomVertexArrayData:: get_handle(Thread *current_thread) const { - const CData *cdata = _cycler.read_unlocked(current_thread); - return new GeomVertexArrayDataHandle(this, current_thread, - cdata, false); + return new GeomVertexArrayDataHandle(this, current_thread); } /** @@ -156,9 +165,7 @@ get_handle(Thread *current_thread) const { */ INLINE PT(GeomVertexArrayDataHandle) GeomVertexArrayData:: modify_handle(Thread *current_thread) { - CData *cdata = _cycler.write_upstream(true, current_thread); - return new GeomVertexArrayDataHandle(this, current_thread, - cdata, true); + return new GeomVertexArrayDataHandle(PT(GeomVertexArrayData)(this), current_thread); } /** @@ -202,6 +209,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 +256,40 @@ operator = (const GeomVertexArrayData::CData ©) { * */ 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 *)cdata), - _writable(writable) + _cdata((GeomVertexArrayData::CData *)object->_cycler.read_unlocked(current_thread)), + _writable(false) { + _object.swap(object); + +#ifdef _DEBUG + nassertv(_object->test_ref_count_nonzero()); +#endif // _DEBUG +#ifdef DO_PIPELINING + _cdata->ref(); +#endif // DO_PIPELINING + // We must grab the lock *after* we have incremented the reference count, + // above. + _cdata->_rw_lock.acquire(); +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, get_class_type()); +#endif +} + +/** + * + */ +INLINE GeomVertexArrayDataHandle:: +GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object, + Thread *current_thread) : + _current_thread(current_thread), + _cdata(object->_cycler.write_upstream(true, current_thread)), + _writable(true) +{ + _object.swap(object); + #ifdef _DEBUG nassertv(_object->test_ref_count_nonzero()); #endif // _DEBUG @@ -265,7 +308,8 @@ GeomVertexArrayDataHandle(const GeomVertexArrayData *object, * Don't attempt to copy these objects. */ INLINE GeomVertexArrayDataHandle:: -GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) { +GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle ©) + : _current_thread(copy._current_thread) { nassertv(false); } @@ -448,7 +492,7 @@ get_subdata(size_t start, size_t size) const { */ void GeomVertexArrayDataHandle:: mark_used() const { - _object->set_lru_size(_object->get_lru_size()); + _object->mark_used(); } INLINE ostream & diff --git a/panda/src/gobj/geomVertexArrayData.h b/panda/src/gobj/geomVertexArrayData.h index 9766a9cbd1..2104e74b52 100644 --- a/panda/src/gobj/geomVertexArrayData.h +++ b/panda/src/gobj/geomVertexArrayData.h @@ -95,7 +95,7 @@ PUBLISHED: void output(ostream &out) const; void write(ostream &out, int indent_level = 0) const; - INLINE bool request_resident() const; + INLINE bool request_resident(Thread *current_thread = Thread::get_current_thread()) const; INLINE CPT(GeomVertexArrayDataHandle) get_handle(Thread *current_thread = Thread::get_current_thread()) const; INLINE PT(GeomVertexArrayDataHandle) modify_handle(Thread *current_thread = Thread::get_current_thread()); @@ -124,6 +124,7 @@ public: private: INLINE void set_lru_size(size_t lru_size); + INLINE void mark_used(); void clear_prepared(PreparedGraphicsObjects *prepared_objects); void reverse_data_endianness(unsigned char *dest, @@ -230,6 +231,7 @@ private: friend class GeomVertexData; friend class PreparedGraphicsObjects; friend class GeomVertexArrayDataHandle; + friend class GeomPrimitivePipelineReader; }; /** @@ -246,10 +248,10 @@ private: */ class EXPCL_PANDA_GOBJ GeomVertexArrayDataHandle : public ReferenceCount, public GeomEnums { private: - INLINE GeomVertexArrayDataHandle(const GeomVertexArrayData *object, - Thread *current_thread, - const GeomVertexArrayData::CData *_cdata, - bool writable); + INLINE GeomVertexArrayDataHandle(CPT(GeomVertexArrayData) object, + Thread *current_thread); + INLINE GeomVertexArrayDataHandle(PT(GeomVertexArrayData) object, + Thread *current_thread); INLINE GeomVertexArrayDataHandle(const GeomVertexArrayDataHandle &); INLINE void operator = (const GeomVertexArrayDataHandle &); @@ -316,7 +318,7 @@ PUBLISHED: private: PT(GeomVertexArrayData) _object; - Thread *_current_thread; + Thread *const _current_thread; GeomVertexArrayData::CData *_cdata; bool _writable; @@ -333,6 +335,11 @@ public: private: static TypeHandle _type_handle; + friend class Geom; + friend class GeomPrimitive; + friend class GeomVertexData; + friend class GeomVertexDataPipelineReader; + friend class GeomVertexDataPipelineWriter; friend class GeomVertexArrayData; }; diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index dfb2138c1a..888db97c88 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -147,6 +147,17 @@ get_array(int i) const { return cdata->_arrays[i].get_read_pointer(); } +/** + * Equivalent to get_array(i).get_handle(). + */ +INLINE CPT(GeomVertexArrayDataHandle) GeomVertexData:: +get_array_handle(int i) const { + Thread *current_thread = Thread::get_current_thread(); + CDReader cdata(_cycler, current_thread); + nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL); + return new GeomVertexArrayDataHandle(cdata->_arrays[i].get_read_pointer(), current_thread); +} + /** * Returns a modifiable pointer to the indicated vertex array, so that * application code may directly manipulate the data. You should avoid @@ -162,6 +173,16 @@ modify_array(int i) { return writer.modify_array(i); } +/** + * Equivalent to modify_array(i).modify_handle(). + */ +INLINE PT(GeomVertexArrayDataHandle) GeomVertexData:: +modify_array_handle(int i) { + Thread *current_thread = Thread::get_current_thread(); + GeomVertexDataPipelineWriter writer(this, true, current_thread); + return new GeomVertexArrayDataHandle(writer.modify_array(i), current_thread); +} + /** * Replaces the indicated vertex data array with a completely new array. You * should be careful that the new array has the same length and format as the @@ -575,6 +596,17 @@ CData(const GeomVertexData::CData ©) : { } +/** + * + */ +INLINE GeomVertexDataPipelineBase:: +GeomVertexDataPipelineBase(Thread *current_thread) : + _object(nullptr), + _current_thread(current_thread), + _cdata(nullptr) +{ +} + /** * */ @@ -600,11 +632,15 @@ GeomVertexDataPipelineBase(GeomVertexData *object, INLINE GeomVertexDataPipelineBase:: ~GeomVertexDataPipelineBase() { #ifdef _DEBUG - nassertv(_object->test_ref_count_nonzero()); + if (_object != nullptr) { + nassertv(_object->test_ref_count_nonzero()); + } #endif // _DEBUG #ifdef DO_PIPELINING - unref_delete((CycleData *)_cdata); + if (_cdata != nullptr) { + unref_delete((CycleData *)_cdata); + } #endif // DO_PIPELINING #ifdef _DEBUG @@ -694,6 +730,16 @@ get_modified() const { return _cdata->_modified; } +/** + * + */ +INLINE GeomVertexDataPipelineReader:: +GeomVertexDataPipelineReader(Thread *current_thread) : + GeomVertexDataPipelineBase(current_thread), + _got_array_readers(false) +{ +} + /** * */ @@ -706,33 +752,23 @@ GeomVertexDataPipelineReader(const GeomVertexData *object, { } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomVertexDataPipelineReader:: -GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©) : - GeomVertexDataPipelineBase(copy) -{ - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomVertexDataPipelineReader:: -operator = (const GeomVertexDataPipelineReader &) { - nassertv(false); -} - /** * */ -INLINE GeomVertexDataPipelineReader:: -~GeomVertexDataPipelineReader() { - if (_got_array_readers) { - delete_array_readers(); +INLINE void GeomVertexDataPipelineReader:: +set_object(CPT(GeomVertexData) object) { +#ifdef DO_PIPELINING + if (_cdata != NULL) { + unref_delete((CycleData *)_cdata); } - // _object->_cycler.release_read(_cdata); +#endif // DO_PIPELINING + _array_readers.clear(); + + _object.swap(object); + _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread); + _got_array_readers = false; + + _cdata->ref(); } /** @@ -819,24 +855,6 @@ GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, #endif // _DEBUG } -/** - * Don't attempt to copy these objects. - */ -INLINE GeomVertexDataPipelineWriter:: -GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©) : - GeomVertexDataPipelineBase(copy) -{ - nassertv(false); -} - -/** - * Don't attempt to copy these objects. - */ -INLINE void GeomVertexDataPipelineWriter:: -operator = (const GeomVertexDataPipelineWriter &) { - nassertv(false); -} - /** * */ diff --git a/panda/src/gobj/geomVertexData.cxx b/panda/src/gobj/geomVertexData.cxx index 6b73e4fe0f..cfa47d9949 100644 --- a/panda/src/gobj/geomVertexData.cxx +++ b/panda/src/gobj/geomVertexData.cxx @@ -516,9 +516,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, if (keep_data_objects) { // Copy the data, but keep the same GeomVertexArrayData object. - PT(GeomVertexArrayData) dest_data = modify_array(dest_i); - CPT(GeomVertexArrayData) source_data = source->get_array(source_i); - dest_data->modify_handle()->copy_data_from(source_data->get_handle()); + modify_array_handle(dest_i)->copy_data_from(source->get_array_handle(source_i)); } else { // Copy the GeomVertexArrayData object. if (get_array(dest_i) != source->get_array(source_i)) { @@ -533,13 +531,16 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } // Now make sure the arrays we didn't share are all filled in. - reserve_num_rows(num_rows); - set_num_rows(num_rows); + { + GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread()); + writer.check_array_writers(); + writer.reserve_num_rows(num_rows); + writer.set_num_rows(num_rows); + } // Now go back through and copy any data that's left over. for (source_i = 0; source_i < num_arrays; ++source_i) { - CPT(GeomVertexArrayData) array_obj = source->get_array(source_i); - CPT(GeomVertexArrayDataHandle) array_handle = array_obj->get_handle(); + CPT(GeomVertexArrayDataHandle) array_handle = source->get_array_handle(source_i); const unsigned char *array_data = array_handle->get_read_pointer(true); const GeomVertexArrayFormat *source_array_format = source_format->get_array(source_i); int num_columns = source_array_format->get_num_columns(); @@ -557,8 +558,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, if (dest_column->is_bytewise_equivalent(*source_column)) { // We can do a quick bytewise copy. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); bytewise_copy(dest_array_data + dest_column->get_start(), @@ -569,8 +569,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } else if (dest_column->is_packed_argb() && source_column->is_uint8_rgba()) { // A common special case: OpenGL color to DirectX color. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); uint8_rgba_to_packed_argb @@ -582,8 +581,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects, } else if (dest_column->is_uint8_rgba() && source_column->is_packed_argb()) { // Another common special case: DirectX color to OpenGL color. - PT(GeomVertexArrayData) dest_array_obj = modify_array(dest_i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(dest_i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); packed_argb_to_uint8_rgba @@ -700,12 +698,10 @@ copy_row_from(int dest_row, const GeomVertexData *source, int num_arrays = source_format->get_num_arrays(); for (int i = 0; i < num_arrays; ++i) { - PT(GeomVertexArrayData) dest_array_obj = modify_array(i); - PT(GeomVertexArrayDataHandle) dest_handle = dest_array_obj->modify_handle(); + PT(GeomVertexArrayDataHandle) dest_handle = modify_array_handle(i); unsigned char *dest_array_data = dest_handle->get_write_pointer(); - CPT(GeomVertexArrayData) source_array_obj = source->get_array(i); - CPT(GeomVertexArrayDataHandle) source_array_handle = source_array_obj->get_handle(); + CPT(GeomVertexArrayDataHandle) source_array_handle = source->get_array_handle(i); const unsigned char *source_array_data = source_array_handle->get_read_pointer(true); const GeomVertexArrayFormat *array_format = source_format->get_array(i); @@ -1144,8 +1140,7 @@ do_set_color(GeomVertexData *vdata, const LColor &color) { packer->set_data4f(buffer, color); #endif - PT(GeomVertexArrayDataHandle) handle = - vdata->modify_array(array_index)->modify_handle(); + PT(GeomVertexArrayDataHandle) handle = vdata->modify_array_handle(array_index); unsigned char *write_ptr = handle->get_write_pointer(); unsigned char *end_ptr = write_ptr + handle->get_data_size_bytes(); write_ptr += column->get_start(); @@ -1586,7 +1581,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { } // Then apply the transforms. - CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(); + CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer(current_thread); if (tb_table != (TransformBlendTable *)NULL) { // Recompute all the blends up front, so we don't have to test each one // for staleness at each vertex. @@ -1617,7 +1612,8 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) { if (blend_array_format->get_stride() == 2 && blend_array_format->get_column(0)->get_component_bytes() == 2) { // The blend indices are a table of ushorts. Optimize this common case. - CPT(GeomVertexArrayDataHandle) blend_array_handle = cdata->_arrays[blend_array_index].get_read_pointer()->get_handle(current_thread); + CPT(GeomVertexArrayDataHandle) blend_array_handle = + new GeomVertexArrayDataHandle(cdata->_arrays[blend_array_index].get_read_pointer(current_thread), current_thread); const unsigned short *blendt = (const unsigned short *)blend_array_handle->get_read_pointer(true); size_t ci; @@ -2399,24 +2395,12 @@ make_array_readers() { _array_readers.reserve(_cdata->_arrays.size()); GeomVertexData::Arrays::const_iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { - CPT(GeomVertexArrayData) array_obj = (*ai).get_read_pointer(); - _array_readers.push_back(array_obj->get_handle(_current_thread)); + _array_readers.push_back(new GeomVertexArrayDataHandle((*ai).get_read_pointer(_current_thread), _current_thread)); } _got_array_readers = true; } -/** - * - */ -void GeomVertexDataPipelineReader:: -delete_array_readers() { - nassertv(_got_array_readers); - - _array_readers.clear(); - _got_array_readers = false; -} - /** * */ @@ -2610,7 +2594,7 @@ set_array(int i, const GeomVertexArrayData *array) { _cdata->_animated_vertices_modified = UpdateSeq(); if (_got_array_writers) { - _array_writers[i] = _cdata->_arrays[i].get_write_pointer()->modify_handle(_current_thread); + _array_writers[i] = new GeomVertexArrayDataHandle(_cdata->_arrays[i].get_write_pointer(), _current_thread); } } @@ -2624,8 +2608,7 @@ make_array_writers() { _array_writers.reserve(_cdata->_arrays.size()); GeomVertexData::Arrays::iterator ai; for (ai = _cdata->_arrays.begin(); ai != _cdata->_arrays.end(); ++ai) { - PT(GeomVertexArrayData) array_obj = (*ai).get_write_pointer(); - _array_writers.push_back(array_obj->modify_handle(_current_thread)); + _array_writers.push_back(new GeomVertexArrayDataHandle((*ai).get_write_pointer(), _current_thread)); } _object->clear_cache_stage(); diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index cfb592529d..0261c05a93 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -107,8 +107,10 @@ PUBLISHED: INLINE int get_num_arrays() const; INLINE CPT(GeomVertexArrayData) get_array(int i) const; + INLINE CPT(GeomVertexArrayDataHandle) get_array_handle(int i) const; MAKE_SEQ(get_arrays, get_num_arrays, get_array); INLINE PT(GeomVertexArrayData) modify_array(int i); + INLINE PT(GeomVertexArrayDataHandle) modify_array_handle(int i); INLINE void set_array(int i, const GeomVertexArrayData *array); MAKE_SEQ_PROPERTY(arrays, get_num_arrays, get_array, set_array); @@ -402,6 +404,7 @@ private: */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineBase : public GeomEnums { protected: + INLINE GeomVertexDataPipelineBase(Thread *current_thread); INLINE GeomVertexDataPipelineBase(GeomVertexData *object, Thread *current_thread, GeomVertexData::CData *cdata); @@ -426,7 +429,7 @@ public: protected: PT(GeomVertexData) _object; - Thread *_current_thread; + Thread *const _current_thread; GeomVertexData::CData *_cdata; }; @@ -436,15 +439,16 @@ protected: */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipelineBase { public: + INLINE GeomVertexDataPipelineReader(Thread *current_thread); INLINE GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread); private: - INLINE GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©); - INLINE void operator = (const GeomVertexDataPipelineReader ©); + GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©) DELETED; + GeomVertexDataPipelineReader &operator = (const GeomVertexDataPipelineReader ©) DELETED_ASSIGN; public: - INLINE ~GeomVertexDataPipelineReader(); ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader); + INLINE void set_object(CPT(GeomVertexData) object); INLINE const GeomVertexData *get_object() const; INLINE void check_array_readers() const; @@ -480,7 +484,6 @@ public: private: void make_array_readers(); - void delete_array_readers(); bool _got_array_readers; typedef pvector ArrayReaders; @@ -507,8 +510,8 @@ public: INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, Thread *current_thread); private: - INLINE GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©); - INLINE void operator = (const GeomVertexDataPipelineWriter ©); + GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©) DELETED; + GeomVertexDataPipelineWriter &operator = (const GeomVertexDataPipelineWriter ©) DELETED_ASSIGN; public: INLINE ~GeomVertexDataPipelineWriter(); diff --git a/panda/src/gobj/geomVertexWriter.cxx b/panda/src/gobj/geomVertexWriter.cxx index b80a30fe67..ef05c3bc44 100644 --- a/panda/src/gobj/geomVertexWriter.cxx +++ b/panda/src/gobj/geomVertexWriter.cxx @@ -14,7 +14,7 @@ #include "geomVertexWriter.h" -#ifndef NDEBUG +#ifdef _DEBUG // This is defined just for the benefit of having something non-NULL to // return from a nassertr() call. unsigned char GeomVertexWriter::empty_buffer[100] = { 0 }; diff --git a/panda/src/gobj/geomVertexWriter.h b/panda/src/gobj/geomVertexWriter.h index 815ca6435f..aaedaf565b 100644 --- a/panda/src/gobj/geomVertexWriter.h +++ b/panda/src/gobj/geomVertexWriter.h @@ -212,7 +212,7 @@ private: int _start_row; -#ifndef NDEBUG +#ifdef _DEBUG // This is defined just for the benefit of having something non-NULL to // return from a nassertr() call. static unsigned char empty_buffer[100]; diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index 8c2d03cdd4..c01c851345 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -528,7 +528,7 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat state = state->set_attrib(current_shader_attrib, 10000); // Emit chunk - CullableObject *object = new CullableObject(_chunk_geom, state, modelview_transform); + CullableObject *object = new CullableObject(_chunk_geom, move(state), move(modelview_transform)); trav->get_cull_handler()->record_object(object, trav); // After rendering, increment the view index diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index d5ad3cba4f..b6bb5911f4 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -101,7 +101,7 @@ apply_transform_and_state(CullTraverser *trav, if (clip_plane_cull) { _cull_planes = _cull_planes->apply_state(trav, this, (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), - DCAST(ClipPlaneAttrib, off_clip_planes), + (const ClipPlaneAttrib *)off_clip_planes, (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); } } diff --git a/panda/src/pgraph/cullableObject.I b/panda/src/pgraph/cullableObject.I index 242496587f..2aae972296 100644 --- a/panda/src/pgraph/cullableObject.I +++ b/panda/src/pgraph/cullableObject.I @@ -26,11 +26,11 @@ CullableObject() { * render state and transform. */ INLINE CullableObject:: -CullableObject(const Geom *geom, const RenderState *state, - const TransformState *internal_transform) : - _geom(geom), - _state(state), - _internal_transform(internal_transform) +CullableObject(CPT(Geom) geom, CPT(RenderState) state, + CPT(TransformState) internal_transform) : + _geom(move(geom)), + _state(move(state)), + _internal_transform(move(internal_transform)) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); @@ -135,6 +135,21 @@ draw_inline(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) _geom->draw(gsg, _munger, _munged_data, force, current_thread); } +/** + * Invokes the draw callback, assuming one is set. Crashes if not. + */ +INLINE void CullableObject:: +draw_callback(GraphicsStateGuardianBase *gsg, bool force, Thread *current_thread) { + gsg->clear_before_callback(); + gsg->set_state_and_transform(_state, _internal_transform); + GeomDrawCallbackData cbdata(this, gsg, force); + _draw_callback->do_callback(&cbdata); + if (cbdata.get_lost_state()) { + // Tell the GSG to forget its state. + gsg->clear_state_and_transform(); + } +} + /** * */ diff --git a/panda/src/pgraph/cullableObject.h b/panda/src/pgraph/cullableObject.h index 82fd0df3a5..aa4a3af3c2 100644 --- a/panda/src/pgraph/cullableObject.h +++ b/panda/src/pgraph/cullableObject.h @@ -46,8 +46,8 @@ class EXPCL_PANDA_PGRAPH CullableObject { public: INLINE CullableObject(); - INLINE CullableObject(const Geom *geom, const RenderState *state, - const TransformState *internal_transform); + INLINE CullableObject(CPT(Geom) geom, CPT(RenderState) state, + CPT(TransformState) internal_transform); INLINE CullableObject(const CullableObject ©); INLINE void operator = (const CullableObject ©); @@ -63,6 +63,11 @@ public: INLINE void set_draw_callback(CallbackObject *draw_callback); + INLINE void draw_inline(GraphicsStateGuardianBase *gsg, + bool force, Thread *current_thread); + INLINE void draw_callback(GraphicsStateGuardianBase *gsg, + bool force, Thread *current_thread); + public: ALLOC_DELETED_CHAIN(CullableObject); @@ -82,9 +87,6 @@ private: static CPT(RenderState) get_flash_cpu_state(); static CPT(RenderState) get_flash_hardware_state(); - INLINE void draw_inline(GraphicsStateGuardianBase *gsg, - bool force, Thread *current_thread); - private: // This class is used internally by munge_points_to_quads(). class PointData { diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index f0000d4ebb..7b850fafc6 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -515,7 +515,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { CPT(TransformState) internal_transform = data.get_internal_transform(trav); for (int i = 0; i < num_geoms; i++) { - const Geom *geom = geoms.get_geom(i); + CPT(Geom) geom = geoms.get_geom(i); if (geom->is_empty()) { continue; } @@ -558,7 +558,7 @@ add_for_draw(CullTraverser *trav, CullTraverserData &data) { } CullableObject *object = - new CullableObject(geom, state, internal_transform); + new CullableObject(move(geom), move(state), internal_transform); trav->get_cull_handler()->record_object(object, trav); } } diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 10648b7686..04207356bd 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -1243,16 +1243,14 @@ apply_collect_changes() { void GeomTransformer::NewCollectedData:: append_vdata(const GeomVertexData *vdata, int vertex_offset) { for (int i = 0; i < vdata->get_num_arrays(); ++i) { - PT(GeomVertexArrayData) new_array = _new_data->modify_array(i); - CPT(GeomVertexArrayData) old_array = vdata->get_array(i); + PT(GeomVertexArrayDataHandle) new_handle = _new_data->modify_array_handle(i); + CPT(GeomVertexArrayDataHandle) old_handle = vdata->get_array_handle(i); size_t stride = (size_t)_new_format->get_array(i)->get_stride(); size_t start_byte = (size_t)vertex_offset * stride; - size_t copy_bytes = old_array->get_data_size_bytes(); - nassertv(start_byte + copy_bytes <= new_array->get_data_size_bytes()); + size_t copy_bytes = old_handle->get_data_size_bytes(); + nassertv(start_byte + copy_bytes <= new_handle->get_data_size_bytes()); - new_array->modify_handle()->copy_subdata_from - (start_byte, copy_bytes, - old_array->get_handle(), 0, copy_bytes); + new_handle->copy_subdata_from(start_byte, copy_bytes, old_handle, 0, copy_bytes); } // Also, copy the animation data (if any). This means combining transform diff --git a/panda/src/pgraph/workingNodePath.I b/panda/src/pgraph/workingNodePath.I index 83010f2009..b74921827b 100644 --- a/panda/src/pgraph/workingNodePath.I +++ b/panda/src/pgraph/workingNodePath.I @@ -43,10 +43,10 @@ WorkingNodePath(const WorkingNodePath ©) : * traversal to the next node. */ INLINE WorkingNodePath:: -WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) { - _next = &parent; - _start = (NodePathComponent *)NULL; - _node = child; +WorkingNodePath(const WorkingNodePath &parent, PandaNode *child) : + _next(&parent), + _start(nullptr), + _node(child) { nassertv(_node != _next->_node); } diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index b721486c72..ba460bc3bf 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -73,7 +73,16 @@ get_unique_id() const { */ INLINE int Thread:: get_pipeline_stage() const { - return _pipeline_stage; +#if !defined(_DEBUG) && defined(__has_builtin) && __has_builtin(__builtin_assume) + // Because this is a signed int, this results in a sign extend on x86-64. + // However, since we guarantee that this is never less than zero, clang + // offers a nice way to avoid that. + int pipeline_stage = _pipeline_stage; + __builtin_assume(_pipeline_stage >= 0); + return pipeline_stage; +#else + return pipeline_stage; +#endif } /** diff --git a/panda/src/putil/copyOnWritePointer.I b/panda/src/putil/copyOnWritePointer.I index a44731bcbc..9e996355fa 100644 --- a/panda/src/putil/copyOnWritePointer.I +++ b/panda/src/putil/copyOnWritePointer.I @@ -166,7 +166,7 @@ operator < (const CopyOnWritePointer &other) const { * This flavor of the method is written for the non-threaded case. */ INLINE const CopyOnWriteObject *CopyOnWritePointer:: -get_read_pointer() const { +get_read_pointer(Thread *current_thread) const { return _cow_object; } #endif // COW_THREADED @@ -362,8 +362,14 @@ operator = (PointerTo &&from) NOEXCEPT { */ template INLINE CPT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: -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::To) to; + CPT(CopyOnWriteObject) from = CopyOnWritePointer::get_read_pointer(current_thread); + to.cheat() = (const To *)from.p(); + from.cheat() = nullptr; + return to; } #else // COW_THREADED /** @@ -371,8 +377,8 @@ get_read_pointer() const { */ template INLINE const TYPENAME CopyOnWritePointerTo::To *CopyOnWritePointerTo:: -get_read_pointer() const { - return (const To *)CopyOnWritePointer::get_read_pointer(); +get_read_pointer(Thread *current_thread) const { + return (const To *)CopyOnWritePointer::get_read_pointer(current_thread); } #endif // COW_THREADED #endif // CPPPARSER @@ -385,7 +391,13 @@ get_read_pointer() const { template INLINE PT(TYPENAME CopyOnWritePointerTo::To) CopyOnWritePointerTo:: 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::To) to; + PT(CopyOnWriteObject) from = CopyOnWritePointer::get_write_pointer(); + to.cheat() = (To *)from.p(); + from.cheat() = nullptr; + return to; } #else // COW_THREADED /** diff --git a/panda/src/putil/copyOnWritePointer.cxx b/panda/src/putil/copyOnWritePointer.cxx index e2396e84a9..03ed76e24b 100644 --- a/panda/src/putil/copyOnWritePointer.cxx +++ b/panda/src/putil/copyOnWritePointer.cxx @@ -23,13 +23,11 @@ * This flavor of the method is written for the threaded case. */ CPT(CopyOnWriteObject) CopyOnWritePointer:: -get_read_pointer() const { +get_read_pointer(Thread *current_thread) const { if (_cow_object == (CopyOnWriteObject *)NULL) { return NULL; } - Thread *current_thread = Thread::get_current_thread(); - MutexHolder holder(_cow_object->_lock_mutex); while (_cow_object->_lock_status == CopyOnWriteObject::LS_locked_write) { if (_cow_object->_locking_thread == current_thread) { diff --git a/panda/src/putil/copyOnWritePointer.h b/panda/src/putil/copyOnWritePointer.h index 1a7f0e099d..2178b6b433 100644 --- a/panda/src/putil/copyOnWritePointer.h +++ b/panda/src/putil/copyOnWritePointer.h @@ -48,10 +48,10 @@ public: INLINE bool operator < (const CopyOnWritePointer &other) const; #ifdef COW_THREADED - CPT(CopyOnWriteObject) get_read_pointer() const; + CPT(CopyOnWriteObject) get_read_pointer(Thread *current_thread) const; PT(CopyOnWriteObject) get_write_pointer(); #else - INLINE const CopyOnWriteObject *get_read_pointer() const; + INLINE const CopyOnWriteObject *get_read_pointer(Thread *current_thread) const; INLINE CopyOnWriteObject *get_write_pointer(); #endif // COW_THREADED @@ -93,10 +93,10 @@ public: #endif #ifdef COW_THREADED - INLINE CPT(To) get_read_pointer() const; + INLINE CPT(To) get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const; INLINE PT(To) get_write_pointer(); #else - INLINE const To *get_read_pointer() const; + INLINE const To *get_read_pointer(Thread *current_thread = Thread::get_current_thread()) const; INLINE To *get_write_pointer(); #endif // COW_THREADED diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 4829576407..3c8550a6a5 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -1142,7 +1142,6 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { } else { tris->set_index_type(GeomEnums::NT_uint16); } - PT(GeomVertexArrayData) indices = tris->modify_vertices(); int i = 0; @@ -1150,9 +1149,10 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { // bottleneck. So, I've written this out the hard way instead. Two // versions of the loop: one for 32-bit indices, one for 16-bit. { - PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array(0)->modify_handle(); + PT(GeomVertexArrayDataHandle) vtx_handle = vdata->modify_array_handle(0); vtx_handle->unclean_set_num_rows(quads.size() * 4); + Thread *current_thread = Thread::get_current_thread(); unsigned char *write_ptr = vtx_handle->get_write_pointer(); size_t stride = format->get_array(0)->get_stride() / sizeof(PN_float32); @@ -1163,7 +1163,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { if (tris->get_index_type() == GeomEnums::NT_uint32) { // 32-bit index case. - PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle(); + PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread); idx_handle->unclean_set_num_rows(quads.size() * 6); uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer(); @@ -1219,7 +1219,7 @@ generate_quads(GeomNode *geom_node, const QuadMap &quad_map) { } } else { // 16-bit index case. - PT(GeomVertexArrayDataHandle) idx_handle = indices->modify_handle(); + PT(GeomVertexArrayDataHandle) idx_handle = tris->modify_vertices_handle(current_thread); idx_handle->unclean_set_num_rows(quads.size() * 6); uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer(); From 351627a0e30e05817581bfcc6decbde2d052c937 Mon Sep 17 00:00:00 2001 From: deflected Date: Tue, 21 Feb 2017 02:21:50 +0100 Subject: [PATCH 14/19] glgsg: fix false positive for buffer texture detection on OpenGL 3.0 --- panda/src/glstuff/glGraphicsStateGuardian_src.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index c83c9e52c0..5c73772b50 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -929,7 +929,7 @@ reset() { #endif #ifndef OPENGLES - if (is_at_least_gl_version(3, 0)) { + if (is_at_least_gl_version(3, 1)) { _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBuffer"); _supports_buffer_texture = true; From 1eaa1bcf706eb280654c42c3f99dc5df2cee93d7 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 21 Feb 2017 02:27:28 +0100 Subject: [PATCH 15/19] Fix error when not compiling with clang --- panda/src/pipeline/thread.I | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index ba460bc3bf..b6ae48469a 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -81,7 +81,7 @@ get_pipeline_stage() const { __builtin_assume(_pipeline_stage >= 0); return pipeline_stage; #else - return pipeline_stage; + return _pipeline_stage; #endif } From 8ec4da2824c166c9242bc218876970836c584781 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 21 Feb 2017 02:43:56 +0100 Subject: [PATCH 16/19] Compile fixes for compilers that don't support all C++11 features --- makepanda/makepanda.py | 2 +- panda/src/gobj/geom.h | 2 +- panda/src/gobj/geomPrimitive.h | 2 +- panda/src/gobj/geomVertexData.h | 14 +++++--------- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index adc2064f21..f782898df5 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -1290,7 +1290,7 @@ def CompileCxx(obj,src,opts): cmd += " -fno-strict-aliasing" if optlevel >= 3: - cmd += " -ffast-math -fno-stack-protector -fno-stack-check" + cmd += " -ffast-math -fno-stack-protector" if optlevel == 3: # Fast math is nice, but we'd like to see NaN in dev builds. cmd += " -fno-finite-math-only" diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 0ed8cc5193..a1408878d8 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -435,7 +435,7 @@ public: private: const Geom *_object; - Thread *const _current_thread; + Thread *_current_thread; const Geom::CData *_cdata; public: diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 41c575acd4..0880e77c7a 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -389,7 +389,7 @@ public: private: CPT(GeomPrimitive) _object; - Thread *const _current_thread; + Thread *_current_thread; const GeomPrimitive::CData *_cdata; CPT(GeomVertexArrayData) _vertices; diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 0261c05a93..8e236029ae 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -409,6 +409,10 @@ protected: Thread *current_thread, GeomVertexData::CData *cdata); +private: + GeomVertexDataPipelineBase(const GeomVertexDataPipelineBase ©) DELETED; + GeomVertexDataPipelineBase &operator = (const GeomVertexDataPipelineBase ©) DELETED_ASSIGN; + public: INLINE ~GeomVertexDataPipelineBase(); @@ -429,7 +433,7 @@ public: protected: PT(GeomVertexData) _object; - Thread *const _current_thread; + Thread *_current_thread; GeomVertexData::CData *_cdata; }; @@ -441,11 +445,7 @@ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipel public: INLINE GeomVertexDataPipelineReader(Thread *current_thread); INLINE GeomVertexDataPipelineReader(const GeomVertexData *object, Thread *current_thread); -private: - GeomVertexDataPipelineReader(const GeomVertexDataPipelineReader ©) DELETED; - GeomVertexDataPipelineReader &operator = (const GeomVertexDataPipelineReader ©) DELETED_ASSIGN; -public: ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader); INLINE void set_object(CPT(GeomVertexData) object); @@ -509,11 +509,7 @@ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineWriter : public GeomVertexDataPipel public: INLINE GeomVertexDataPipelineWriter(GeomVertexData *object, bool force_to_0, Thread *current_thread); -private: - GeomVertexDataPipelineWriter(const GeomVertexDataPipelineWriter ©) DELETED; - GeomVertexDataPipelineWriter &operator = (const GeomVertexDataPipelineWriter ©) DELETED_ASSIGN; -public: INLINE ~GeomVertexDataPipelineWriter(); ALLOC_DELETED_CHAIN(GeomVertexDataPipelineWriter); From 72262ea15aeadfe6b2ce8d1fa7cd4930e2901e75 Mon Sep 17 00:00:00 2001 From: rdb Date: Tue, 21 Feb 2017 21:38:46 +0100 Subject: [PATCH 17/19] Fix compiler issues on Windows --- panda/src/dxgsg9/dxIndexBufferContext9.cxx | 3 +-- panda/src/gobj/geomVertexArrayData.I | 11 ++++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx index 6cf6a78c84..fada562e55 100644 --- a/panda/src/dxgsg9/dxIndexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -132,8 +132,7 @@ allocate_ibuffer(DXScreenData &scrn, dxgsg9_cat.debug() << "creating index buffer " << _ibuffer << ": " << reader->get_num_vertices() << " indices (" - << reader->get_vertices_reader()->get_array_format()->get_column(0)->get_numeric_type() - << ")\n"; + << reader->get_index_type() << ")\n"; } } } diff --git a/panda/src/gobj/geomVertexArrayData.I b/panda/src/gobj/geomVertexArrayData.I index 0c2b9904ea..6b29288f3b 100644 --- a/panda/src/gobj/geomVertexArrayData.I +++ b/panda/src/gobj/geomVertexArrayData.I @@ -131,10 +131,10 @@ get_modified() const { */ INLINE bool GeomVertexArrayData:: request_resident(Thread *current_thread) const { -#ifdef DO_PIPELINING - CPT(GeomVertexArrayData::CData) cdata = _cycler.read_unlocked(current_thread); -#else const GeomVertexArrayData::CData *cdata = _cycler.read_unlocked(current_thread); + +#ifdef DO_PIPELINING + cdata->ref(); #endif cdata->_rw_lock.acquire(); @@ -143,6 +143,11 @@ request_resident(Thread *current_thread) const { 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; } From ea1ba281b516dc3d93cbeb36d4e1ce432ecde8b5 Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Wed, 8 Mar 2017 01:54:21 -0700 Subject: [PATCH 18/19] interrogate: Add missing cast in generated calls to PyObject_INIT_VAR --- dtool/src/interrogate/interfaceMakerPythonNative.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dtool/src/interrogate/interfaceMakerPythonNative.cxx b/dtool/src/interrogate/interfaceMakerPythonNative.cxx index 2b51f87689..e4dbfd4084 100644 --- a/dtool/src/interrogate/interfaceMakerPythonNative.cxx +++ b/dtool/src/interrogate/interfaceMakerPythonNative.cxx @@ -6219,7 +6219,7 @@ write_make_seq(ostream &out, Object *obj, const std::string &ClassName, // the assumption that the called method doesn't do anything with this // tuple other than unpack it (which is a fairly safe assumption to make). out << " PyTupleObject args;\n"; - out << " (void)PyObject_INIT_VAR(&args, &PyTuple_Type, 1);\n"; + out << " (void)PyObject_INIT_VAR((PyVarObject *)&args, &PyTuple_Type, 1);\n"; } out << From 4d59ad401488a2a8cfb013b3d0aeb46e4ee455df Mon Sep 17 00:00:00 2001 From: Sam Edwards Date: Wed, 8 Mar 2017 01:59:02 -0700 Subject: [PATCH 19/19] interrogatedb: Build even when _PyErr_OCCURRED is undefined --- dtool/src/interrogatedb/py_panda.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dtool/src/interrogatedb/py_panda.h b/dtool/src/interrogatedb/py_panda.h index f5e77e0dbb..d66ee88c21 100644 --- a/dtool/src/interrogatedb/py_panda.h +++ b/dtool/src/interrogatedb/py_panda.h @@ -303,8 +303,14 @@ template INLINE bool DTOOL_Call_ExtractThisPointer(PyObject *self, T *& // Functions related to error reporting. EXPCL_INTERROGATEDB bool _Dtool_CheckErrorOccurred(); +// _PyErr_OCCURRED is an undocumented macro version of PyErr_Occurred. +// Some implementations of the CPython API (e.g. PyPy's cpyext) do not define +// it, so in these cases we just silently fall back to PyErr_Occurred. +#ifndef _PyErr_OCCURRED +#define _PyErr_OCCURRED() PyErr_Occurred() +#endif + #ifdef NDEBUG -// _PyErr_OCCURRED is an undocumented inline version of PyErr_Occurred. #define Dtool_CheckErrorOccurred() (_PyErr_OCCURRED() != NULL) #else #define Dtool_CheckErrorOccurred() _Dtool_CheckErrorOccurred()