From 3c2882439f1d3668082a25b3cd694db8244fd7a2 Mon Sep 17 00:00:00 2001 From: Christophe Riccio Date: Tue, 11 Oct 2011 19:15:41 +0100 Subject: [PATCH] Added nlz, improved int log2, optimized findMSB with intrinsics --- glm/core/func_integer.inl | 32 ++++++++ glm/gtx/integer.hpp | 18 +++-- glm/gtx/integer.inl | 58 ++++++++++++++- test/gtx/gtx_integer.cpp | 150 ++++++++++---------------------------- 4 files changed, 139 insertions(+), 119 deletions(-) diff --git a/glm/core/func_integer.inl b/glm/core/func_integer.inl index fb91defc..31f9684f 100644 --- a/glm/core/func_integer.inl +++ b/glm/core/func_integer.inl @@ -26,6 +26,11 @@ /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// +#if(GLM_COMPILER & GLM_COMPILER_VC) +#include +#pragma intrinsic(_BitScanReverse) +#endif + namespace glm { // uaddCarry @@ -550,6 +555,32 @@ namespace glm } // findMSB +#if(GLM_COMPILER & GLM_COMPILER_VC) + + template + 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 + GLM_FUNC_QUALIFIER int findMSB + ( + genIUType const & Value + ) + { + return __builtin_clz(x); + } + +#else + template GLM_FUNC_QUALIFIER int findMSB ( @@ -564,6 +595,7 @@ namespace glm for(genIUType tmp = Value; tmp; tmp >>= 1, ++bit){} return bit; } +#endif//(GLM_COMPILER) template GLM_FUNC_QUALIFIER detail::tvec2 findMSB diff --git a/glm/gtx/integer.hpp b/glm/gtx/integer.hpp index 5dde37e5..9369bd43 100644 --- a/glm/gtx/integer.hpp +++ b/glm/gtx/integer.hpp @@ -58,10 +58,14 @@ namespace glm //! From GLM_GTX_integer extension. 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. 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. //! From GLM_GTX_integer extension. int mod(int x, int y); @@ -72,21 +76,25 @@ namespace glm genType factorial(genType const & x); //! 32bit signed integer. - //! From GLM_GTX_unsigned_int extension. + //! From GLM_GTX_integer extension. typedef signed int sint; //! Returns x raised to the y power. - //! From GLM_GTX_unsigned_int extension. + //! From GLM_GTX_integer extension. uint pow(uint x, uint y); //! Returns the positive square root of x. - //! From GLM_GTX_unsigned_int extension. + //! From GLM_GTX_integer extension. uint sqrt(uint x); //! 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); + //! Returns the number of leading zeros. + //! From GLM_GTX_integer extension. + uint nlz(uint x); + /// @} }//namespace glm diff --git a/glm/gtx/integer.inl b/glm/gtx/integer.inl index 113cb3cd..6bcaaf80 100644 --- a/glm/gtx/integer.inl +++ b/glm/gtx/integer.inl @@ -54,10 +54,18 @@ namespace detail return(x & 0x0000003f); } }//namespace detail -/* -// Henry Gordon Dietz: http://aggregate.org/MAGIC/ + 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)); y |= -y; @@ -69,10 +77,11 @@ GLM_FUNC_QUALIFIER unsigned int log2(unsigned int x) x |= (x >> 16); return detail::ones32(x) - 1 - y; -} */ +} + // 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 >> 2); @@ -159,4 +168,45 @@ GLM_FUNC_QUALIFIER uint mod(uint x, uint 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 diff --git a/test/gtx/gtx_integer.cpp b/test/gtx/gtx_integer.cpp index 13c9178b..08350b52 100644 --- a/test/gtx/gtx_integer.cpp +++ b/test/gtx/gtx_integer.cpp @@ -1,136 +1,66 @@ /////////////////////////////////////////////////////////////////////////////////////////////////// // OpenGL Mathematics Copyright (c) 2005 - 2011 G-Truc Creation (www.g-truc.net) /////////////////////////////////////////////////////////////////////////////////////////////////// -// Created : 2010-09-16 -// Updated : 2010-09-16 +// Created : 2011-10-11 +// Updated : 2011-10-11 // Licence : This source is under MIT licence -// File : test/gtx/bit.cpp +// File : test/gtx/gtx_integer.cpp /////////////////////////////////////////////////////////////////////////////////////////////////// #include -#include -#include +#include +#include #include -enum result +int test_floor_log2() { - SUCCESS, - FAIL, - ASSERT, - STATIC_ASSERT -}; + int Error = 0; -namespace extractField -{ - template - struct type + for(std::size_t i = 1; i < 1000000; ++i) { - genType Value; - sizeType BitFirst; - sizeType BitCount; - genType Return; - result Result; - }; + glm::uint A = glm::floor_log2(glm::uint(i)); + glm::uint B = glm::uint(glm::log2(double(i))); // Will fail with float, lack of accuracy - typedef type typeU64; - - 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; + Error += A == B ? 0 : 1; + assert(!Error); } -}//extractField -namespace bitRevert + return Error; +} + +int test_log2() { - template - struct type - { - genType Value; - genType Return; - result Result; - }; + int Error = 0; - typedef type typeU64; - - typeU64 const Data64[] = + for(std::size_t i = 1; i < 1000000; ++i) { - {0xffffffffffffffff, 0xffffffffffffffff, SUCCESS}, - {0x0000000000000000, 0x0000000000000000, SUCCESS}, - {0xf000000000000000, 0x000000000000000f, SUCCESS}, - }; + glm::uint A = glm::log2(glm::uint(i)); + double B = glm::log2(double(i)); - 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; + Error += glm::equalEpsilon(double(A), B, 1.0) ? 0 : 1; + assert(!Error); } -}//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 Error = 0; - Error += ::extractField::test(); - Error += ::bitRevert::test(); + + Error += test_nlz(); + Error += test_floor_log2(); + Error += test_log2(); + return Error; }