diff --git a/data/uking_functions.csv b/data/uking_functions.csv index 4d983a19..bc351901 100644 --- a/data/uking_functions.csv +++ b/data/uking_functions.csv @@ -103040,12 +103040,12 @@ Address,Quality,Size,Name 0x0000007101585b50,U,000016, 0x0000007101585b60,U,000004,nullsub_5613 0x0000007101585b64,U,000004,nullsub_5614 -0x0000007101585b68,U,000008, +0x0000007101585b68,O,000008,_ZNK18hkReferencedObject12getClassTypeEv 0x0000007101585b70,U,000256, 0x0000007101585c70,U,000020, 0x0000007101585c84,U,000120, 0x0000007101585cfc,U,000088, -0x0000007101585d54,U,000020, +0x0000007101585d54,O,000020,_ZNK18hkReferencedObject26deleteThisReferencedObjectEv 0x0000007101585d68,U,000096, 0x0000007101585dc8,U,000168, 0x0000007101585e70,U,000016, diff --git a/lib/hkStubs/CMakeLists.txt b/lib/hkStubs/CMakeLists.txt index cb26f6a7..3ec0a122 100644 --- a/lib/hkStubs/CMakeLists.txt +++ b/lib/hkStubs/CMakeLists.txt @@ -2,11 +2,23 @@ project(hkStubs CXX ASM) add_library(hkStubs OBJECT Havok/Common/Base/hkBase.h + Havok/Common/Base/Container/String/hkStringPtr.h + Havok/Common/Base/Math/hkMath.h Havok/Common/Base/Math/Vector/hkVector4.h + + Havok/Common/Base/Memory/Allocator/hkMemoryAllocator.h + Havok/Common/Base/Memory/Allocator/Lifo/hkLifoAllocator.h + Havok/Common/Base/Memory/Router/hkMemoryRouter.h + Havok/Common/Base/Object/hkBaseObject.h + Havok/Common/Base/Object/hkReferencedObject.cpp Havok/Common/Base/Object/hkReferencedObject.h + + Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h + Havok/Common/Base/Thread/Thread/hkThreadLocalData.h + Havok/Common/Base/Types/hkBaseDefs.h Havok/Common/Base/Types/hkBaseTypes.h @@ -14,6 +26,7 @@ add_library(hkStubs OBJECT Havok/Physics/Collide/Shape/Convex/hkpConvexShape.h Havok/Physics/Collide/Shape/Convex/Capsule/hkpCapsuleShape.h Havok/Physics/Collide/Shape/HeightField/hkpSphereRepShape.h + Havok/Physics/Dynamics/Entity/hkpEntity.h Havok/Physics/Dynamics/Entity/hkpRigidBody.h Havok/Physics/Dynamics/World/hkpWorld.cpp @@ -25,3 +38,8 @@ target_compile_options(hkStubs PRIVATE -fno-exceptions) target_compile_options(hkStubs PRIVATE -fno-strict-aliasing) target_compile_options(hkStubs PRIVATE -Wno-invalid-offsetof) target_include_directories(hkStubs PUBLIC ./) + +if(NOT TARGET NintendoSDK) + add_subdirectory(../NintendoSDK) +endif() +target_link_libraries(hkStubs PUBLIC NintendoSDK) diff --git a/lib/hkStubs/Havok/Common/Base/Memory/Allocator/Lifo/hkLifoAllocator.h b/lib/hkStubs/Havok/Common/Base/Memory/Allocator/Lifo/hkLifoAllocator.h new file mode 100644 index 00000000..2305dbf8 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Memory/Allocator/Lifo/hkLifoAllocator.h @@ -0,0 +1,57 @@ +#pragma once + +#include + +class hkLifoAllocator : public hkMemoryAllocator { +public: + explicit hkLifoAllocator(int slabSize = 32 * 1024); + + void init(hkMemoryAllocator* slabAllocator, hkMemoryAllocator* largeAllocator, + hkMemoryAllocator* internalAllocator); + /// Optional: [slabAllocator, largeAllocator, internalAllocator] + void quit(hkMemoryAllocator* allocators[3] = nullptr); + + void* blockAlloc(int numBytes) override; + + /// Inline equivalent of blockAlloc + // TODO: add this if this is actually used by BotW + HK_FORCE_INLINE void* fastBlockAlloc(int numBytes); + + void blockFree(void* p, int numBytes) override; + + /// Inline equivalent of blockFree + // TODO: add this if this is actually used by BotW + HK_FORCE_INLINE void fastBlockFree(void* p, int numBytes); + + void* bufAlloc(int& reqNumBytesInOut) override; + void bufFree(void* p, int numBytes) override; + void* bufRealloc(void* pold, int oldNumBytes, int& reqNumBytesInOut) override; + + void getMemoryStatistics(MemoryStatistics& u) const override {} + int getAllocatedSize(const void* obj, int nbytes) const override { return nbytes; } + + bool isEmpty() const; + int numExternalAllocations() const; + +protected: + void* allocateFromNewSlab(int nbytes); + void popNonLifoFrees(); + void slowBlockFree(void*, int numBytesIn); + void insertNonLifoFree(void* p, int nbytes); + + class Implementation; + + Implementation* m_impl; + + const int m_slabSize; + + void* m_cur; + void* m_end; + void* m_firstNonLifoEnd; + + void* m_cachedEmptySlab; + + hkMemoryAllocator* m_slabAllocator; + hkMemoryAllocator* m_largeAllocator; + hkMemoryAllocator* m_internalAllocator; +}; diff --git a/lib/hkStubs/Havok/Common/Base/Memory/Allocator/hkMemoryAllocator.h b/lib/hkStubs/Havok/Common/Base/Memory/Allocator/hkMemoryAllocator.h new file mode 100644 index 00000000..b024b565 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Memory/Allocator/hkMemoryAllocator.h @@ -0,0 +1,102 @@ +#pragma once + +#include + +class hkMemorySnapshot; + +template +struct hkSizeOfTypeOrVoid { + enum { val = sizeof(T) }; +}; + +template <> +struct hkSizeOfTypeOrVoid { + enum { val = 1 }; +}; + +class hkMemoryAllocator { +public: + using MemoryWalkCallback = void (*)(void* start, hk_size_t size, bool allocated, int pool, + void* param); + + struct MemoryStatistics { + static const hkLong INFINITE_SIZE = -1; + + hkLong m_allocated = -1; + hkLong m_inUse = -1; + hkLong m_peakInUse = -1; + hkLong m_available = -1; + hkLong m_totalAvailable = -1; + hkLong m_largestBlock = -1; + }; + + struct ExtendedInterface { + virtual ~ExtendedInterface() = default; + + virtual void garbageCollect() = 0; + virtual void incrementalGarbageCollect(int numBlocks) = 0; + virtual hkResult setMemorySoftLimit(hk_size_t maxMemory) = 0; + virtual hk_size_t getMemorySoftLimit() const = 0; + virtual bool canAllocTotal(int numBytes) = 0; + virtual hkResult walkMemory(MemoryWalkCallback callback, void* param) = 0; + virtual hk_size_t getApproxTotalAllocated() const = 0; + virtual void setScrubValues(hkUint32 allocValue, hkUint32 freeValue) = 0; + virtual int addToSnapshot(hkMemorySnapshot& snap, int parentId) = 0; + }; + + virtual ~hkMemoryAllocator(); + + virtual void* blockAlloc(int numBytes) = 0; + virtual void blockFree(void* p, int numBytes) = 0; + virtual void* bufAlloc(int& reqNumBytesInOut); + virtual void bufFree(void* p, int numBytes); + virtual void* bufRealloc(void* pold, int oldNumBytes, int& reqNumBytesInOut); + + virtual void blockAllocBatch(void** ptrsOut, int numPtrs, int blockSize); + virtual void blockFreeBatch(void** ptrsIn, int numPtrs, int blockSize); + + virtual void getMemoryStatistics(MemoryStatistics& u) const = 0; + virtual int getAllocatedSize(const void* obj, int nbytes) const = 0; + virtual void resetPeakMemoryStatistics() {} + + virtual ExtendedInterface* getExtendedInterface() { return nullptr; } + + template + inline TYPE* _bufAlloc(int& reqNumInOut) { + const int SIZE_ELEM = hkSizeOfTypeOrVoid::val; + int n = reqNumInOut * SIZE_ELEM; + void* p = bufAlloc(n); + reqNumInOut = n / SIZE_ELEM; + return static_cast(p); + } + + template + inline void _bufFree(void* p, int numElem) { + const int SIZE_ELEM = hkSizeOfTypeOrVoid::val; + bufFree(p, numElem * SIZE_ELEM); + } + + template + inline TYPE* _bufRealloc(void* pold, int oldNum, int& reqNumInOut) { + const int SIZE_ELEM = hkSizeOfTypeOrVoid::val; + int n = reqNumInOut * SIZE_ELEM; + void* p = bufRealloc(pold, oldNum * SIZE_ELEM, n); + reqNumInOut = n / SIZE_ELEM; + return static_cast(p); + } + + template + inline TYPE* _blockAlloc(int n) { + return static_cast(blockAlloc(n * hkSizeOfTypeOrVoid::val)); + } + + template + inline void _blockFree(TYPE* p, int n) { + blockFree(p, n * hkSizeOfTypeOrVoid::val); + } + + enum MemoryState { + MEMORY_STATE_OK, + MEMORY_STATE_OUT_OF_MEMORY, + }; +}; diff --git a/lib/hkStubs/Havok/Common/Base/Memory/Router/hkMemoryRouter.h b/lib/hkStubs/Havok/Common/Base/Memory/Router/hkMemoryRouter.h new file mode 100644 index 00000000..d8be9046 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Memory/Router/hkMemoryRouter.h @@ -0,0 +1,98 @@ +#pragma once + +#include +#include +#include +#include + +class hkLifoAllocator; + +class hkOstream; + +class hkMemoryRouter { +public: + using Stack = hkLifoAllocator; + using Allocator = hkMemoryAllocator; + + static void replaceInstance(hkMemoryRouter* m); + + static inline hkMemoryRouter& getInstance() { return *getInstancePtr(); } + static inline hkMemoryRouter* getInstancePtr() { return HK_THREAD_LOCAL_GET(s_memoryRouter); } + + hkMemoryRouter(); + + void resetPeakMemoryStatistics(); + + /// Small thread local allocation in a stack pattern. + inline Stack& stack() { return m_stack; } + + /// Temporary allocation, thread local. Often but not always in a stack pattern. + inline Allocator& temp() { return *m_temp; } + inline void setTemp(Allocator* a) { m_temp = a; } + + /// Allocation which is likely to persist. Not thread local. + inline Allocator& heap() { return *m_heap; } + inline void setHeap(Allocator* a) { m_heap = a; } + + /// Allocation which may break the rules. Not thread local. + inline Allocator& debug() { return *m_debug; } + inline void setDebug(Allocator* a) { m_debug = a; } + + inline Allocator& solver() { return *m_solver; } + inline void setSolver(Allocator* a) { m_solver = a; } + + inline void* getUserData() const { return m_userData; } + inline void setUserData(void* p) { m_userData = p; } + + inline const hkUint32* getRefObjectLocalStore() const { return &m_refObjLocalStore; } + inline hkUint32* getRefObjectLocalStore() { return &m_refObjLocalStore; } + + static void* alignedAlloc(Allocator& b, int nbytes, int align); + static void alignedFree(Allocator& b, void* p); + + static void* easyAlloc(Allocator& b, int nbytes); + static hk_size_t getEasyAllocSize(Allocator& b, const void* ptr); + static const void* getEasyAllocStartAddress(Allocator& b, const void* ptr); + static void easyFree(Allocator& b, void* p); + +protected: + Stack m_stack; + + Allocator* m_temp; + Allocator* m_heap; + Allocator* m_debug; + Allocator* m_solver; + + void* m_userData; + hkUint32 m_refObjLocalStore; + + static HK_THREAD_LOCAL(hkMemoryRouter*) s_memoryRouter; +}; + +#define HK_DECLARE_CLASS_ALLOCATOR_IMPL(CLASS_TYPE, ALLOCATOR) \ + HK_FORCE_INLINE void* operator new(hk_size_t nbytes) { \ + if constexpr (std::is_base_of_v) { \ + return hkMemoryRouter::getInstance().ALLOCATOR().blockAlloc(static_cast(nbytes)); \ + } else { \ + return hkMemoryRouter::getInstance().ALLOCATOR().blockAlloc(sizeof(CLASS_TYPE)); \ + } \ + } \ + HK_FORCE_INLINE void operator delete(void* p, hk_size_t nbytes) { \ + if constexpr (std::is_base_of_v) { \ + auto* b = static_cast(p); \ + hkMemoryRouter::getInstance().ALLOCATOR().blockFree( \ + p, (b->getMemorySizeAndFlags() == 0xffff) ? static_cast(nbytes) : \ + b->getMemorySizeAndFlags()); \ + } else { \ + hkMemoryRouter::getInstance().ALLOCATOR().blockFree(p, sizeof(CLASS_TYPE)); \ + } \ + } \ + HK_FORCE_INLINE void* operator new(hk_size_t, void* p) { return p; } \ + HK_FORCE_INLINE void* operator new[](hk_size_t, void* p) { return p; } \ + HK_FORCE_INLINE void operator delete(void*, void*) {} \ + HK_FORCE_INLINE void operator delete[](void*, void*) {} + +#define HK_DECLARE_CLASS_ALLOCATOR(CLASS_TYPE) HK_DECLARE_CLASS_ALLOCATOR_IMPL(CLASS_TYPE, heap) + +#define HK_DECLARE_CLASS_DEBUG_ALLOCATOR(CLASS_TYPE) \ + HK_DECLARE_CLASS_ALLOCATOR_IMPL(CLASS_TYPE, debug) diff --git a/lib/hkStubs/Havok/Common/Base/Object/hkBaseObject.h b/lib/hkStubs/Havok/Common/Base/Object/hkBaseObject.h index 072425f7..feb8f474 100644 --- a/lib/hkStubs/Havok/Common/Base/Object/hkBaseObject.h +++ b/lib/hkStubs/Havok/Common/Base/Object/hkBaseObject.h @@ -4,5 +4,6 @@ class hkBaseObject { public: - virtual ~hkBaseObject() {} + virtual ~hkBaseObject() = default; + virtual void __first_virtual_table_function__() {} // NOLINT(bugprone-reserved-identifier) }; diff --git a/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.cpp b/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.cpp new file mode 100644 index 00000000..b67324b2 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.cpp @@ -0,0 +1,9 @@ +#include + +const void* hkReferencedObject::getClassType() const { + return nullptr; +} + +void hkReferencedObject::deleteThisReferencedObject() const { + delete this; +} diff --git a/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.h b/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.h index aacc1c8e..8fbf51c4 100644 --- a/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.h +++ b/lib/hkStubs/Havok/Common/Base/Object/hkReferencedObject.h @@ -1,10 +1,98 @@ #pragma once +#include #include +#include +#include +#include "Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h" class hkReferencedObject : public hkBaseObject { public: - virtual ~hkReferencedObject() {} + inline hkReferencedObject(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + explicit hkReferencedObject(hkFinishLoadedObjectFlag flag) {} + + /// Dummy copy constructor and copy assignment operator. + inline hkReferencedObject(const hkReferencedObject& other); + inline hkReferencedObject& operator=(const hkReferencedObject& other); + + ~hkReferencedObject() override = default; virtual const void* getClassType() const; + + inline int getReferenceCount() const; + inline void setReferenceCount(int newRefCount); + inline void addReference() const; + inline void removeReference() const; + + inline int getAllocatedSize() const; + inline int getMemorySizeAndFlags() const; + inline void setMemorySizeAndFlags(int newMemSizeAndFlags); + inline void setMemorySizeFlagsAndReferenceCount(int newMemSizeAndFlags, int newRefCount); + +protected: + virtual void deleteThisReferencedObject() const; + +private: + mutable hkUint32 m_memSizeAndRefCount; }; + +inline hkReferencedObject::hkReferencedObject() : m_memSizeAndRefCount(0xFFFF0001) {} + +inline hkReferencedObject::hkReferencedObject(const hkReferencedObject& other) + : m_memSizeAndRefCount(0xFFFF0001) {} + +inline hkReferencedObject& hkReferencedObject::operator=(const hkReferencedObject& other) { + return *this; +} + +inline int hkReferencedObject::getReferenceCount() const { + return int(m_memSizeAndRefCount & 0xFFFF); +} + +inline void hkReferencedObject::setReferenceCount(int newRefCount) { + hkAtomic::readModifyWrite(&m_memSizeAndRefCount, [newRefCount](hkUint32 oldVal) { + return (oldVal & 0xFFFF0000) | (newRefCount & 0xFFFF); + }); +} + +inline void hkReferencedObject::addReference() const { + if (getMemorySizeAndFlags() == 0) + return; + + hkAtomic::readModifyWrite(&m_memSizeAndRefCount, [](hkUint32 oldVal) { + return (oldVal & 0xFFFF0000) | (((oldVal & 0xFFFF) + 1) & 0xFFFF); + }); +} + +inline void hkReferencedObject::removeReference() const { + if (getMemorySizeAndFlags() == 0) + return; + + auto newVal = hkAtomic::readModifyWrite(&m_memSizeAndRefCount, [](hkUint32 oldVal) { + return (oldVal & 0xFFFF0000) | (((oldVal & 0xFFFF) - 1) & 0xFFFF); + }); + + if ((newVal & 0xFFFF) == 0) + deleteThisReferencedObject(); +} + +inline int hkReferencedObject::getAllocatedSize() const { + return getMemorySizeAndFlags() & 0x7FFF; +} + +inline int hkReferencedObject::getMemorySizeAndFlags() const { + return int((m_memSizeAndRefCount >> 16) & 0xFFFF); +} + +inline void hkReferencedObject::setMemorySizeAndFlags(int newMemSizeAndFlags) { + hkAtomic::readModifyWrite(&m_memSizeAndRefCount, [=](hkUint32 oldVal) { + return (newMemSizeAndFlags << 16) | (oldVal & 0xFFFF); + }); +} + +inline void hkReferencedObject::setMemorySizeFlagsAndReferenceCount(int newMemSizeAndFlags, + int newRefCount) { + const hkUint32 newVal = (newMemSizeAndFlags << 16) | (newRefCount & 0xFFFF); + hkAtomic::readModifyWrite(&m_memSizeAndRefCount, [=](auto) { return newVal; }); +} diff --git a/lib/hkStubs/Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h b/lib/hkStubs/Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h new file mode 100644 index 00000000..ba81e7c7 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Thread/Atomic/hkAtomicPrimitives.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +namespace hkAtomic { + +/// Weak compare-and-swap. +template +HK_FORCE_INLINE bool compareAndSwap(volatile T* address, const T& oldValue, const T& newValue) { + T expected = oldValue; + return __atomic_compare_exchange_n(address, &expected, newValue, false, __ATOMIC_SEQ_CST, + __ATOMIC_SEQ_CST); +} + +template +HK_FORCE_INLINE T readModifyWrite(volatile T* address, const Fn& getNewValue) { + T oldVal, newVal; + do { + oldVal = *address; + newVal = getNewValue(oldVal); + } while (!hkAtomic::compareAndSwap(address, oldVal, newVal)); + return newVal; +} + +} // namespace hkAtomic diff --git a/lib/hkStubs/Havok/Common/Base/Thread/Thread/hkThreadLocalData.h b/lib/hkStubs/Havok/Common/Base/Thread/Thread/hkThreadLocalData.h new file mode 100644 index 00000000..30dfa527 --- /dev/null +++ b/lib/hkStubs/Havok/Common/Base/Thread/Thread/hkThreadLocalData.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +template +class hkThreadLocalData { +public: + hkThreadLocalData() { nn::os::AllocateTlsSlot(&m_tls_slot, nullptr); } + ~hkThreadLocalData() { nn::os::FreeTlsSlot(m_tls_slot); } + + T getData() const { return reinterpret_cast(nn::os::GetTlsValue(m_tls_slot)); } + void setData(T p) { nn::os::SetTlsValue(m_tls_slot, reinterpret_cast(p)); } + +private: + nn::os::TlsSlot m_tls_slot{}; +}; + +#define HK_THREAD_LOCAL(TYPE) hkThreadLocalData +#define HK_THREAD_LOCAL_SET(var, value) var.setData(value) +#define HK_THREAD_LOCAL_GET(var) var.getData() diff --git a/lib/hkStubs/Havok/Common/Base/Types/hkBaseTypes.h b/lib/hkStubs/Havok/Common/Base/Types/hkBaseTypes.h index 5a7018b8..318cb31c 100644 --- a/lib/hkStubs/Havok/Common/Base/Types/hkBaseTypes.h +++ b/lib/hkStubs/Havok/Common/Base/Types/hkBaseTypes.h @@ -1,20 +1,27 @@ #pragma once +#include +#include + using hkFloat32 = float; using hkDouble64 = double; using hkReal = hkFloat32; -using hkChar = signed char; -using hkInt8 = signed char; -using hkInt16 = signed short; -using hkInt32 = signed int; +using hkChar = char; +using hkInt8 = std::int8_t; +using hkInt16 = std::int16_t; +using hkInt32 = std::int32_t; +using hkInt64 = std::int64_t; using hkUchar = unsigned char; -using hkUint8 = unsigned char; -using hkUint16 = unsigned short; -using hkUint32 = unsigned int; +using hkUint8 = std::uint8_t; +using hkUint16 = std::uint16_t; +using hkUint32 = std::uint32_t; +using hkUint64 = std::uint64_t; +using hk_size_t = hkUint64; +using hkLong = long; +using hkUlong = unsigned long; -using hkUint64 = unsigned long long; using m128 = __attribute((vector_size(16))) float; class hkHalf { @@ -118,3 +125,36 @@ public: private: Storage m_storage; }; + +enum hkResultEnum { + HK_SUCCESS = 0, + HK_FAILURE = 1, +}; + +struct hkResult { + HK_FORCE_INLINE hkResult() {} + HK_FORCE_INLINE hkResult(hkResultEnum b) { m_enum = b; } + + HK_FORCE_INLINE hkResult& operator=(hkResultEnum e) { + m_enum = e; + return *this; + } + + HK_FORCE_INLINE bool operator==(hkResultEnum e) const { return m_enum == e; } + HK_FORCE_INLINE bool operator!=(hkResultEnum e) const { return m_enum != e; } + + HK_FORCE_INLINE bool isSuccess() const { return m_enum ^ HK_FAILURE; } + + hkResultEnum m_enum; +}; + +inline bool operator==(hkResultEnum e, hkResult r) { + return r.m_enum == e; +} +inline bool operator!=(hkResultEnum e, hkResult r) { + return r.m_enum != e; +} + +struct hkFinishLoadedObjectFlag { + int m_finishing = 0; +}; diff --git a/lib/hkStubs/Havok/Common/Base/hkBase.h b/lib/hkStubs/Havok/Common/Base/hkBase.h index c79c768a..47c37691 100644 --- a/lib/hkStubs/Havok/Common/Base/hkBase.h +++ b/lib/hkStubs/Havok/Common/Base/hkBase.h @@ -7,4 +7,6 @@ #include +#include + #include diff --git a/lib/sead b/lib/sead index bc92bd8d..ca3982b3 160000 --- a/lib/sead +++ b/lib/sead @@ -1 +1 @@ -Subproject commit bc92bd8d9adb6791feef492643ddaf08b99985eb +Subproject commit ca3982b344be82ac3578f545c64403ae41589117