home / developers / discussion forums / coding:advanced


UBBFriend: Email This Page to Someone!
  OpenGL.org Discussion & Help Forums
  OpenGL coding: advanced
  NV_half_float

Post New Topic  Post A Reply
profile | register | preferences | faq | search

next newest topic | next oldest topic
Author Topic:   NV_half_float
Lev
Frequent Contributor
posted 02-16-2003 11:41 AM     Click Here to See the Profile for Lev   Click Here to Email Lev     Edit/Delete Message Reply w/Quote
Anyone knows which C++ datatype should be used for the "half" GL type?

Regards,
-Lev

[This message has been edited by Lev (edited 02-24-2003).]

Asgard
Frequent Contributor
posted 02-16-2003 12:11 PM     Click Here to See the Profile for Asgard     Edit/Delete Message Reply w/Quote
Since half is a 16-bit IEEE-like floating point type, it'll nicely fit into a float on most machine architectures where float is typically a 32-bit IEEE floating point type.

Lev
Frequent Contributor
posted 02-16-2003 05:50 PM     Click Here to See the Profile for Lev   Click Here to Email Lev     Edit/Delete Message Reply w/Quote
Well, I can't see how a 16 bit float would fit into 32 bit one. They have different mantissa sizes. On the other hand 32 bit is te smallest float type available on x86. should I just typedef GLhalf as float? then what's the point in introducing new entry points if they are the same as existing on existing architectures?

regards,
-Lev

V-man
Frequent Contributor
posted 02-16-2003 10:28 PM     Click Here to See the Profile for V-man   Click Here to Email V-man     Edit/Delete Message Reply w/Quote
There is no 16 float support on most architextures. YOu have to do a conversion in software I guess.

Copy the mantissa, then OR the exponent and finally OR the sign bit on it. I'm going to check this out myself.

Ozzy
Frequent Contributor
posted 02-17-2003 02:49 AM     Click Here to See the Profile for Ozzy   Click Here to Email Ozzy     Edit/Delete Message Reply w/Quote
Yep u should adjust it for your needs just match what is written into the specs.. But should look as follow..

typedef short VR_FLOAT16;

__forceinline VR_FLOAT16 floatToFloat16(VR_FLOAT f)
{
VR_LONG val;
VR_FLOAT16 res;

__asm{
Fld dword ptr f
Fstp dword ptr val
}

res = (VR_FLOAT16) (val>>MYMANT);
return res;
}
__forceinline VR_FLOAT float16ToFloat(VR_FLOAT16 f16)
{
VR_LONG val;
VR_FLOAT res;

val = (VR_LONG) f16<<MYMANT;
__asm{
Fld dword ptr val
Fstp dword ptr res
}

return res;
}

hth

Nicolas Lelong
Frequent Contributor
posted 02-17-2003 11:02 AM     Click Here to See the Profile for Nicolas Lelong   Click Here to Email Nicolas Lelong     Edit/Delete Message Reply w/Quote
Hi,

