From 90b47b2dae25b933cc66510607e5a76fa1005155 Mon Sep 17 00:00:00 2001 From: Dylan Smith Date: Tue, 29 Mar 2011 13:47:38 -0400 Subject: [ 1/2] d3dx9: Implement D3DXFloat32To16Array. Reply-To: wine-devel X-Our-ReplyTo: Full To: wine-patches Derived from patch submitted by Misha Koshelev . Corrected rounding of denormalized numbers. --- dlls/d3dx9_36/d3dx9_36.spec | 2 +- dlls/d3dx9_36/math.c | 97 +++++++++++++++++++++++++++++++++++++++++++ dlls/d3dx9_36/tests/math.c | 9 ++++ 3 files changed, 107 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 229a058..2e455c6 100644 --- a/dlls/d3dx9_36/math.c +++ b/dlls/d3dx9_36/math.c @@ -1770,6 +1770,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