[1/2] d3dx9: Implement D3DXFloat32To16Array.

Dylan Smith dylan.ah.smith at gmail.com
Sun Jul 3 02:36:44 CDT 2011


Derived from patch submitted by Misha Koshelev <misha680 at gmail.com>.

Corrected rounding of denormalized numbers.
---
 dlls/d3dx9_36/d3dx9_36.spec |    2 +-
 dlls/d3dx9_36/math.c        |   99 +++++++++++++++++++++++++++++++++++++++++++
 dlls/d3dx9_36/tests/math.c  |    9 ++++
 3 files changed, 109 insertions(+), 1 deletions(-)

diff --git a/dlls/d3dx9_36/d3dx9_36.spec b/dlls/d3dx9_36/d3dx9_36.spec
index 5973d20..19c38c1 100644
--- a/dlls/d3dx9_36/d3dx9_36.spec
+++ b/dlls/d3dx9_36/d3dx9_36.spec
@@ -131,7 +131,7 @@
 @ stdcall D3DXFilterTexture(ptr ptr long long)
 @ stdcall D3DXFindShaderComment(ptr long ptr ptr)
 @ stdcall D3DXFloat16To32Array(ptr ptr long)
-@ stub D3DXFloat32To16Array(ptr ptr long)
+@ stdcall D3DXFloat32To16Array(ptr ptr long)
 @ stub D3DXFrameAppendChild(ptr ptr)
 @ stub D3DXFrameCalculateBoundingSphere(ptr ptr ptr)
 @ stdcall D3DXFrameDestroy(ptr ptr)
diff --git a/dlls/d3dx9_36/math.c b/dlls/d3dx9_36/math.c
index fde3e4e..f13f2fb 100644
--- a/dlls/d3dx9_36/math.c
+++ b/dlls/d3dx9_36/math.c
@@ -25,6 +25,8 @@
 #define NONAMELESSUNION
 
 #include "config.h"
+#include "wine/port.h"
+
 #include "windef.h"
 #include "wingdi.h"
 #include "d3dx9_36_private.h"
@@ -1770,6 +1772,103 @@ D3DXVECTOR4* WINAPI D3DXVec4TransformArray(D3DXVECTOR4* out, UINT outstride, CON
     return out;
 }
 
+static inline unsigned short float_32_to_16(const float in)
+{
+    int exp = 0, origexp;
+    float tmp = fabs(in);
+    int sign = signbit(in);
+    unsigned int mantissa;
+    unsigned short ret;
+
+    /* Deal with special numbers */
+    if (isinf(in)) return (sign ? 0xffff : 0x7fff);
+    if (isnan(in)) return (sign ? 0xffff : 0x7fff);
+    if (in == 0.0f) return (sign ? 0x8000 : 0x0000);
+
+    if (tmp < powf(2, 10))
+    {
+        do
+        {
+            tmp *= 2.0f;
+            exp--;
+        } while (tmp < powf(2, 10));
+    }
+    else if (tmp >= powf(2, 11))
+    {
+        do
+        {
+            tmp /= 2.0f;
+            exp++;
+        } while (tmp >= powf(2, 11));
+    }
+
+    exp += 10;  /* Normalize the mantissa */
+    exp += 15;  /* Exponent is encoded with excess 15 */
+
+    origexp = exp;
+
+    mantissa = (unsigned int) tmp;
+    if ((tmp - mantissa == 0.5f && mantissa % 2 == 1) || /* round half to even */
+        (tmp - mantissa > 0.5f))
+    {
+        mantissa++; /* round to nearest, away from zero */
+    }
+    if (mantissa == 2048)
+    {
+        mantissa = 1024;
+        exp++;
+    }
+
+    if (exp > 31)
+    {
+        /* too big */
+        ret = 0x7fff; /* INF */
+    }
+    else if (exp <= 0)
+    {
+        unsigned int rounding = 0;
+
+        /* Denormalized half float */
+
+        /* return 0x0000 (=0.0) for numbers too small to represent in half floats */
+        if (exp < -11)
+            return (sign ? 0x8000 : 0x0000);
+
+        exp = origexp;
+
+        /* the 13 extra bits from single precision are used for rounding */
+        mantissa = (unsigned int)(tmp * powf(2, 13));
+        mantissa >>= 1 - exp; /* denormalize */
+
+        mantissa -= ~(mantissa >> 13) & 1; /* round half to even */
+        /* remove 13 least significant bits to get half float precision */
+        mantissa >>= 12;
+        rounding = mantissa & 1;
+        mantissa >>= 1;
+
+        ret = mantissa + rounding;
+    }
+    else
+    {
+        ret = (exp << 10) | (mantissa & 0x3ff);
+    }
+
+    ret |= ((sign ? 1 : 0) << 15); /* Add the sign */
+    return ret;
+}
+
+D3DXFLOAT16 *WINAPI D3DXFloat32To16Array(D3DXFLOAT16 *pout, CONST FLOAT *pin, UINT n)
+{
+    unsigned int i;
+
+    for (i = 0; i < n; ++i)
+    {
+        pout[i].value = float_32_to_16(pin[i]);
+    }
+
+    return pout;
+}
+
 /* Native d3dx9's D3DXFloat16to32Array lacks support for NaN and Inf. Specifically, e = 16 is treated as a
  * regular number - e.g., 0x7fff is converted to 131008.0 and 0xffff to -131008.0. */
 static inline float float_16_to_32(const unsigned short in)
diff --git a/dlls/d3dx9_36/tests/math.c b/dlls/d3dx9_36/tests/math.c
index aa3f135..5dbc863 100644
--- a/dlls/d3dx9_36/tests/math.c
+++ b/dlls/d3dx9_36/tests/math.c
@@ -2257,11 +2257,20 @@ static void test_D3DXFloat_Array(void)
     };
 
     /* exception on NULL out or in parameter */
+    out = D3DXFloat32To16Array(&half, &single, 0);
+    ok(out == &half, "Got %p, expected %p.\n", out, &half);
+
     out = D3DXFloat16To32Array(&single, (D3DXFLOAT16 *)&half, 0);
     ok(out == &single, "Got %p, expected %p.\n", out, &single);
 
     for (i = 0; i < sizeof(testdata)/sizeof(testdata[0]); i++)
     {
+        out = D3DXFloat32To16Array(&half, &testdata[i].single_in, 1);
+        ok(out == &half, "Got %p, expected %p.\n", out, &half);
+        ok(half.value == testdata[i].half_ver1 || half.value == testdata[i].half_ver2,
+           "Got %x, expected %x or %x for index %d.\n", half.value, testdata[i].half_ver1,
+           testdata[i].half_ver2, i);
+
         out = D3DXFloat16To32Array(&single, (D3DXFLOAT16 *)&testdata[i].half_ver1, 1);
         ok(out == &single, "Got %p, expected %p.\n", out, &single);
         ok(relative_error(single, testdata[i].single_out_ver1) < admitted_error,
-- 
1.7.4.1




More information about the wine-patches mailing list