mirror of
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
synced 2024-11-05 12:20:07 +00:00
619 lines
22 KiB
C
619 lines
22 KiB
C
|
/*
|
||
|
* Copyright 2014 Google Inc. All rights reserved.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
#ifndef MATHFU_UTILITIES_H_
|
||
|
#define MATHFU_UTILITIES_H_
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <math.h>
|
||
|
#include <stdint.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <algorithm>
|
||
|
#include <memory>
|
||
|
|
||
|
/// @file mathfu/utilities.h Utilities
|
||
|
/// @brief Utility macros and functions.
|
||
|
|
||
|
/// @addtogroup mathfu_build_config
|
||
|
///
|
||
|
/// By default MathFu will attempt to build with SIMD optimizations enabled
|
||
|
/// based upon the target architecture and compiler options. However, it's
|
||
|
/// possible to change the default build configuration using the following
|
||
|
/// macros:
|
||
|
///
|
||
|
/// @li @ref MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT
|
||
|
/// @li @ref MATHFU_COMPILE_FORCE_PADDING
|
||
|
///
|
||
|
/// <table>
|
||
|
/// <tr>
|
||
|
/// <th>MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT</th>
|
||
|
/// <th>MATHFU_COMPILE_FORCE_PADDING</th>
|
||
|
/// <th>Configuration</th>
|
||
|
/// </tr>
|
||
|
/// <tr>
|
||
|
/// <td><em>undefined</em></td>
|
||
|
/// <td><em>undefined</em> or 1</td>
|
||
|
/// <td>Default build configuration, SIMD optimization is enabled based upon
|
||
|
/// the target architecture, compiler options and MathFu library
|
||
|
/// support.</td>
|
||
|
/// </tr>
|
||
|
/// <tr>
|
||
|
/// <td><em>undefined</em></td>
|
||
|
/// <td>0</td>
|
||
|
/// <td>If SIMD is supported, padding of data structures is disabled. See
|
||
|
/// @ref MATHFU_COMPILE_FORCE_PADDING for more information.</td>
|
||
|
/// </tr>
|
||
|
/// <tr>
|
||
|
/// <td><em>defined</em></td>
|
||
|
/// <td><em>undefined/0/1</em></td>
|
||
|
/// <td>Builds MathFu with explicit SIMD optimization disabled. The compiler
|
||
|
/// could still potentially optimize some code paths with SIMD
|
||
|
/// instructions based upon the compiler options.</td>
|
||
|
/// </tr>
|
||
|
/// </table>
|
||
|
|
||
|
#ifdef DOXYGEN
|
||
|
/// @addtogroup mathfu_build_config
|
||
|
/// @{
|
||
|
/// @def MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT
|
||
|
/// @brief Disable SIMD build configuration.
|
||
|
///
|
||
|
/// When defined, this macro <b>disables</b> the default behavior of trying to
|
||
|
/// build the library with SIMD enabled based upon the target architecture
|
||
|
/// and compiler options.
|
||
|
///
|
||
|
/// To use this build option, this macro <b>must</b> be defined in all modules
|
||
|
/// of the project.
|
||
|
#define MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT
|
||
|
/// @}
|
||
|
#endif // DOXYGEN
|
||
|
#if !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT)
|
||
|
#if defined(__SSE__)
|
||
|
#define MATHFU_COMPILE_WITH_SIMD
|
||
|
#elif defined(__ARM_NEON__)
|
||
|
#define MATHFU_COMPILE_WITH_SIMD
|
||
|
#elif defined(_M_IX86_FP) // MSVC
|
||
|
#if _M_IX86_FP >= 1 // SSE enabled
|
||
|
#define MATHFU_COMPILE_WITH_SIMD
|
||
|
#endif // _M_IX86_FP >= 1
|
||
|
#endif
|
||
|
#endif // !defined(MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT)
|
||
|
|
||
|
#ifdef DOXYGEN
|
||
|
/// @addtogroup mathfu_build_config
|
||
|
/// @{
|
||
|
/// @def MATHFU_COMPILE_FORCE_PADDING
|
||
|
/// @brief Enable / disable padding of data structures.
|
||
|
///
|
||
|
/// By default, when @ref MATHFU_COMPILE_FORCE_PADDING is <b>not</b> defined,
|
||
|
/// data structures are padded when SIMD is enabled
|
||
|
/// (i.e when @ref MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT is also not defined).
|
||
|
///
|
||
|
/// If @ref MATHFU_COMPILE_FORCE_PADDING is defined as <b>1</b>, all data
|
||
|
/// structures are padded to a power of 2 size which enables more efficient
|
||
|
/// SIMD operations. This is the default build configuration when SIMD is
|
||
|
/// enabled.
|
||
|
///
|
||
|
/// If @ref MATHFU_COMPILE_FORCE_PADDING is defined as <b>0</b>, all data
|
||
|
/// structures are packed by the compiler (with no padding) even when the SIMD
|
||
|
/// build configuration is enabled. This build option can be useful in the
|
||
|
/// rare occasion an application is CPU memory bandwidth constrained, at the
|
||
|
/// expense of additional instructions to copy to / from SIMD registers.
|
||
|
///
|
||
|
/// To use this build option, this macro <b>must</b> be defined in all modules
|
||
|
/// of the project.
|
||
|
///
|
||
|
/// @see MATHFU_COMPILE_WITHOUT_SIMD_SUPPORT
|
||
|
#define MATHFU_COMPILE_FORCE_PADDING
|
||
|
/// @}
|
||
|
#endif // DOXYGEN
|
||
|
|
||
|
#ifdef MATHFU_COMPILE_WITH_SIMD
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
/// @addtogroup mathfu_build_config
|
||
|
/// @{
|
||
|
/// @def MATHFU_COMPILE_WITH_PADDING
|
||
|
/// @brief Enable padding of data structures to be efficient with SIMD.
|
||
|
///
|
||
|
/// When defined, this option enables padding of some data structures (e.g
|
||
|
/// @ref vec3) to be more efficient with SIMD operations. This option is
|
||
|
/// only applicable when @ref MATHFU_COMPILE_WITHOUT_SIMD is not defined and
|
||
|
/// the target architecture and compiler support SIMD.
|
||
|
///
|
||
|
/// To use this build option, this macro <b>must</b> be defined in all modules
|
||
|
/// of the project.
|
||
|
/// @see MATHFU_COMPILE_FORCE_PADDING
|
||
|
#define MATHFU_COMPILE_WITH_PADDING
|
||
|
/// @}
|
||
|
#if defined(MATHFU_COMPILE_FORCE_PADDING)
|
||
|
#if MATHFU_COMPILE_FORCE_PADDING == 1
|
||
|
#if !defined(MATHFU_COMPILE_WITH_PADDING)
|
||
|
#define MATHFU_COMPILE_WITH_PADDING
|
||
|
#endif // !defined(MATHFU_COMPILE_WITH_PADDING)
|
||
|
#else
|
||
|
#if defined(MATHFU_COMPILE_WITH_PADDING)
|
||
|
#undef MATHFU_COMPILE_WITH_PADDING
|
||
|
#endif // MATHFU_COMPILE_WITH_PADDING
|
||
|
#endif // MATHFU_COMPILE_FORCE_PADDING == 1
|
||
|
#endif // MATHFU_COMPILE_FORCE_PADDING
|
||
|
/// @endcond
|
||
|
#endif // MATHFU_COMPILE_WITH_SIMD
|
||
|
|
||
|
/// @addtogroup mathfu_version
|
||
|
/// @{
|
||
|
|
||
|
/// @def MATHFU_VERSION_MAJOR
|
||
|
/// @brief Major version number of the library.
|
||
|
/// @see kMathFuVersionString
|
||
|
#define MATHFU_VERSION_MAJOR 1
|
||
|
/// @def MATHFU_VERSION_MINOR
|
||
|
/// @brief Minor version number of the library.
|
||
|
/// @see kMathFuVersionString
|
||
|
#define MATHFU_VERSION_MINOR 1
|
||
|
/// @def MATHFU_VERSION_REVISION
|
||
|
/// @brief Revision number of the library.
|
||
|
/// @see kMathFuVersionString
|
||
|
#define MATHFU_VERSION_REVISION 0
|
||
|
|
||
|
/// @}
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
#define MATHFU_STRING_EXPAND(X) #X
|
||
|
#define MATHFU_STRING(X) MATHFU_STRING_EXPAND(X)
|
||
|
/// @endcond
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
// Generate string which contains build options for the library.
|
||
|
#if defined(MATHFU_COMPILE_WITH_SIMD)
|
||
|
#define MATHFU_BUILD_OPTIONS_SIMD "[simd]"
|
||
|
#else
|
||
|
#define MATHFU_BUILD_OPTIONS_SIMD "[no simd]"
|
||
|
#endif // defined(MATHFU_COMPILE_WITH_SIMD)
|
||
|
#if defined(MATHFU_COMPILE_WITH_PADDING)
|
||
|
#define MATHFU_BUILD_OPTIONS_PADDING "[padding]"
|
||
|
#else
|
||
|
#define MATHFU_BUILD_OPTIONS_PADDING "[no padding]"
|
||
|
#endif // defined(MATHFU_COMPILE_WITH_PADDING)
|
||
|
/// @endcond
|
||
|
|
||
|
/// @addtogroup mathfu_version
|
||
|
/// @{
|
||
|
/// @def MATHFU_BUILD_OPTIONS_STRING
|
||
|
/// @brief String that describes the library's build configuration.
|
||
|
#define MATHFU_BUILD_OPTIONS_STRING \
|
||
|
(MATHFU_BUILD_OPTIONS_SIMD " " MATHFU_BUILD_OPTIONS_PADDING)
|
||
|
/// @}
|
||
|
|
||
|
// Weak linkage is culled by VS & doesn't work on cygwin.
|
||
|
#if !defined(_WIN32) && !defined(__CYGWIN__)
|
||
|
|
||
|
extern volatile __attribute__((weak)) const char *kMathFuVersionString;
|
||
|
/// @addtogroup mathfu_version
|
||
|
/// @{
|
||
|
|
||
|
/// @var kMathFuVersionString
|
||
|
/// @brief String which identifies the current version of MathFu.
|
||
|
///
|
||
|
/// @ref kMathFuVersionString is used by Google developers to identify which
|
||
|
/// applications uploaded to Google Play are using this library. This allows
|
||
|
/// the development team at Google to determine the popularity of the library.
|
||
|
/// How it works: Applications that are uploaded to the Google Play Store are
|
||
|
/// scanned for this version string. We track which applications are using it
|
||
|
/// to measure popularity. You are free to remove it (of course) but we would
|
||
|
/// appreciate if you left it in.
|
||
|
///
|
||
|
/// @see MATHFU_VERSION_MAJOR
|
||
|
/// @see MATHFU_VERSION_MINOR
|
||
|
/// @see MATHFU_VERSION_REVISION
|
||
|
volatile __attribute__((weak)) const char *kMathFuVersionString =
|
||
|
"MathFu " MATHFU_STRING(MATHFU_VERSION_MAJOR) "." MATHFU_STRING(
|
||
|
MATHFU_VERSION_MINOR) "." MATHFU_STRING(MATHFU_VERSION_REVISION);
|
||
|
/// @}
|
||
|
|
||
|
#endif // !defined(_WIN32) && !defined(__CYGWIN__)
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
template <bool>
|
||
|
struct static_assert_util;
|
||
|
template <>
|
||
|
struct static_assert_util<true> {};
|
||
|
/// @endcond
|
||
|
|
||
|
/// @addtogroup mathfu_utilities
|
||
|
/// @{
|
||
|
/// @def MATHFU_STATIC_ASSERT
|
||
|
/// @brief Compile time assert for pre-C++11 compilers.
|
||
|
///
|
||
|
/// For example:
|
||
|
/// <blockquote><code>
|
||
|
/// MATHFU_STATIC_ASSERT(0 == 1);
|
||
|
/// </code></blockquote> will result in a compile error.
|
||
|
#define MATHFU_STATIC_ASSERT(x) static_assert_util<(x)>()
|
||
|
/// @}
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
/// Unroll an loop up to 4 iterations, where iterator is the identifier
|
||
|
/// used in each operation (e.g "i"), number_of_iterations is a constant which
|
||
|
/// specifies the number of times to perform the operation and "operation" is
|
||
|
/// the statement to execute for each iteration of the loop (e.g data[i] = v).
|
||
|
#define MATHFU_UNROLLED_LOOP(iterator, number_of_iterations, operation) \
|
||
|
{ \
|
||
|
const int iterator = 0; \
|
||
|
{ operation; } \
|
||
|
if ((number_of_iterations) > 1) { \
|
||
|
const int iterator = 1; \
|
||
|
{ operation; } \
|
||
|
if ((number_of_iterations) > 2) { \
|
||
|
const int iterator = 2; \
|
||
|
{ operation; } \
|
||
|
if ((number_of_iterations) > 3) { \
|
||
|
const int iterator = 3; \
|
||
|
{ operation; } \
|
||
|
if ((number_of_iterations) > 4) { \
|
||
|
for (int iterator = 4; iterator < (number_of_iterations); \
|
||
|
++iterator) { \
|
||
|
operation; \
|
||
|
} \
|
||
|
} \
|
||
|
} \
|
||
|
} \
|
||
|
} \
|
||
|
}
|
||
|
/// @endcond
|
||
|
|
||
|
namespace mathfu {
|
||
|
|
||
|
/// @addtogroup mathfu_utilities
|
||
|
/// @{
|
||
|
|
||
|
/// @brief Clamp x within [lower, upper].
|
||
|
/// @anchor mathfu_Clamp
|
||
|
///
|
||
|
/// @note Results are undefined if lower > upper.
|
||
|
///
|
||
|
/// @param x Value to clamp.
|
||
|
/// @param lower Lower value of the range.
|
||
|
/// @param upper Upper value of the range.
|
||
|
/// @returns Clamped value.
|
||
|
template <class T>
|
||
|
T Clamp(const T &x, const T &lower, const T &upper) {
|
||
|
return std::max<T>(lower, std::min<T>(x, upper));
|
||
|
}
|
||
|
|
||
|
/// @brief Linearly interpolate between range_start and range_end, based on
|
||
|
/// percent.
|
||
|
/// @anchor mathfu_Lerp
|
||
|
///
|
||
|
/// @param range_start Start of the range.
|
||
|
/// @param range_end End of the range.
|
||
|
/// @param percent Value between 0.0 and 1.0 used to interpolate between
|
||
|
/// range_start and range_end. Where a value of 0.0 results in a return
|
||
|
/// value of range_start and 1.0 results in a return value of range_end.
|
||
|
/// @return Value between range_start and range_end.
|
||
|
///
|
||
|
/// @tparam T Type of the range to interpolate over.
|
||
|
/// @tparam T2 Type of the value used to perform interpolation
|
||
|
/// (e.g float or double).
|
||
|
template <class T, class T2>
|
||
|
T Lerp(const T &range_start, const T &range_end, const T2 &percent) {
|
||
|
const T2 one_minus_percent = static_cast<T2>(1.0) - percent;
|
||
|
return range_start * one_minus_percent + range_end * percent;
|
||
|
}
|
||
|
|
||
|
/// @brief Linearly interpolate between range_start and range_end, based on
|
||
|
/// percent.
|
||
|
/// @anchor mathfu_Lerp2
|
||
|
///
|
||
|
/// @param range_start Start of the range.
|
||
|
/// @param range_end End of the range.
|
||
|
/// @param percent Value between 0.0 and 1.0 used to interpolate between
|
||
|
/// range_start and range_end. Where a value of 0.0 results in a return
|
||
|
/// value of range_start and 1.0 results in a return value of range_end.
|
||
|
/// @return Value between range_start and range_end.
|
||
|
///
|
||
|
/// @tparam T Type of the range to interpolate over.
|
||
|
template <class T>
|
||
|
T Lerp(const T &range_start, const T &range_end, const T &percent) {
|
||
|
return Lerp<T, T>(range_start, range_end, percent);
|
||
|
}
|
||
|
|
||
|
/// @brief Check if val is within [range_start..range_end).
|
||
|
/// @anchor mathfu_InRange
|
||
|
///
|
||
|
/// @param val Value to be tested.
|
||
|
/// @param range_start Starting point of the range (inclusive).
|
||
|
/// @param range_end Ending point of the range (non-inclusive).
|
||
|
/// @return Bool indicating success.
|
||
|
///
|
||
|
/// @tparam T Type of values to test.
|
||
|
template <class T>
|
||
|
bool InRange(T val, T range_start, T range_end) {
|
||
|
return val >= range_start && val < range_end;
|
||
|
}
|
||
|
|
||
|
/// @brief Generate a random value of type T.
|
||
|
/// @anchor mathfu_Random
|
||
|
///
|
||
|
/// This method generates a random value of type T, greater than or equal to
|
||
|
/// 0.0 and less than 1.0.
|
||
|
///
|
||
|
/// This function uses the standard C library function rand() from math.h to
|
||
|
/// generate the random number.
|
||
|
///
|
||
|
/// @returns Random number greater than or equal to 0.0 and less than 1.0.
|
||
|
///
|
||
|
/// @see RandomRange()
|
||
|
/// @see RandomInRange()
|
||
|
template <class T>
|
||
|
inline T Random() {
|
||
|
return static_cast<T>(rand()) / static_cast<T>(RAND_MAX);
|
||
|
}
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
template <>
|
||
|
inline float Random() {
|
||
|
return static_cast<float>(rand() >> 8) /
|
||
|
(static_cast<float>((RAND_MAX >> 8) + 1));
|
||
|
}
|
||
|
/// @endcond
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
template <>
|
||
|
inline double Random() {
|
||
|
return static_cast<double>(rand()) / (static_cast<double>(RAND_MAX + 1LL));
|
||
|
}
|
||
|
/// @endcond
|
||
|
|
||
|
/// @brief Generate a random value of type T in the range -range...+range
|
||
|
/// @anchor mathfu_RandomRange
|
||
|
///
|
||
|
/// This function uses the standard C library function rand() from math.h to
|
||
|
/// generate the random number.
|
||
|
///
|
||
|
/// @param range Range of the random value to generate.
|
||
|
/// @return Random value in the range -range to +range
|
||
|
///
|
||
|
/// @see Random()
|
||
|
template <class T>
|
||
|
inline T RandomRange(T range) {
|
||
|
return (Random<T>() * range * 2) - range;
|
||
|
}
|
||
|
|
||
|
/// @brief Generate a random number between [range_start, range_end]
|
||
|
/// @anchor mathfu_RandomInRange
|
||
|
///
|
||
|
/// This function uses the standard C library function rand() from math.h to
|
||
|
/// generate the random number.
|
||
|
///
|
||
|
/// @param range_start Minimum value.
|
||
|
/// @param range_end Maximum value.
|
||
|
/// @return Random value in the range [range_start, range_end].
|
||
|
///
|
||
|
/// @see Lerp()
|
||
|
/// @see Random()
|
||
|
template <class T>
|
||
|
inline T RandomInRange(T range_start, T range_end) {
|
||
|
return Lerp(range_start, range_end, Random<T>());
|
||
|
}
|
||
|
|
||
|
/// @cond MATHFU_INTERNAL
|
||
|
template <>
|
||
|
inline int RandomInRange<int>(int range_start, int range_end) {
|
||
|
return static_cast<int>(RandomInRange<float>(static_cast<float>(range_start),
|
||
|
static_cast<float>(range_end)));
|
||
|
}
|
||
|
/// @endcond
|
||
|
|
||
|
/// @brief Round a value up to the nearest power of 2.
|
||
|
///
|
||
|
/// @param x Value to round up.
|
||
|
/// @returns Value rounded up to the nearest power of 2.
|
||
|
template <class T>
|
||
|
T RoundUpToPowerOf2(T x) {
|
||
|
return static_cast<T>(
|
||
|
pow(static_cast<T>(2), ceil(log(x) / log(static_cast<T>(2)))));
|
||
|
}
|
||
|
|
||
|
/// @brief Specialized version of RoundUpToPowerOf2 for int32_t.
|
||
|
template <>
|
||
|
inline int32_t RoundUpToPowerOf2<>(int32_t x) {
|
||
|
x--;
|
||
|
x |= x >> 1;
|
||
|
x |= x >> 2;
|
||
|
x |= x >> 4;
|
||
|
x |= x >> 8;
|
||
|
x |= x >> 16;
|
||
|
x++;
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
/// @brief Round a value up to the type's size boundary.
|
||
|
///
|
||
|
/// @param v Value to round up.
|
||
|
/// @returns Value rounded up to the type's size boundary.
|
||
|
template <typename T>
|
||
|
uint32_t RoundUpToTypeBoundary(uint32_t v) {
|
||
|
return (v + sizeof(T) - 1) & ~(sizeof(T) - 1);
|
||
|
}
|
||
|
|
||
|
/// @}
|
||
|
|
||
|
/// @addtogroup mathfu_allocator
|
||
|
///
|
||
|
/// If you use MathFu with SIMD (SSE in particular), you need to have all
|
||
|
/// your allocations be 16-byte aligned (which isn't the case with the default
|
||
|
/// allocators on most platforms except OS X).
|
||
|
///
|
||
|
/// You can either use simd_allocator, which solves the problem for
|
||
|
/// any STL containers, but not for manual dynamic allocations or the
|
||
|
/// new/delete override MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE will
|
||
|
/// solve it for all allocations, at the cost of MATHFU_ALIGNMENT bytes per
|
||
|
/// allocation.
|
||
|
|
||
|
/// @addtogroup mathfu_allocator
|
||
|
/// @{
|
||
|
|
||
|
/// @def MATHFU_ALIGNMENT
|
||
|
/// @brief Alignment (in bytes) of memory allocated by AllocateAligned.
|
||
|
///
|
||
|
/// @see mathfu::AllocateAligned()
|
||
|
/// @see mathfu::simd_allocator
|
||
|
#define MATHFU_ALIGNMENT 16
|
||
|
|
||
|
/// @brief Allocate an aligned block of memory.
|
||
|
/// @anchor mathfu_AllocateAligned
|
||
|
///
|
||
|
/// This function allocates a block of memory aligned to MATHFU_ALIGNMENT
|
||
|
/// bytes.
|
||
|
///
|
||
|
/// @param n Size of memory to allocate.
|
||
|
/// @return Pointer to aligned block of allocated memory or NULL if
|
||
|
/// allocation failed.
|
||
|
inline void *AllocateAligned(size_t n) {
|
||
|
#if defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015
|
||
|
return _aligned_malloc(n, MATHFU_ALIGNMENT);
|
||
|
#else
|
||
|
// We need to allocate extra bytes to guarantee alignment,
|
||
|
// and to store the pointer to the original buffer.
|
||
|
uint8_t *buf = reinterpret_cast<uint8_t *>(malloc(n + MATHFU_ALIGNMENT));
|
||
|
if (!buf) return NULL;
|
||
|
// Align to next higher multiple of MATHFU_ALIGNMENT.
|
||
|
uint8_t *aligned_buf = reinterpret_cast<uint8_t *>(
|
||
|
(reinterpret_cast<size_t>(buf) + MATHFU_ALIGNMENT) &
|
||
|
~(MATHFU_ALIGNMENT - 1));
|
||
|
// Write out original buffer pointer before aligned buffer.
|
||
|
// The assert will fail if the allocator granularity is less than the pointer
|
||
|
// size, or if MATHFU_ALIGNMENT doesn't fit two pointers.
|
||
|
assert(static_cast<size_t>(aligned_buf - buf) > sizeof(void *));
|
||
|
*(reinterpret_cast<uint8_t **>(aligned_buf) - 1) = buf;
|
||
|
return aligned_buf;
|
||
|
#endif // defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015
|
||
|
}
|
||
|
|
||
|
/// @brief Deallocate a block of memory allocated with AllocateAligned().
|
||
|
/// @anchor mathfu_FreeAligned
|
||
|
///
|
||
|
/// @param p Pointer to memory to deallocate.
|
||
|
inline void FreeAligned(void *p) {
|
||
|
#if defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015
|
||
|
_aligned_free(p);
|
||
|
#else
|
||
|
if (p == NULL) return;
|
||
|
free(*(reinterpret_cast<uint8_t **>(p) - 1));
|
||
|
#endif // defined(_MSC_VER) && _MSC_VER >= 1900 // MSVC 2015
|
||
|
}
|
||
|
|
||
|
/// @brief SIMD-safe memory allocator, for use with STL types like std::vector.
|
||
|
///
|
||
|
/// For example:
|
||
|
/// <blockquote><code><pre>
|
||
|
/// std::vector<vec4, mathfu::simd_allocator<vec4>> myvector;
|
||
|
/// </pre></code></blockquote>
|
||
|
///
|
||
|
/// @see MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE
|
||
|
/// @tparam T type allocated by this object.
|
||
|
template <typename T>
|
||
|
class simd_allocator : public std::allocator<T> {
|
||
|
public:
|
||
|
/// Size type.
|
||
|
typedef size_t size_type;
|
||
|
/// Pointer of type T.
|
||
|
typedef T *pointer;
|
||
|
/// Const pointer of type T.
|
||
|
typedef const T *const_pointer;
|
||
|
|
||
|
/// Constructs a simd_allocator.
|
||
|
simd_allocator() throw() : std::allocator<T>() {}
|
||
|
/// @brief Constructs and copies a simd_allocator.
|
||
|
///
|
||
|
/// @param a Allocator to copy.
|
||
|
simd_allocator(const simd_allocator &a) throw() : std::allocator<T>(a) {}
|
||
|
/// @brief Constructs and copies a simd_allocator.
|
||
|
///
|
||
|
/// @param a Allocator to copy.
|
||
|
/// @tparam U type of the object allocated by the allocator to copy.
|
||
|
template <class U>
|
||
|
simd_allocator(const simd_allocator<U> &a) throw() : std::allocator<T>(a) {}
|
||
|
/// @brief Destructs a simd_allocator.
|
||
|
~simd_allocator() throw() {}
|
||
|
|
||
|
/// @brief Obtains an allocator of a different type.
|
||
|
///
|
||
|
/// @tparam _Tp1 type of the new allocator.
|
||
|
template <typename _Tp1>
|
||
|
struct rebind {
|
||
|
/// @brief Allocator of type _Tp1.
|
||
|
typedef simd_allocator<_Tp1> other;
|
||
|
};
|
||
|
|
||
|
/// @brief Allocate memory for object T.
|
||
|
///
|
||
|
/// @param n Number of types to allocate.
|
||
|
/// @return Pointer to the newly allocated memory.
|
||
|
pointer allocate(size_type n) {
|
||
|
return reinterpret_cast<pointer>(AllocateAligned(n * sizeof(T)));
|
||
|
}
|
||
|
|
||
|
/// Deallocate memory referenced by pointer p.
|
||
|
///
|
||
|
/// @param p Pointer to memory to deallocate.
|
||
|
void deallocate(pointer p, size_type) { FreeAligned(p); }
|
||
|
};
|
||
|
|
||
|
#if defined(_MSC_VER)
|
||
|
#if _MSC_VER <= 1800 // MSVC 2013
|
||
|
#if !defined(noexcept)
|
||
|
#define noexcept
|
||
|
#endif // !defined(noexcept)
|
||
|
#endif // _MSC_VER <= 1800
|
||
|
#endif // defined(_MSC_VER)
|
||
|
|
||
|
/// @def MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE
|
||
|
/// @brief Macro which overrides the default new and delete allocators.
|
||
|
///
|
||
|
/// To globally override new and delete, simply add the line:
|
||
|
/// <blockquote><code><pre>
|
||
|
/// MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE
|
||
|
/// </pre></code></blockquote>
|
||
|
/// to the end of your main .cpp file.
|
||
|
#define MATHFU_DEFINE_GLOBAL_SIMD_AWARE_NEW_DELETE \
|
||
|
void *operator new(std::size_t n) { return mathfu::AllocateAligned(n); } \
|
||
|
void *operator new[](std::size_t n) { return mathfu::AllocateAligned(n); } \
|
||
|
void operator delete(void *p) noexcept { mathfu::FreeAligned(p); } \
|
||
|
void operator delete[](void *p) noexcept { mathfu::FreeAligned(p); }
|
||
|
|
||
|
/// @def MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE
|
||
|
/// @brief Macro which defines the new and delete for MathFu classes.
|
||
|
#define MATHFU_DEFINE_CLASS_SIMD_AWARE_NEW_DELETE \
|
||
|
static void *operator new(std::size_t n) { \
|
||
|
return mathfu::AllocateAligned(n); \
|
||
|
} \
|
||
|
static void *operator new[](std::size_t n) { \
|
||
|
return mathfu::AllocateAligned(n); \
|
||
|
} \
|
||
|
static void *operator new(std::size_t /*n*/, void *p) { return p; } \
|
||
|
static void *operator new[](std::size_t /*n*/, void *p) { return p; } \
|
||
|
static void operator delete(void *p) { mathfu::FreeAligned(p); } \
|
||
|
static void operator delete[](void *p) { mathfu::FreeAligned(p); } \
|
||
|
static void operator delete(void * /*p*/, void * /*place*/) {} \
|
||
|
static void operator delete[](void * /*p*/, void * /*place*/) {}
|
||
|
|
||
|
/// @}
|
||
|
|
||
|
} // namespace mathfu
|
||
|
|
||
|
#endif // MATHFU_UTILITIES_H_
|