diff --git a/modules/jolt_physics/SCsub b/modules/jolt_physics/SCsub index cd84c0ef0b..08500d8fc1 100644 --- a/modules/jolt_physics/SCsub +++ b/modules/jolt_physics/SCsub @@ -132,14 +132,9 @@ thirdparty_sources = [ "Jolt/Skeleton/Skeleton.cpp", "Jolt/Skeleton/SkeletonMapper.cpp", "Jolt/Skeleton/SkeletonPose.cpp", - "Jolt/TriangleGrouper/TriangleGrouperClosestCentroid.cpp", - "Jolt/TriangleGrouper/TriangleGrouperMorton.cpp", "Jolt/TriangleSplitter/TriangleSplitter.cpp", "Jolt/TriangleSplitter/TriangleSplitterBinning.cpp", - "Jolt/TriangleSplitter/TriangleSplitterFixedLeafSize.cpp", - "Jolt/TriangleSplitter/TriangleSplitterLongestAxis.cpp", "Jolt/TriangleSplitter/TriangleSplitterMean.cpp", - "Jolt/TriangleSplitter/TriangleSplitterMorton.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] diff --git a/modules/jolt_physics/shapes/jolt_height_map_shape_3d.cpp b/modules/jolt_physics/shapes/jolt_height_map_shape_3d.cpp index edacc6d057..2855ec88e0 100644 --- a/modules/jolt_physics/shapes/jolt_height_map_shape_3d.cpp +++ b/modules/jolt_physics/shapes/jolt_height_map_shape_3d.cpp @@ -103,7 +103,7 @@ JPH::ShapeRefC JoltHeightMapShape3D::_build_height_field() const { } } - JPH::HeightFieldShapeSettings shape_settings(heights_rev.ptr(), JPH::Vec3(offset_x, 0, offset_y), JPH::Vec3::sReplicate(1.0f), (JPH::uint32)width); + JPH::HeightFieldShapeSettings shape_settings(heights_rev.ptr(), JPH::Vec3(offset_x, 0, offset_y), JPH::Vec3::sOne(), (JPH::uint32)width); shape_settings.mBitsPerSample = shape_settings.CalculateBitsPerSampleForError(0.0f); shape_settings.mActiveEdgeCosThresholdAngle = JoltProjectSettings::active_edge_threshold_cos; diff --git a/modules/jolt_physics/spaces/jolt_physics_direct_space_state_3d.cpp b/modules/jolt_physics/spaces/jolt_physics_direct_space_state_3d.cpp index 02fcbbc7e6..d78f08c8c1 100644 --- a/modules/jolt_physics/spaces/jolt_physics_direct_space_state_3d.cpp +++ b/modules/jolt_physics/spaces/jolt_physics_direct_space_state_3d.cpp @@ -190,7 +190,7 @@ bool JoltPhysicsDirectSpaceState3D::_body_motion_recover(const JoltBody3D &p_bod for (int i = 0; i < JoltProjectSettings::motion_query_recovery_iterations; ++i) { collector.reset(); - _collide_shape_kinematics(jolt_shape, JPH::Vec3::sReplicate(1.0f), to_jolt_r(transform_com), settings, to_jolt_r(base_offset), collector, motion_filter, motion_filter, motion_filter, motion_filter); + _collide_shape_kinematics(jolt_shape, JPH::Vec3::sOne(), to_jolt_r(transform_com), settings, to_jolt_r(base_offset), collector, motion_filter, motion_filter, motion_filter, motion_filter); if (!collector.had_hit()) { break; @@ -320,7 +320,7 @@ bool JoltPhysicsDirectSpaceState3D::_body_motion_collide(const JoltBody3D &p_bod const JoltMotionFilter3D motion_filter(p_body, p_excluded_bodies, p_excluded_objects); JoltQueryCollectorClosestMulti collector(p_max_collisions); - _collide_shape_kinematics(jolt_shape, JPH::Vec3::sReplicate(1.0f), to_jolt_r(transform_com), settings, to_jolt_r(base_offset), collector, motion_filter, motion_filter, motion_filter, motion_filter); + _collide_shape_kinematics(jolt_shape, JPH::Vec3::sOne(), to_jolt_r(transform_com), settings, to_jolt_r(base_offset), collector, motion_filter, motion_filter, motion_filter, motion_filter); if (!collector.had_hit() || p_result == nullptr) { return collector.had_hit(); @@ -418,7 +418,7 @@ void JoltPhysicsDirectSpaceState3D::_generate_manifold(const JPH::CollideShapeRe const JPH::PhysicsSettings &physics_settings = physics_system.GetPhysicsSettings(); const JPH::Vec3 penetration_axis = p_hit.mPenetrationAxis.Normalized(); - JPH::ManifoldBetweenTwoFaces(p_hit.mContactPointOn1, p_hit.mContactPointOn2, penetration_axis, physics_settings.mManifoldToleranceSq, p_hit.mShape1Face, p_hit.mShape2Face, r_contact_points1, r_contact_points2 JPH_IF_DEBUG_RENDERER(, p_center_of_mass)); + JPH::ManifoldBetweenTwoFaces(p_hit.mContactPointOn1, p_hit.mContactPointOn2, penetration_axis, physics_settings.mManifoldTolerance, p_hit.mShape1Face, p_hit.mShape2Face, r_contact_points1, r_contact_points2 JPH_IF_DEBUG_RENDERER(, p_center_of_mass)); if (r_contact_points1.size() > 4) { JPH::PruneContactPoints(penetration_axis, r_contact_points1, r_contact_points2 JPH_IF_DEBUG_RENDERER(, p_center_of_mass)); diff --git a/thirdparty/README.md b/thirdparty/README.md index de19519224..9591ea294a 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -448,7 +448,7 @@ Files generated from upstream source: ## jolt_physics - Upstream: https://github.com/jrouwe/JoltPhysics -- Version: 5.2.1 (f094082aa2bbfcbebc725dbe8b8f65c7d5152886, 2024) +- Version: 5.3.0 (0373ec0dd762e4bc2f6acdb08371ee84fa23c6db, 2025) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/jolt_physics/Jolt/Core/Array.h b/thirdparty/jolt_physics/Jolt/Core/Array.h index a273f4eb50..b8dbce5953 100644 --- a/thirdparty/jolt_physics/Jolt/Core/Array.h +++ b/thirdparty/jolt_physics/Jolt/Core/Array.h @@ -47,6 +47,83 @@ public: using const_iterator = const T *; using iterator = T *; + /// An iterator that traverses the array in reverse order + class rev_it + { + public: + /// Constructor + rev_it() = default; + explicit rev_it(T *inValue) : mValue(inValue) { } + + /// Copying + rev_it(const rev_it &) = default; + rev_it & operator = (const rev_it &) = default; + + /// Comparison + bool operator == (const rev_it &inRHS) const { return mValue == inRHS.mValue; } + bool operator != (const rev_it &inRHS) const { return mValue != inRHS.mValue; } + + /// Arithmetics + rev_it & operator ++ () { --mValue; return *this; } + rev_it operator ++ (int) { return rev_it(mValue--); } + rev_it & operator -- () { ++mValue; return *this; } + rev_it operator -- (int) { return rev_it(mValue++); } + + rev_it operator + (int inValue) { return rev_it(mValue - inValue); } + rev_it operator - (int inValue) { return rev_it(mValue + inValue); } + + rev_it & operator += (int inValue) { mValue -= inValue; return *this; } + rev_it & operator -= (int inValue) { mValue += inValue; return *this; } + + /// Access + T & operator * () const { return *mValue; } + T & operator -> () const { return *mValue; } + + private: + T * mValue; + }; + + /// A const iterator that traverses the array in reverse order + class crev_it + { + public: + /// Constructor + crev_it() = default; + explicit crev_it(const T *inValue) : mValue(inValue) { } + + /// Copying + crev_it(const crev_it &) = default; + explicit crev_it(const rev_it &inValue) : mValue(inValue.mValue) { } + crev_it & operator = (const crev_it &) = default; + crev_it & operator = (const rev_it &inRHS) { mValue = inRHS.mValue; return *this; } + + /// Comparison + bool operator == (const crev_it &inRHS) const { return mValue == inRHS.mValue; } + bool operator != (const crev_it &inRHS) const { return mValue != inRHS.mValue; } + + /// Arithmetics + crev_it & operator ++ () { --mValue; return *this; } + crev_it operator ++ (int) { return crev_it(mValue--); } + crev_it & operator -- () { ++mValue; return *this; } + crev_it operator -- (int) { return crev_it(mValue++); } + + crev_it operator + (int inValue) { return crev_it(mValue - inValue); } + crev_it operator - (int inValue) { return crev_it(mValue + inValue); } + + crev_it & operator += (int inValue) { mValue -= inValue; return *this; } + crev_it & operator -= (int inValue) { mValue += inValue; return *this; } + + /// Access + const T & operator * () const { return *mValue; } + const T & operator -> () const { return *mValue; } + + private: + const T * mValue; + }; + + using reverse_iterator = rev_it; + using const_reverse_iterator = crev_it; + private: /// Move elements from one location to another inline void move(pointer inDestination, pointer inSource, size_type inCount) @@ -388,7 +465,7 @@ public: } /// Remove one element from the array - void erase(const_iterator inIter) + iterator erase(const_iterator inIter) { size_type p = size_type(inIter - begin()); JPH_ASSERT(p < mSize); @@ -396,10 +473,11 @@ public: if (p + 1 < mSize) move(mElements + p, mElements + p + 1, mSize - p - 1); --mSize; + return const_cast(inIter); } /// Remove multiple element from the array - void erase(const_iterator inBegin, const_iterator inEnd) + iterator erase(const_iterator inBegin, const_iterator inEnd) { size_type p = size_type(inBegin - begin()); size_type n = size_type(inEnd - inBegin); @@ -408,6 +486,7 @@ public: if (p + n < mSize) move(mElements + p, mElements + p + n, mSize - p - n); mSize -= n; + return const_cast(inBegin); } /// Iterators @@ -421,14 +500,34 @@ public: return mElements + mSize; } + inline crev_it rbegin() const + { + return crev_it(mElements + mSize - 1); + } + + inline crev_it rend() const + { + return crev_it(mElements - 1); + } + inline const_iterator cbegin() const { - return mElements; + return begin(); } inline const_iterator cend() const { - return mElements + mSize; + return end(); + } + + inline crev_it crbegin() const + { + return rbegin(); + } + + inline crev_it crend() const + { + return rend(); } inline iterator begin() @@ -441,6 +540,16 @@ public: return mElements + mSize; } + inline rev_it rbegin() + { + return rev_it(mElements + mSize - 1); + } + + inline rev_it rend() + { + return rev_it(mElements - 1); + } + inline const T * data() const { return mElements; diff --git a/thirdparty/jolt_physics/Jolt/Core/Color.h b/thirdparty/jolt_physics/Jolt/Core/Color.h index d07390de1c..7706ca85b5 100644 --- a/thirdparty/jolt_physics/Jolt/Core/Color.h +++ b/thirdparty/jolt_physics/Jolt/Core/Color.h @@ -12,7 +12,7 @@ class Color; using ColorArg = Color; /// Class that holds an RGBA color with 8-bits per component -class [[nodiscard]] JPH_EXPORT_GCC_BUG_WORKAROUND Color +class JPH_EXPORT_GCC_BUG_WORKAROUND [[nodiscard]] Color { public: /// Constructors diff --git a/thirdparty/jolt_physics/Jolt/Core/Core.h b/thirdparty/jolt_physics/Jolt/Core/Core.h index 01b6afbf19..dfd2a04d2f 100644 --- a/thirdparty/jolt_physics/Jolt/Core/Core.h +++ b/thirdparty/jolt_physics/Jolt/Core/Core.h @@ -6,8 +6,8 @@ // Jolt library version #define JPH_VERSION_MAJOR 5 -#define JPH_VERSION_MINOR 2 -#define JPH_VERSION_PATCH 1 +#define JPH_VERSION_MINOR 3 +#define JPH_VERSION_PATCH 0 // Determine which features the library was compiled with #ifdef JPH_DOUBLE_PRECISION @@ -83,8 +83,8 @@ #define JPH_PLATFORM_ANDROID #elif defined(__linux__) #define JPH_PLATFORM_LINUX -#elif defined(__FreeBSD__) - #define JPH_PLATFORM_FREEBSD +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) + #define JPH_PLATFORM_BSD #elif defined(__APPLE__) #include #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE @@ -195,7 +195,11 @@ #elif defined(JPH_PLATFORM_WASM) // WebAssembly CPU architecture #define JPH_CPU_WASM - #define JPH_CPU_ADDRESS_BITS 32 + #if defined(__wasm64__) + #define JPH_CPU_ADDRESS_BITS 64 + #else + #define JPH_CPU_ADDRESS_BITS 32 + #endif #define JPH_VECTOR_ALIGNMENT 16 #define JPH_DVECTOR_ALIGNMENT 32 #ifdef __wasm_simd128__ @@ -360,6 +364,7 @@ JPH_MSVC_SUPPRESS_WARNING(4514) /* 'X' : unreferenced inline function has been removed */ \ JPH_MSVC_SUPPRESS_WARNING(4710) /* 'X' : function not inlined */ \ JPH_MSVC_SUPPRESS_WARNING(4711) /* function 'X' selected for automatic inline expansion */ \ + JPH_MSVC_SUPPRESS_WARNING(4714) /* function 'X' marked as __forceinline not inlined */ \ JPH_MSVC_SUPPRESS_WARNING(4820) /* 'X': 'Y' bytes padding added after data member 'Z' */ \ JPH_MSVC_SUPPRESS_WARNING(4100) /* 'X' : unreferenced formal parameter */ \ JPH_MSVC_SUPPRESS_WARNING(4626) /* 'X' : assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted */ \ @@ -388,9 +393,9 @@ // Configuration for a popular game console. // This file is not distributed because it would violate an NDA. // Creating one should only be a couple of minutes of work if you have the documentation for the platform - // (you only need to define JPH_BREAKPOINT, JPH_PLATFORM_BLUE_GET_TICKS, JPH_PLATFORM_BLUE_MUTEX*, JPH_PLATFORM_BLUE_RWLOCK* and include the right header). + // (you only need to define JPH_BREAKPOINT, JPH_PLATFORM_BLUE_GET_TICKS, JPH_PLATFORM_BLUE_MUTEX*, JPH_PLATFORM_BLUE_RWLOCK*, JPH_PLATFORM_BLUE_SEMAPHORE* and include the right header). #include -#elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_FREEBSD) +#elif defined(JPH_PLATFORM_LINUX) || defined(JPH_PLATFORM_ANDROID) || defined(JPH_PLATFORM_MACOS) || defined(JPH_PLATFORM_IOS) || defined(JPH_PLATFORM_BSD) #if defined(JPH_CPU_X86) #define JPH_BREAKPOINT __asm volatile ("int $0x3") #elif defined(JPH_CPU_ARM) || defined(JPH_CPU_RISCV) || defined(JPH_CPU_E2K) || defined(JPH_CPU_PPC) || defined(JPH_CPU_LOONGARCH) @@ -426,7 +431,8 @@ JPH_MSVC_SUPPRESS_WARNING(4514) \ JPH_MSVC_SUPPRESS_WARNING(5262) \ JPH_MSVC_SUPPRESS_WARNING(5264) \ - JPH_MSVC_SUPPRESS_WARNING(4738) + JPH_MSVC_SUPPRESS_WARNING(4738) \ + JPH_MSVC_SUPPRESS_WARNING(5045) #define JPH_SUPPRESS_WARNINGS_STD_END \ JPH_SUPPRESS_WARNING_POP diff --git a/thirdparty/jolt_physics/Jolt/Core/FPException.h b/thirdparty/jolt_physics/Jolt/Core/FPException.h index ef75780242..9e22f5422e 100644 --- a/thirdparty/jolt_physics/Jolt/Core/FPException.h +++ b/thirdparty/jolt_physics/Jolt/Core/FPException.h @@ -16,11 +16,12 @@ JPH_NAMESPACE_BEGIN class FPExceptionsEnable { }; class FPExceptionDisableInvalid { }; class FPExceptionDisableDivByZero { }; +class FPExceptionDisableOverflow { }; #elif defined(JPH_USE_SSE) -/// Enable floating point divide by zero exception and exceptions on invalid numbers -class FPExceptionsEnable : public FPControlWord<0, _MM_MASK_DIV_ZERO | _MM_MASK_INVALID> { }; +/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers +class FPExceptionsEnable : public FPControlWord<0, _MM_MASK_DIV_ZERO | _MM_MASK_INVALID | _MM_MASK_OVERFLOW> { }; /// Disable invalid floating point value exceptions class FPExceptionDisableInvalid : public FPControlWord<_MM_MASK_INVALID, _MM_MASK_INVALID> { }; @@ -28,10 +29,13 @@ class FPExceptionDisableInvalid : public FPControlWord<_MM_MASK_INVALID, _MM_MAS /// Disable division by zero floating point exceptions class FPExceptionDisableDivByZero : public FPControlWord<_MM_MASK_DIV_ZERO, _MM_MASK_DIV_ZERO> { }; +/// Disable floating point overflow exceptions +class FPExceptionDisableOverflow : public FPControlWord<_MM_MASK_OVERFLOW, _MM_MASK_OVERFLOW> { }; + #elif defined(JPH_CPU_ARM) && defined(JPH_COMPILER_MSVC) -/// Enable floating point divide by zero exception and exceptions on invalid numbers -class FPExceptionsEnable : public FPControlWord<0, _EM_INVALID | _EM_ZERODIVIDE> { }; +/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers +class FPExceptionsEnable : public FPControlWord<0, _EM_INVALID | _EM_ZERODIVIDE | _EM_OVERFLOW> { }; /// Disable invalid floating point value exceptions class FPExceptionDisableInvalid : public FPControlWord<_EM_INVALID, _EM_INVALID> { }; @@ -39,6 +43,9 @@ class FPExceptionDisableInvalid : public FPControlWord<_EM_INVALID, _EM_INVALID> /// Disable division by zero floating point exceptions class FPExceptionDisableDivByZero : public FPControlWord<_EM_ZERODIVIDE, _EM_ZERODIVIDE> { }; +/// Disable floating point overflow exceptions +class FPExceptionDisableOverflow : public FPControlWord<_EM_OVERFLOW, _EM_OVERFLOW> { }; + #elif defined(JPH_CPU_ARM) /// Invalid operation exception bit @@ -47,8 +54,11 @@ static constexpr uint64 FP_IOE = 1 << 8; /// Enable divide by zero exception bit static constexpr uint64 FP_DZE = 1 << 9; -/// Enable floating point divide by zero exception and exceptions on invalid numbers -class FPExceptionsEnable : public FPControlWord { }; +/// Enable floating point overflow bit +static constexpr uint64 FP_OFE = 1 << 10; + +/// Enable floating point divide by zero exception, overflow exceptions and exceptions on invalid numbers +class FPExceptionsEnable : public FPControlWord { }; /// Disable invalid floating point value exceptions class FPExceptionDisableInvalid : public FPControlWord<0, FP_IOE> { }; @@ -56,6 +66,9 @@ class FPExceptionDisableInvalid : public FPControlWord<0, FP_IOE> { }; /// Disable division by zero floating point exceptions class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { }; +/// Disable floating point overflow exceptions +class FPExceptionDisableOverflow : public FPControlWord<0, FP_OFE> { }; + #elif defined(JPH_CPU_RISCV) #error "RISC-V only implements manually checking if exceptions occurred by reading the fcsr register. It doesn't generate exceptions. JPH_FLOATING_POINT_EXCEPTIONS_ENABLED must be disabled." @@ -76,6 +89,7 @@ class FPExceptionDisableDivByZero : public FPControlWord<0, FP_DZE> { }; class FPExceptionsEnable { }; class FPExceptionDisableInvalid { }; class FPExceptionDisableDivByZero { }; +class FPExceptionDisableOverflow { }; #endif diff --git a/thirdparty/jolt_physics/Jolt/Core/HashTable.h b/thirdparty/jolt_physics/Jolt/Core/HashTable.h index 9b69f9d084..d2d766fe0f 100644 --- a/thirdparty/jolt_physics/Jolt/Core/HashTable.h +++ b/thirdparty/jolt_physics/Jolt/Core/HashTable.h @@ -26,10 +26,10 @@ private: class IteratorBase { public: - /// Properties + /// Properties using difference_type = typename Table::difference_type; - using value_type = typename Table::value_type; - using iterator_category = std::forward_iterator_tag; + using value_type = typename Table::value_type; + using iterator_category = std::forward_iterator_tag; /// Copy constructor IteratorBase(const IteratorBase &inRHS) = default; @@ -179,17 +179,9 @@ private: mSize = inRHS.mSize; } - /// Grow the table to the next power of 2 - void GrowTable() + /// Grow the table to a new size + void GrowTable(size_type inNewMaxSize) { - // Calculate new size - size_type new_max_size = max(mMaxSize << 1, 16); - if (new_max_size < mMaxSize) - { - JPH_ASSERT(false, "Overflow in hash table size, can't grow!"); - return; - } - // Move the old table to a temporary structure size_type old_max_size = mMaxSize; KeyValue *old_data = mData; @@ -201,7 +193,7 @@ private: mLoadLeft = 0; // Allocate new table - AllocateTable(new_max_size); + AllocateTable(inNewMaxSize); // Reset all control bytes memset(mControl, cBucketEmpty, mMaxSize + 15); @@ -252,7 +244,16 @@ protected: if (num_deleted * cMaxDeletedElementsDenominator > mMaxSize * cMaxDeletedElementsNumerator) rehash(0); else - GrowTable(); + { + // Grow by a power of 2 + size_type new_max_size = max(mMaxSize << 1, 16); + if (new_max_size < mMaxSize) + { + JPH_ASSERT(false, "Overflow in hash table size, can't grow!"); + return false; + } + GrowTable(new_max_size); + } } // Split hash into index and control value @@ -363,9 +364,9 @@ public: using Base = IteratorBase; public: - /// Properties - using reference = typename Base::value_type &; - using pointer = typename Base::value_type *; + /// Properties + using reference = typename Base::value_type &; + using pointer = typename Base::value_type *; /// Constructors explicit iterator(HashTable *inTable) : Base(inTable) { } @@ -400,9 +401,9 @@ public: using Base = IteratorBase; public: - /// Properties - using reference = const typename Base::value_type &; - using pointer = const typename Base::value_type *; + /// Properties + using reference = const typename Base::value_type &; + using pointer = const typename Base::value_type *; /// Constructors explicit const_iterator(const HashTable *inTable) : Base(inTable) { } @@ -489,11 +490,7 @@ public: if (max_size <= mMaxSize) return; - // Allocate buffers - AllocateTable(max_size); - - // Reset all control bytes - memset(mControl, cBucketEmpty, mMaxSize + 15); + GrowTable(max_size); } /// Destroy the entire hash table @@ -523,6 +520,27 @@ public: } } + /// Destroy the entire hash table but keeps the memory allocated + void ClearAndKeepMemory() + { + // Destruct elements + if constexpr (!std::is_trivially_destructible()) + if (!empty()) + for (size_type i = 0; i < mMaxSize; ++i) + if (mControl[i] & cBucketUsed) + mData[i].~KeyValue(); + mSize = 0; + + // If there are elements that are not marked cBucketEmpty, we reset them + size_type max_load = sGetMaxLoad(mMaxSize); + if (mLoadLeft != max_load) + { + // Reset all control bytes + memset(mControl, cBucketEmpty, mMaxSize + 15); + mLoadLeft = max_load; + } + } + /// Iterator to first element iterator begin() { diff --git a/thirdparty/jolt_physics/Jolt/Core/Profiler.cpp b/thirdparty/jolt_physics/Jolt/Core/Profiler.cpp index 39152b10b4..6536607d5a 100644 --- a/thirdparty/jolt_physics/Jolt/Core/Profiler.cpp +++ b/thirdparty/jolt_physics/Jolt/Core/Profiler.cpp @@ -222,8 +222,331 @@ void Profiler::DumpChart(const char *inTag, const Threads &inThreads, const KeyT Profile Chart - - + +