Implement floating-point conversion to the nearest representable integer.

Bug 20724899

Change-Id: I35f63709b5773c2cefe8bf2376e6d9236dfd81f9
Reviewed-on: https://swiftshader-review.googlesource.com/5090
Tested-by: Nicolas Capens <capn@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/libGLESv2/libGLESv2.cpp b/src/OpenGL/libGLESv2/libGLESv2.cpp
index 4732c52..ec21154 100644
--- a/src/OpenGL/libGLESv2/libGLESv2.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv2.cpp
@@ -3121,7 +3121,7 @@
 				{
 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
 					{
-						params[i] = es2::floatToInt(floatParams[i]);
+						params[i] = convert_float_int(floatParams[i]);
 					}
 					else
 					{
diff --git a/src/OpenGL/libGLESv2/libGLESv3.cpp b/src/OpenGL/libGLESv2/libGLESv3.cpp
index efa16c1..f20c893 100644
--- a/src/OpenGL/libGLESv2/libGLESv3.cpp
+++ b/src/OpenGL/libGLESv2/libGLESv3.cpp
@@ -1872,7 +1872,7 @@
 				{
 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
 					{
-						data[i] = es2::floatToInt(floatParams[i]);
+						data[i] = convert_float_int(floatParams[i]);
 					}
 					else
 					{
@@ -3210,7 +3210,7 @@
 				{
 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
 					{
-						data[i] = (GLint64)(es2::floatToInt(floatParams[i]));
+						data[i] = (GLint64)(convert_float_int(floatParams[i]));
 					}
 					else
 					{
@@ -3282,7 +3282,7 @@
 				{
 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
 					{
-						data[i] = (GLint64)(es2::floatToInt(floatParams[i]));
+						data[i] = (GLint64)(convert_float_int(floatParams[i]));
 					}
 					else
 					{
diff --git a/src/OpenGL/libGLESv2/mathutil.h b/src/OpenGL/libGLESv2/mathutil.h
index 0fbd709..62b6a1c 100644
--- a/src/OpenGL/libGLESv2/mathutil.h
+++ b/src/OpenGL/libGLESv2/mathutil.h
@@ -69,6 +69,26 @@
 		return (unsigned int)(max * x + 0.5f);
 	}
 }
+
+// Converts floating-point values to the nearest representable integer
+inline int convert_float_int(float x)
+{
+	// The largest positive integer value that is exactly representable in IEEE 754 binary32 is 0x7FFFFF80.
+	// The next floating-point value is 128 larger and thus needs clamping to 0x7FFFFFFF.
+	static_assert(std::numeric_limits<float>::is_iec559, "Unsupported floating-point format");
+
+	if(x > 0x7FFFFF80)
+	{
+		return 0x7FFFFFFF;
+	}
+
+	if(x < (signed)0x80000000)
+	{
+		return 0x80000000;
+	}
+
+	return static_cast<int>(roundf(x));
+}
 }
 
 #endif   // LIBGLESV2_MATHUTIL_H_
diff --git a/src/OpenGL/libGLESv2/utilities.cpp b/src/OpenGL/libGLESv2/utilities.cpp
index 850c1e2..9d22290 100644
--- a/src/OpenGL/libGLESv2/utilities.cpp
+++ b/src/OpenGL/libGLESv2/utilities.cpp
@@ -464,11 +464,6 @@
 		return -1;
 	}
 
-	GLint floatToInt(GLfloat value)
-	{
-		return static_cast<GLint>((static_cast<GLfloat>(0xFFFFFFFF) * value - 1.0f) * 0.5f);
-	}
-
 	bool IsCompressed(GLenum format, GLint clientVersion)
 	{
 		return ValidateCompressedFormat(format, clientVersion, true) == GL_NONE;
diff --git a/src/OpenGL/libGLESv2/utilities.h b/src/OpenGL/libGLESv2/utilities.h
index d2d9084..918fffa 100644
--- a/src/OpenGL/libGLESv2/utilities.h
+++ b/src/OpenGL/libGLESv2/utilities.h
@@ -41,8 +41,6 @@
 
 	int AllocateFirstFreeBits(unsigned int *bits, unsigned int allocationSize, unsigned int bitsSize);
 
-	GLint floatToInt(GLfloat value);
-
 	bool IsCompressed(GLenum format, GLint clientVersion);
 	GLenum GetSizedInternalFormat(GLenum internalFormat, GLenum type);
 	GLenum ValidateCompressedFormat(GLenum format, GLint clientVersion, bool expectCompressedFormats);