Parcourir la source

Added nlz, improved int log2, optimized findMSB with intrinsics

Christophe Riccio il y a 14 ans
Parent
commit
3c2882439f
4 fichiers modifiés avec 138 ajouts et 118 suppressions
  1. 32 0
      glm/core/func_integer.inl
  2. 13 5
      glm/gtx/integer.hpp
  3. 54 4
      glm/gtx/integer.inl
  4. 39 109
      test/gtx/gtx_integer.cpp

+ 32 - 0
glm/core/func_integer.inl

@@ -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

+ 13 - 5
glm/gtx/integer.hpp

@@ -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 - 4
glm/gtx/integer.inl

@@ -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

+ 39 - 109
test/gtx/gtx_integer.cpp

@@ -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
-// Updated : 2010-09-16
+// Created : 2011-10-11
+// 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/bit.hpp>
+#include <glm/gtx/integer.hpp>
+#include <glm/gtx/epsilon.hpp>
 #include <iostream>
 #include <iostream>
 
 
-enum result
+int test_floor_log2()
 {
 {
-	SUCCESS,
-	FAIL,
-	ASSERT,
-	STATIC_ASSERT
-};
+	int Error = 0;
 
 
-namespace extractField
-{
-	template <typename genType, typename sizeType>
-	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<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 
-	};
+	return Error;
+}
 
 
-	int test()
+int test_log2()
+{
+	int Error = 0;
+
+	for(std::size_t i = 1; i < 1000000; ++i)
 	{
 	{
-		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;
+		glm::uint A = glm::log2(glm::uint(i));
+		double B = glm::log2(double(i));
+
+		Error += glm::equalEpsilon(double(A), B, 1.0) ? 0 : 1;
+		assert(!Error);
 	}
 	}
-}//extractField
 
 
-namespace bitRevert
-{
-	template <typename genType>
-	struct type
-	{
-		genType		Value;
-		genType		Return;
-		result		Result;
-	};
+	return Error;
+}
 
 
-	typedef type<glm::uint64> typeU64;
+int test_nlz()
+{
+	int Error = 0;
 
 
-	typeU64 const Data64[] =
-	{
-		{0xffffffffffffffff, 0xffffffffffffffff, SUCCESS},
-		{0x0000000000000000, 0x0000000000000000, SUCCESS},
-		{0xf000000000000000, 0x000000000000000f, SUCCESS},
-	};
+	for(std::size_t i = 1; i < 33; ++i)
+		printf("%d, %d\n", glm::nlz(i), 31 - glm::findMSB(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;
-	}
-}//bitRevert
+	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;
 }
 }