Added nlz, improved int log2, optimized findMSB with intrinsics
This commit is contained in:
parent
09ee14ad4c
commit
3c2882439f
@ -26,6 +26,11 @@
|
|||||||
/// @author Christophe Riccio
|
/// @author Christophe Riccio
|
||||||
///////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if(GLM_COMPILER & GLM_COMPILER_VC)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse)
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace glm
|
namespace glm
|
||||||
{
|
{
|
||||||
// uaddCarry
|
// uaddCarry
|
||||||
@ -550,6 +555,32 @@ namespace glm
|
|||||||
}
|
}
|
||||||
|
|
||||||
// findMSB
|
// findMSB
|
||||||
|
#if(GLM_COMPILER & GLM_COMPILER_VC)
|
||||||
|
|
||||||
|
template <typename genIUType>
|
||||||
|
GLM_FUNC_QUALIFIER int findMSB
|
||||||
|
(
|
||||||
|
genIUType const & Value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
unsigned long Result(0);
|
||||||
|
_BitScanReverse(&Result, Value);
|
||||||
|
return int(Result);
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif((GLM_COMPILER & GLM_COMPILER_GCC) && __has_builtin(__builtin_clz))
|
||||||
|
|
||||||
|
template <typename genIUType>
|
||||||
|
GLM_FUNC_QUALIFIER int findMSB
|
||||||
|
(
|
||||||
|
genIUType const & Value
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return __builtin_clz(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
template <typename genIUType>
|
template <typename genIUType>
|
||||||
GLM_FUNC_QUALIFIER int findMSB
|
GLM_FUNC_QUALIFIER int findMSB
|
||||||
(
|
(
|
||||||
@ -564,6 +595,7 @@ namespace glm
|
|||||||
for(genIUType tmp = Value; tmp; tmp >>= 1, ++bit){}
|
for(genIUType tmp = Value; tmp; tmp >>= 1, ++bit){}
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
|
#endif//(GLM_COMPILER)
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
GLM_FUNC_QUALIFIER detail::tvec2<int> findMSB
|
GLM_FUNC_QUALIFIER detail::tvec2<int> findMSB
|
||||||
|
@ -58,10 +58,14 @@ namespace glm
|
|||||||
//! From GLM_GTX_integer extension.
|
//! From GLM_GTX_integer extension.
|
||||||
int sqrt(int x);
|
int sqrt(int x);
|
||||||
|
|
||||||
//! Returns the log2 of x.
|
//! Returns the log2 of x. Can be reliably using to compute mipmap count from the texture size.
|
||||||
//! From GLM_GTX_integer extension.
|
//! From GLM_GTX_integer extension.
|
||||||
unsigned int log2(unsigned int x);
|
unsigned int log2(unsigned int x);
|
||||||
|
|
||||||
|
//! Returns the floor log2 of x.
|
||||||
|
//! From GLM_GTX_integer extension.
|
||||||
|
unsigned int floor_log2(unsigned int x);
|
||||||
|
|
||||||
//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
|
//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
|
||||||
//! From GLM_GTX_integer extension.
|
//! From GLM_GTX_integer extension.
|
||||||
int mod(int x, int y);
|
int mod(int x, int y);
|
||||||
@ -72,21 +76,25 @@ namespace glm
|
|||||||
genType factorial(genType const & x);
|
genType factorial(genType const & x);
|
||||||
|
|
||||||
//! 32bit signed integer.
|
//! 32bit signed integer.
|
||||||
//! From GLM_GTX_unsigned_int extension.
|
//! From GLM_GTX_integer extension.
|
||||||
typedef signed int sint;
|
typedef signed int sint;
|
||||||
|
|
||||||
//! Returns x raised to the y power.
|
//! Returns x raised to the y power.
|
||||||
//! From GLM_GTX_unsigned_int extension.
|
//! From GLM_GTX_integer extension.
|
||||||
uint pow(uint x, uint y);
|
uint pow(uint x, uint y);
|
||||||
|
|
||||||
//! Returns the positive square root of x.
|
//! Returns the positive square root of x.
|
||||||
//! From GLM_GTX_unsigned_int extension.
|
//! From GLM_GTX_integer extension.
|
||||||
uint sqrt(uint x);
|
uint sqrt(uint x);
|
||||||
|
|
||||||
//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
|
//! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
|
||||||
//! From GLM_GTX_unsigned_int extension.
|
//! From GLM_GTX_integer extension.
|
||||||
uint mod(uint x, uint y);
|
uint mod(uint x, uint y);
|
||||||
|
|
||||||
|
//! Returns the number of leading zeros.
|
||||||
|
//! From GLM_GTX_integer extension.
|
||||||
|
uint nlz(uint x);
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
}//namespace glm
|
}//namespace glm
|
||||||
|
|
||||||
|
@ -54,10 +54,18 @@ namespace detail
|
|||||||
return(x & 0x0000003f);
|
return(x & 0x0000003f);
|
||||||
}
|
}
|
||||||
}//namespace detail
|
}//namespace detail
|
||||||
/*
|
|
||||||
// Henry Gordon Dietz: http://aggregate.org/MAGIC/
|
|
||||||
GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x)
|
GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x)
|
||||||
{
|
{
|
||||||
|
return unsigned(32) - nlz(x - 1u);
|
||||||
|
//if(x <= 1)
|
||||||
|
// return 0;
|
||||||
|
//return unsigned(32) - findLSB(x) - 1u;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Henry Gordon Dietz: http://aggregate.org/MAGIC/
|
||||||
|
|
||||||
register int y = (x & (x - 1));
|
register int y = (x & (x - 1));
|
||||||
|
|
||||||
y |= -y;
|
y |= -y;
|
||||||
@ -69,10 +77,11 @@ GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x)
|
|||||||
x |= (x >> 16);
|
x |= (x >> 16);
|
||||||
|
|
||||||
return detail::ones32(x) - 1 - y;
|
return detail::ones32(x) - 1 - y;
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// Henry Gordon Dietz: http://aggregate.org/MAGIC/
|
// Henry Gordon Dietz: http://aggregate.org/MAGIC/
|
||||||
unsigned int log2(unsigned int x)
|
unsigned int floor_log2(unsigned int x)
|
||||||
{
|
{
|
||||||
x |= (x >> 1);
|
x |= (x >> 1);
|
||||||
x |= (x >> 2);
|
x |= (x >> 2);
|
||||||
@ -159,4 +168,45 @@ GLM_FUNC_QUALIFIER uint mod(uint x, uint y)
|
|||||||
return x - y * (x / y);
|
return x - y * (x / y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC))
|
||||||
|
|
||||||
|
GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x)
|
||||||
|
{
|
||||||
|
return 32u - findMSB(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt
|
||||||
|
GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x)
|
||||||
|
{
|
||||||
|
int y, m, n;
|
||||||
|
|
||||||
|
y = -int(x >> 16); // If left half of x is 0,
|
||||||
|
m = (y >> 16) & 16; // set n = 16. If left half
|
||||||
|
n = 16 - m; // is nonzero, set n = 0 and
|
||||||
|
x = x >> m; // shift x right 16.
|
||||||
|
// Now x is of the form 0000xxxx.
|
||||||
|
y = x - 0x100; // If positions 8-15 are 0,
|
||||||
|
m = (y >> 16) & 8; // add 8 to n and shift x left 8.
|
||||||
|
n = n + m;
|
||||||
|
x = x << m;
|
||||||
|
|
||||||
|
y = x - 0x1000; // If positions 12-15 are 0,
|
||||||
|
m = (y >> 16) & 4; // add 4 to n and shift x left 4.
|
||||||
|
n = n + m;
|
||||||
|
x = x << m;
|
||||||
|
|
||||||
|
y = x - 0x4000; // If positions 14-15 are 0,
|
||||||
|
m = (y >> 16) & 2; // add 2 to n and shift x left 2.
|
||||||
|
n = n + m;
|
||||||
|
x = x << m;
|
||||||
|
|
||||||
|
y = x >> 14; // Set y = 0, 1, 2, or 3.
|
||||||
|
m = y & ~(y >> 1); // Set m = 0, 1, 2, or 2 resp.
|
||||||
|
return unsigned(n + 2 - m);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif//(GLM_COMPILER)
|
||||||
|
|
||||||
}//namespace glm
|
}//namespace glm
|
||||||
|
@ -1,136 +1,66 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net)
|
// OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net)
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Created : 2010-09-16
|
// Created : 2011-10-11
|
||||||
// Updated : 2010-09-16
|
// Updated : 2011-10-11
|
||||||
// Licence : This source is under MIT licence
|
// Licence : This source is under MIT licence
|
||||||
// File : test/gtx/bit.cpp
|
// File : test/gtx/gtx_integer.cpp
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtx/number_precision.hpp>
|
#include <glm/gtx/integer.hpp>
|
||||||
#include <glm/gtx/bit.hpp>
|
#include <glm/gtx/epsilon.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
enum result
|
int test_floor_log2()
|
||||||
{
|
{
|
||||||
SUCCESS,
|
int Error = 0;
|
||||||
FAIL,
|
|
||||||
ASSERT,
|
|
||||||
STATIC_ASSERT
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace extractField
|
for(std::size_t i = 1; i < 1000000; ++i)
|
||||||
{
|
|
||||||
template <typename genType, typename sizeType>
|
|
||||||
struct type
|
|
||||||
{
|
{
|
||||||
genType Value;
|
glm::uint A = glm::floor_log2(glm::uint(i));
|
||||||
sizeType BitFirst;
|
glm::uint B = glm::uint(glm::log2(double(i))); // Will fail with float, lack of accuracy
|
||||||
sizeType BitCount;
|
|
||||||
genType Return;
|
|
||||||
result Result;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef type<glm::uint64, glm::uint> typeU64;
|
Error += A == B ? 0 : 1;
|
||||||
|
assert(!Error);
|
||||||
typeU64 const Data64[] =
|
|
||||||
{
|
|
||||||
{0xffffffffffffffff, 8, 0, 0x0000000000000000, SUCCESS},
|
|
||||||
{0x0000000000000000, 0,64, 0x0000000000000000, SUCCESS},
|
|
||||||
{0xffffffffffffffff, 0,64, 0xffffffffffffffff, SUCCESS},
|
|
||||||
{0x0f0f0f0f0f0f0f0f, 0,64, 0x0f0f0f0f0f0f0f0f, SUCCESS},
|
|
||||||
{0x0000000000000000, 8, 0, 0x0000000000000000, SUCCESS},
|
|
||||||
{0x8000000000000000,63, 1, 0x0000000000000001, SUCCESS},
|
|
||||||
{0x7fffffffffffffff,63, 1, 0x0000000000000000, SUCCESS},
|
|
||||||
{0x0000000000000300, 8, 8, 0x0000000000000003, SUCCESS},
|
|
||||||
{0x000000000000ff00, 8, 8, 0x00000000000000ff, SUCCESS},
|
|
||||||
{0xfffffffffffffff0, 0, 5, 0x0000000000000010, SUCCESS},
|
|
||||||
{0x00000000000000ff, 1, 3, 0x0000000000000007, SUCCESS},
|
|
||||||
{0x00000000000000ff, 0, 3, 0x0000000000000007, SUCCESS},
|
|
||||||
{0x0000000000000000, 0, 2, 0x0000000000000000, SUCCESS},
|
|
||||||
{0xffffffffffffffff, 0, 8, 0x00000000000000ff, SUCCESS},
|
|
||||||
{0xffffffff00000000,32,32, 0x00000000ffffffff, SUCCESS},
|
|
||||||
{0xfffffffffffffff0, 0, 8, 0x0000000000000000, FAIL},
|
|
||||||
{0xffffffffffffffff,32,32, 0x0000000000000000, FAIL},
|
|
||||||
//{0xffffffffffffffff,64, 1, 0x0000000000000000, ASSERT}, // Throw an assert
|
|
||||||
//{0xffffffffffffffff, 0,65, 0x0000000000000000, ASSERT}, // Throw an assert
|
|
||||||
//{0xffffffffffffffff,33,32, 0x0000000000000000, ASSERT}, // Throw an assert
|
|
||||||
};
|
|
||||||
|
|
||||||
int test()
|
|
||||||
{
|
|
||||||
glm::uint32 count = sizeof(Data64) / sizeof(typeU64);
|
|
||||||
|
|
||||||
for(glm::uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
glm::uint64 Return = glm::extractField(
|
|
||||||
Data64[i].Value,
|
|
||||||
Data64[i].BitFirst,
|
|
||||||
Data64[i].BitCount);
|
|
||||||
|
|
||||||
bool Compare = Data64[i].Return == Return;
|
|
||||||
|
|
||||||
if(Data64[i].Result == SUCCESS && Compare)
|
|
||||||
continue;
|
|
||||||
else if(Data64[i].Result == FAIL && !Compare)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::cout << "glm::extractfield test fail on test " << i << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}//extractField
|
|
||||||
|
|
||||||
namespace bitRevert
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_log2()
|
||||||
{
|
{
|
||||||
template <typename genType>
|
int Error = 0;
|
||||||
struct type
|
|
||||||
|
for(std::size_t i = 1; i < 1000000; ++i)
|
||||||
{
|
{
|
||||||
genType Value;
|
glm::uint A = glm::log2(glm::uint(i));
|
||||||
genType Return;
|
double B = glm::log2(double(i));
|
||||||
result Result;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef type<glm::uint64> typeU64;
|
Error += glm::equalEpsilon(double(A), B, 1.0) ? 0 : 1;
|
||||||
|
assert(!Error);
|
||||||
typeU64 const Data64[] =
|
|
||||||
{
|
|
||||||
{0xffffffffffffffff, 0xffffffffffffffff, SUCCESS},
|
|
||||||
{0x0000000000000000, 0x0000000000000000, SUCCESS},
|
|
||||||
{0xf000000000000000, 0x000000000000000f, SUCCESS},
|
|
||||||
};
|
|
||||||
|
|
||||||
int test()
|
|
||||||
{
|
|
||||||
glm::uint32 count = sizeof(Data64) / sizeof(typeU64);
|
|
||||||
|
|
||||||
for(glm::uint32 i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
glm::uint64 Return = glm::bitRevert(
|
|
||||||
Data64[i].Value);
|
|
||||||
|
|
||||||
bool Compare = Data64[i].Return == Return;
|
|
||||||
|
|
||||||
if(Data64[i].Result == SUCCESS && Compare)
|
|
||||||
continue;
|
|
||||||
else if(Data64[i].Result == FAIL && !Compare)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
std::cout << "glm::extractfield test fail on test " << i << std::endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}//bitRevert
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_nlz()
|
||||||
|
{
|
||||||
|
int Error = 0;
|
||||||
|
|
||||||
|
for(std::size_t i = 1; i < 33; ++i)
|
||||||
|
printf("%d, %d\n", glm::nlz(i), 31 - glm::findMSB(i));
|
||||||
|
|
||||||
|
return Error;
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
int Error = 0;
|
int Error = 0;
|
||||||
Error += ::extractField::test();
|
|
||||||
Error += ::bitRevert::test();
|
Error += test_nlz();
|
||||||
|
Error += test_floor_log2();
|
||||||
|
Error += test_log2();
|
||||||
|
|
||||||
return Error;
|
return Error;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user