32 Bit Support
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 19 Sep 2024 15:23:19 +0000 (16:23 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Thu, 19 Sep 2024 15:23:19 +0000 (16:23 +0100)
12 files changed:
CMakeLists.txt
pxr/base/arch/assumptions.cpp
pxr/base/arch/defines.h
pxr/base/arch/timing.cpp
pxr/base/arch/timing.h
pxr/base/tf/mallocTag.cpp
pxr/base/tf/pointerAndBits.h
pxr/base/tf/smallVector.cpp
pxr/usd/ndr/declare.h
pxr/usd/sdf/path.h
pxr/usd/sdf/pathNode.cpp
pxr/usd/usd/primData.cpp

index e9fd6d3a68fabae463cb3d3703aea0dcc23f6fb1..6f09e6ca01ee530a9893ea61c33adefaf29a598f 100644 (file)
@@ -2,17 +2,6 @@ cmake_minimum_required(VERSION 3.14)
 
 project(usd)
 
-if (NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
-    if (WIN32)
-        message(FATAL_ERROR "Compiler does not support 64-bit builds. "
-                "If you are using Visual Studio, make sure you are in the "
-                "x64 command prompt and have specified the Win64 cmake "
-                "generator (e.g., -G \"Visual Studio 15 2017 Win64\")")
-    else()
-        message(FATAL_ERROR "Compiler does not support 64-bit builds.")
-    endif()
-endif()
-
 list(APPEND CMAKE_MODULE_PATH
     ${PROJECT_SOURCE_DIR}/cmake/defaults
     ${PROJECT_SOURCE_DIR}/cmake/modules
index 3952f136ca667759258a1b365ab399c216831939..480e962fc5bd4d5c45e6c6a0054cc19b70d186e9 100644 (file)
@@ -51,7 +51,11 @@ static size_t
 Arch_ObtainCacheLineSize()
 {
 #if defined(ARCH_OS_LINUX)
+#if defined(ARCH_BITS_64)
     return sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
+#else
+    return 64;
+#endif
 #elif defined(ARCH_OS_DARWIN)
     size_t cacheLineSize = 0;
     size_t cacheLineSizeSize = sizeof(cacheLineSize);
index cb6ad44c5b1847a53bc32d91a39cf364ba01e97d..169cb3e579f3d1441de2b6f4c90e59ee268dcbaa 100644 (file)
@@ -60,7 +60,7 @@
 #if defined(__x86_64__) || defined(__aarch64__) || defined(_M_X64)
 #define ARCH_BITS_64
 #else
-#error "Unsupported architecture.  x86_64 or ARM64 required."
+#define ARCH_BITS_32
 #endif
 
 //
index 99ce4ce974b5a743b06d65c0868e3f6841f19813..4e4d82d65020b294109597aa1b169bb24196a2b9 100644 (file)
@@ -112,7 +112,7 @@ static
 double
 Arch_ComputeNanosecondsPerTick()
 {
-#if defined(ARCH_CPU_ARM)
+#if defined(ARCH_CPU_ARM) && defined(ARCH_BITS_64)
     uint64_t counter_hz;
     __asm __volatile("mrs      %0, CNTFRQ_EL0" : "=&r" (counter_hz));
     Arch_NanosecondsPerTick = double(1e9) / double(counter_hz);
index 88bdb15524fa13ba8578d09a1e219ebf0c1d77c6..4160d22e9a465e1b6dcf6a76e80ce09320dae580 100644 (file)
 #include <iterator>
 #include <numeric>
 
+#ifdef ARCH_BITS_32
+#include <chrono>
+#include <thread>
+#endif // ARCH_BITS_32
+
 PXR_NAMESPACE_OPEN_SCOPE
 
 /// Return the current time in system-dependent units.
@@ -68,9 +73,15 @@ ArchGetTickTime()
     // On Intel we'll use the rdtsc instruction.
     return __rdtsc();
 #elif defined (ARCH_CPU_ARM)
+#ifdef ARCH_BITS_64
     uint64_t result;
     __asm __volatile("mrs      %0, CNTVCT_EL0" : "=&r" (result));
     return result;
+#else
+    auto epoch = std::chrono::steady_clock::now().time_since_epoch();
+       auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(epoch);
+    return static_cast<uint64_t>(duration.count());
+#endif // ARCH_BITS_64s
 #else
 #error Unknown architecture.
 #endif
@@ -85,7 +96,7 @@ inline uint64_t
 ArchGetStartTickTime()
 {
     uint64_t t;
-#if defined (ARCH_OS_DARWIN)
+#if defined (ARCH_OS_DARWIN) || defined (ARCH_BITS_32)
     return ArchGetTickTime();
 #elif defined (ARCH_CPU_ARM)
     std::atomic_signal_fence(std::memory_order_seq_cst);
@@ -126,7 +137,7 @@ inline uint64_t
 ArchGetStopTickTime()
 {
     uint64_t t;
-#if defined (ARCH_OS_DARWIN)
+#if defined (ARCH_OS_DARWIN) || defined (ARCH_BITS_32)
     return ArchGetTickTime();
 #elif defined (ARCH_CPU_ARM)
     std::atomic_signal_fence(std::memory_order_seq_cst);
index 3fd235e9abff2aaebd3a22ffaefb634a65410136..ee466c7d7604c074edf28421d8e3f6c6c523c80e 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "pxr/base/arch/attributes.h"
 #include "pxr/base/arch/debugger.h"
+#include "pxr/base/arch/defines.h"
 #include "pxr/base/arch/hash.h"
 #include "pxr/base/arch/inttypes.h"
 #include "pxr/base/arch/mallocHook.h"
@@ -129,8 +130,13 @@ struct Tf_MallocBlockInfo {
 };
 
 #if !defined(ARCH_OS_WINDOWS)
+#ifdef ARCH_BITS_64
 static_assert(sizeof(Tf_MallocBlockInfo) == 16, 
               "Unexpected size for Tf_MallocBlockInfo");
+#else
+static_assert(sizeof(Tf_MallocBlockInfo) == 8,
+              "Unexpected size for Tf_MallocBlockInfo");
+#endif // ARCH_BITS_64
 #endif
 
 /*
index 180213d01aa08479b0ababc93d7f7175277854e5..dc095e3785bfdffd2b3a7047c3ea1b5fc8e17551 100644 (file)
 
 #include "pxr/pxr.h"
 #include "pxr/base/arch/pragmas.h"
+#include "pxr/base/arch/defines.h"
 
 #include <cstdint>
 #include <type_traits>
+#include <limits>
 #include <utility>
 
 PXR_NAMESPACE_OPEN_SCOPE
 
+#ifdef ARCH_BITS_32
+// If we are on a 32 bit architecture, we just store 32bits and a pointer with 32 bits
+// Taken from: https://github.com/autodesk-forks/USD/blob/adsk/collab/port-python-wasm/pxr/base/tf/pointerAndBits.h
+/// \class TfPointerAndBits
+///
+/// This class stores a T * and a small integer in the space of a T *. The
+/// number of bits possible to store depends on the alignment of T.  The
+/// number of distinct values representable by the bits and the maximal value
+/// are exposed via the compile time constants \a NumBitsValues and \a
+/// MaxValue, respectively.
+///
+/// The bits may be set and retrieved as any integral type.  The pointer value
+/// and the bits value may be set and retrieved independently.
+///
+template <class T>
+class TfPointerAndBits
+{
+public:
+    /// Constructor.  Pointer is initialized to null, bits are initialized to
+    /// zero.
+    constexpr TfPointerAndBits() noexcept : _ptr(0), _bits(0) {
+    }
+
+    /// Constructor.  Set the pointer to \a p, and the bits to \a bits.
+    constexpr explicit TfPointerAndBits(T *p, uintptr_t bits = 0) noexcept
+        : _ptr(p), _bits(bits)
+    {
+    }
+
+    constexpr uintptr_t GetMaxValue() const {
+        return std::numeric_limits<uint32_t>::max();
+    }
+
+    constexpr uintptr_t GetNumBitsValues() const {
+        return 32;
+    }
+
+    /// Assignment.  Leaves bits unmodified.
+    TfPointerAndBits &operator=(T *ptr) noexcept {
+        _SetPtr(ptr);
+        return *this;
+    }
+
+    /// Indirection.
+    constexpr T *operator->() const noexcept {
+        return _GetPtr();
+    }
+
+    /// Dereference.
+    constexpr T &operator *() const noexcept {
+        return *_GetPtr();
+    }
+
+    /// Retrieve the stored bits as the integral type \a Integral.
+    template <class Integral>
+    constexpr Integral BitsAs() const noexcept {
+        return static_cast<Integral>(_bits);
+    }
+
+    /// Set the stored bits.  No static range checking is performed.
+    template <class Integral>
+    void SetBits(Integral val) noexcept {
+        _SetBits(static_cast<int32_t>(val));
+    }
+
+    /// Set the pointer value to \a ptr.
+    void Set(T *ptr) noexcept {
+        _SetPtr(ptr);
+    }
+
+    /// Set the pointer value to \a ptr and the bits to \a val.
+    template <class Integral>
+    void Set(T *ptr, Integral val) noexcept {
+        _ptr = ptr;
+        _bits = static_cast<int32_t>(val);
+    }
+
+    /// Retrieve the pointer.
+    constexpr T *Get() const noexcept {
+        return _GetPtr();
+    }
+
+    /// Retrieve the raw underlying value.  This can be useful for doing literal
+    /// equality checks between two instances.  The only guarantees are that
+    /// this has the same bit pattern as the pointer value if the bits are 0,
+    /// and will compare equal to another instance when both have identical
+    /// pointer and bits values.
+    constexpr uintptr_t GetLiteral() const noexcept {
+        return (static_cast<uint64_t>(_bits) << 32) | reinterpret_cast<uint64_t>(_ptr);
+    }
+
+    /// Swap this PointerAndBits with \a other.
+    void Swap(TfPointerAndBits &other) noexcept {
+        ::std::swap(_ptr, other._ptr);
+        ::std::swap(_bits, other._bits);
+    }
+
+private:
+    constexpr uintptr_t _GetBitMask() const noexcept {
+        return GetMaxValue();
+    }
+
+    // Retrieve the held pointer value.
+    constexpr T *_GetPtr() const noexcept {
+        return _ptr;
+    }
+
+    // Set the held pointer value.
+    void _SetPtr(T *p) noexcept {
+        _ptr = p;
+    }
+
+    // Retrieve the held bits value.
+    constexpr uint32_t _GetBits() const noexcept {
+        return _bits;
+    }
+
+    // Set the held bits value.
+    void _SetBits(uint32_t bits) noexcept {
+        _bits = bits;
+    }
+
+    // Single pointer member stores pointer value and bits.
+    T *_ptr;
+    uint32_t _bits;
+};
+#else
 // Return true if \p val is a power of two.
 constexpr bool Tf_IsPow2(uintptr_t val) {
     return val && !(val & (val - 1));
@@ -207,6 +336,7 @@ private:
     // Single pointer member stores pointer value and bits.
     T *_ptrAndBits;
 };
+#endif
 
 PXR_NAMESPACE_CLOSE_SCOPE
 
index 3b4010bbe69d0e7843b9942fb27385f856bbe04d..3931f1f09534b352526ffad424fce2eaa410b188 100644 (file)
 //
 #include "pxr/pxr.h"
 #include "pxr/base/tf/smallVector.h"
+#include "pxr/base/arch/defines.h"
 
 PXR_NAMESPACE_OPEN_SCOPE
 
+#ifndef ARCH_BITS_32
 static_assert(
     sizeof(TfSmallVector<int, 1>) == 16, 
     "Expecting sizeof(TfSmallVector<int, N = 1>) to be 16 bytes.");
+#else
+static_assert(
+    sizeof(TfSmallVector<int, 1>) == 12,
+    "Expecting sizeof(TfSmallVector<int, N = 1>) to be 12 bytes.");
+#endif
 
 static_assert(
     sizeof(TfSmallVector<int, 2>) == 16, 
@@ -42,8 +49,14 @@ static_assert(
     sizeof(TfSmallVector<double, 2>) == 24, 
     "Expecting sizeof(TfSmallVector<double, N = 2>) to be 24 bytes.");
 
+#ifndef ARCH_BITS_32
 static_assert(
     TfSmallVectorBase::ComputeSerendipitousLocalCapacity<char>() == 8,
     "Expecting 8 bytes of local capacity.");
+#else
+static_assert(
+    TfSmallVectorBase::ComputeSerendipitousLocalCapacity<char>() == 4,
+    "Expecting 4 bytes of local capacity.");
+#endif
 
 PXR_NAMESPACE_CLOSE_SCOPE
index cbb6aeb4e32e2d25af87e323e808092c92815c62..654f129b2927f2f76e8ddeb64ae053053aac3703 100644 (file)
@@ -30,6 +30,7 @@
 #include "pxr/pxr.h"
 #include "pxr/usd/ndr/api.h"
 #include "pxr/base/tf/token.h"
+#include "pxr/base/arch/defines.h"
 
 #include <memory>
 #include <string>
 #include <unordered_set>
 #include <vector>
 
+#ifdef ARCH_BITS_32
+#include <boost/functional/hash.hpp>
+#endif // ARCH_BITS_32
+
 PXR_NAMESPACE_OPEN_SCOPE
 
 class NdrNode;
@@ -128,8 +133,15 @@ public:
     NDR_API
     std::size_t GetHash() const
     {
-        return (static_cast<std::size_t>(_major) << 32) +
-                static_cast<std::size_t>(_minor);
+        #ifdef ARCH_BITS_32
+            size_t h = 0;
+            boost::hash_combine(h, _major);
+            boost::hash_combine(h, _minor);
+            return h;
+        #else
+            return (static_cast<std::size_t>(_major) << 32) +
+                    static_cast<std::size_t>(_minor);
+        #endif // ARCH_BITS_32
     }
 
     /// Return true iff the version is valid.
index 62d414cd2d438b00280131717294552cf85d5d33..dce767417cf1e67d49cd1657ea6497df12e86d03 100644 (file)
@@ -63,8 +63,8 @@ struct Sdf_PathPrimTag;
 struct Sdf_PathPropTag;
 
 // These are validated below.
-static constexpr size_t Sdf_SizeofPrimPathNode = sizeof(void *) * 3;
-static constexpr size_t Sdf_SizeofPropPathNode = sizeof(void *) * 3;
+static constexpr size_t Sdf_SizeofPrimPathNode = sizeof(TfToken) + 2 * sizeof(unsigned int) + sizeof(void*);
+static constexpr size_t Sdf_SizeofPropPathNode = sizeof(TfToken) + 2 * sizeof(unsigned int) + sizeof(void*);
 
 using Sdf_PathPrimPartPool = Sdf_Pool<
     Sdf_PathPrimTag, Sdf_SizeofPrimPathNode, /*regionBits=*/8>;
index defaf35f3e01fc7c27964b0c1f88cc8fd457895d..8f10ceb7a5d62b4a6d29d0b686fb311f0d5c27d8 100644 (file)
@@ -55,8 +55,8 @@ SDF_INSTANTIATE_POOL(Sdf_PathPropTag, Sdf_SizeofPropPathNode, /*regionBits=*/8);
 
 // Size of path nodes is important, so we want the compiler to tell us if it
 // changes.
-static_assert(sizeof(Sdf_PrimPathNode) == 3 * sizeof(void *), "");
-static_assert(sizeof(Sdf_PrimPropertyPathNode) == 3 * sizeof(void *), "");
+static_assert(sizeof(Sdf_PrimPathNode) == sizeof(TfToken) + 2 * sizeof(unsigned int) + sizeof(void*), "");
+static_assert(sizeof(Sdf_PrimPropertyPathNode) == sizeof(TfToken) + 2 * sizeof(unsigned int) + sizeof(void*), "");
 
 struct Sdf_PathNodePrivateAccess
 {
index e1ce385b9f30a760a8472ace73362647290bf41b..dcf4d36af88627ffa135bda02225ea45015071b1 100644 (file)
@@ -37,6 +37,8 @@
 #include "pxr/base/tf/exception.h"
 #include "pxr/base/tf/stringUtils.h"
 
+#include "pxr/base/arch/defines.h"
+
 #include <algorithm>
 #include <sstream>
 #include <vector>
@@ -45,8 +47,13 @@ PXR_NAMESPACE_OPEN_SCOPE
 
 // Static assertion on PrimData size.  We want to be warned when its size
 // changes.
+#ifndef ARCH_BITS_32
 static_assert(sizeof(Usd_PrimData) == 64,
               "Expected sizeof(Usd_PrimData) == 64");
+#else
+static_assert(sizeof(Usd_PrimData) == 48,
+              "Expected sizeof(Usd_PrimData) == 48");
+#endif
 
 // Usd_PrimData need to be always initialized with a valid type info pointer
 static const UsdPrimTypeInfo *_GetEmptyPrimTypeInfo()