you can also use the portable code provided with the OpenEXR image lib (http://www.openexr.org/) that uses Half floats.

In case you use VC, there is no official VC port yet but it's along the way - take a look at the OpenEXR forum.

Regards,
Nicolas.

mcraighead
Frequent Contributor
posted 02-19-2003 07:27 PM     Click Here to See the Profile for mcraighead   Click Here to Email mcraighead     Edit/Delete Message Reply w/Quote
The conversion is not as simple as has been suggested here -- it's fairly messy.

Isn't the answer "GLhalf"? Or, if you want to be fancy, a C++ struct that contains a GLhalf data element and has a bunch of operator overloads?

- Matt

pbrown
Frequent Contributor
posted 02-19-2003 08:35 PM     Click Here to See the Profile for pbrown   Click Here to Email pbrown     Edit/Delete Message Reply w/Quote
There is no native support for half-precision floats in any CPU I'm aware off.

We typedef GLhalf to "unsigned short" on Win32 platforms. To do anything CPU-wise with half-precision floats, you probably want to first convert them to float using a little bit of bit magic along the lines as those described in the posts above. Basically, we chose "unsigned short" because it takes the same number of bits and is the data type you'd want to use in this conversion.

Even with the CPU overhead, GLhalf data is useful for cases where (1) the data sets are pre-converted or (2) the data is both generated and consumed by GPUs that have native support. 16-bit components take 1/2 the bandwidth of 32-bit ones, and that bandwidth (and space) savings can be important if it doesn't get eaten up by the CPU overhead.

gking
Contributor
posted 02-19-2003 10:57 PM     Click Here to See the Profile for gking     Edit/Delete Message Reply w/Quote
We used half float vertex attributes in most of the GeForce FX launch demos, primarily for basis vectors (tangents, binormals, and normals). Note that for performance reasons, any half array should be padded to be a half2 array (or just left as a float array), and any half3 array should be padded to be a half4 array.

I've attached the basic conversion routines we used. We wrapped these in a class to automate the conversion process (like OpenEXR). The code isn't as efficient as it could be (half->float promotion could be performed with a 64K float lookup table), but it should be relatively self-explanatory. I'm hoping the formatting comes through ok, since I've copied it from the original file.

code:

union nv_half_data {
unsigned short bits;
struct {
unsigned long m : 10;
unsigned long e : 5;
unsigned long s : 1;
} ieee;
};

union ieee_single {
float f;
struct {
unsigned long m : 23;
unsigned long e : 8;
unsigned long s : 1;
} ieee;
};

inline static float htof(unsigned short val) {
nv_half_data h;
h.bits = val;
ieee_single sng;
sng.ieee.s = h.ieee.s;

// handle special cases
if ( (h.ieee.e==0) && (h.ieee.m==0) ) { // zero
sng.ieee.m=0;
sng.ieee.e=0;
}
else if ( (h.ieee.e==0) && (h.ieee.m!=0) ) { // denorm -- denorm half will fit in non-denorm single
const float half_denorm = (1.0f/16384.0f); // 2^-14
float mantissa = ((float)(h.ieee.m)) / 1024.0f;
float sgn = (h.ieee.s)? -1.0f :1.0f;
sng.f = sgn*mantissa*half_denorm;
}
else if ( (h.ieee.e==31) && (h.ieee.m==0) ) { // infinity
sng.ieee.e = 0xff;
sng.ieee.m = 0;
}
else if ( (h.ieee.e==31) && (h.ieee.m!=0) ) { // NaN
sng.ieee.e = 0xff;
sng.ieee.m = 1;
}
else {
sng.ieee.e = h.ieee.e+112;
sng.ieee.m = (h.ieee.m << 13);
}

return sng.f;
}

inline static unsigned short ftoh(float val) {
ieee_single f;
f.f = val;
nv_half_data h;

h.ieee.s = f.ieee.s;

// handle special cases

const float half_denorm = (1.0f/16384.0f);

if ( (f.ieee.e==0) && (f.ieee.m==0) ) { // zero
h.ieee.m = 0;
h.ieee.e = 0;
}
else if ( (f.ieee.e==0) && (f.ieee.m!=0) ) { // denorm -- denorm float maps to 0 half
h.ieee.m = 0;
h.ieee.e = 0;
}
else if ( (f.ieee.e==0xff) && (f.ieee.m==0) ) { // infinity
h.ieee.m = 0;
h.ieee.e = 31;
}
else if ( (f.ieee.e==0xff) && (f.ieee.m!=0) ) { // NaN
h.ieee.m = 1;
h.ieee.e = 31;
}
else { // regular number
int new_exp = f.ieee.e-127;
if (new_exp<-24) { // this maps to 0
h.ieee.m = 0;
h.ieee.e = 0;
}

if (new_exp<-14) { // this maps to a denorm
h.ieee.e = 0;
unsigned int exp_val = (unsigned int) (-14 - new_exp); // 2^-exp_val
switch (exp_val) {
case 0: fprintf(stderr, "ftoh: logical error in denorm creation!\n"); h.ieee.m = 0; break;
case 1: h.ieee.m = 512 + (f.ieee.m>>14); break;
case 2: h.ieee.m = 256 + (f.ieee.m>>15); break;
case 3: h.ieee.m = 128 + (f.ieee.m>>16); break;
case 4: h.ieee.m = 64 + (f.ieee.m>>17); break;
case 5: h.ieee.m = 32 + (f.ieee.m>>18); break;
case 6: h.ieee.m = 16 + (f.ieee.m>>19); break;
case 7: h.ieee.m = 8 + (f.ieee.m>>20); break;
case 8: h.ieee.m = 4 + (f.ieee.m>>21); break;
case 9: h.ieee.m = 2 + (f.ieee.m>>22); break;
case 10: h.ieee.m = 1; break;
}
}
else if (new_exp>15) { // map this value to infinity
h.ieee.m = 0;
h.ieee.e = 31;
}
else {
h.ieee.e = new_exp+15;
h.ieee.m = (f.ieee.m >> 13);
}
}

return h.bits;
}


MZ
Frequent Contributor
posted 02-20-2003 07:00 AM     Click Here to See the Profile for MZ   Click Here to Email MZ     Edit/Delete Message Reply w/Quote
quote:
We used half float vertex attributes in most of the GeForce FX launch demos, primarily for basis vectors (tangents, binormals, and normals)

What is benefit of using GLhalf instead of GLshort in such case?

harsman
Frequent Contributor
posted 02-20-2003 09:38 AM     Click Here to See the Profile for harsman   Click Here to Email harsman     Edit/Delete Message Reply w/Quote
Uhhm, floating point precision?

gking
Contributor
posted 02-20-2003 10:56 AM     Click Here to See the Profile for gking     Edit/Delete Message Reply w/Quote
It was chosen primarily as a convenience for the vector channels -- we have both ASCII and binary file formats, and using the half float format allowed us to use the ASCII format with floating point values and maintain straight-forward class compatibility.

However, the ability to use NaNs (or values > 1) to store per-vertex flags could be beneficial in some cases.

All times are ET (US)

next newest topic | next oldest topic

Administrative Options: Close Topic | Archive/Move | Delete Topic
Post New Topic  Post A Reply
Hop to:

Contact Us | OpenGL.org

Powered by: Ultimate Bulletin Board, Version 5.43d
© Infopop Corporation (formerly Madrona Park, Inc.), 1998 - 2000.