author | Claus Gittinger <cg@exept.de> |
Wed, 08 May 2019 14:41:45 +0200 | |
changeset 4942 | 9f424bed67c4 |
parent 4889 | 7d32114f8359 |
child 4980 | bef95bf81d84 |
permissions | -rw-r--r-- |
3159 | 1 |
" |
3221 | 2 |
COPYRIGHT (c) 2014 by Claus Gittinger |
3 |
All Rights Reserved |
|
3159 | 4 |
|
5 |
This software is furnished under a license and may be used |
|
6 |
only in accordance with the terms of that license and with the |
|
7 |
inclusion of the above copyright notice. This software may not |
|
8 |
be provided or otherwise made available to, or used by, any |
|
9 |
other person. No title to or ownership of the software is |
|
10 |
hereby transferred. |
|
11 |
" |
|
12 |
"{ Package: 'stx:libbasic2' }" |
|
13 |
||
4044 | 14 |
"{ NameSpace: Smalltalk }" |
15 |
||
4835 | 16 |
UnboxedFloatArray variableWordSubclass:#HalfFloatArray |
3159 | 17 |
instanceVariableNames:'' |
18 |
classVariableNames:'' |
|
19 |
poolDictionaries:'' |
|
20 |
category:'Collections-Arrayed' |
|
21 |
! |
|
22 |
||
23 |
!HalfFloatArray primitiveFunctions! |
|
24 |
%{ |
|
25 |
typedef unsigned short halffloat; |
|
26 |
typedef unsigned short uint16; |
|
27 |
typedef unsigned int uint32; |
|
4889 | 28 |
#if 0 |
4888 | 29 |
#if defined(__GNUC__) || defined(__CLANG__) || defined(__MINGW__) |
30 |
inline float |
|
31 |
XMConvertHalfToFloat(HALF Value) { |
|
32 |
__m128i V1 = _mm_cvtsi32_si128( static_cast<uint32_t>(Value) ); |
|
33 |
__m128 V2 = _mm_cvtph_ps( V1 ); |
|
34 |
return _mm_cvtss_f32( V2 ); |
|
35 |
} |
|
36 |
||
37 |
inline HALF |
|
38 |
XMConvertFloatToHalf(float Value) { |
|
39 |
__m128 V1 = _mm_set_ss( Value ); |
|
40 |
__m128i V2 = _mm_cvtps_ph( V1, 0 ); |
|
41 |
return static_cast<HALF>( _mm_cvtsi128_si32(V2) ); |
|
42 |
} |
|
43 |
#endif |
|
4889 | 44 |
#endif |
3159 | 45 |
// |
46 |
// convert a halffloat (16-bit float) to a float |
|
47 |
// |
|
48 |
float |
|
49 |
__STX_halffloat_to_float(halffloat h) { |
|
4888 | 50 |
int e; |
51 |
uint16 hs, he, hm; |
|
52 |
uint32 xs, xe, xm; |
|
53 |
int32 xes; |
|
54 |
union { |
|
55 |
uint32 u32; |
|
56 |
float f32; |
|
57 |
} u; |
|
3159 | 58 |
|
4888 | 59 |
if( (h & 0x7FFFu) == 0 ) { // Signed zero |
60 |
u.u32 = ((uint32) h) << 16; // Return the signed zero |
|
61 |
} else { // Not zero |
|
62 |
hs = h & 0x8000u; // Pick off sign bit |
|
63 |
he = h & 0x7C00u; // Pick off exponent bits |
|
64 |
hm = h & 0x03FFu; // Pick off mantissa bits |
|
65 |
if( he == 0 ) { // Denormal will convert to normalized |
|
66 |
e = -1; // The following loop figures out how much extra to adjust the exponent |
|
67 |
do { |
|
68 |
e++; |
|
69 |
hm <<= 1; |
|
70 |
} while( (hm & 0x0400u) == 0 ); // Shift until leading bit overflows into exponent bit |
|
71 |
xs = ((uint32) hs) << 16; // Sign bit |
|
72 |
xes = ((uint32) (he >> 10)) - 15 + 127 - e; // Exponent unbias the halfp, then bias the single |
|
73 |
xe = (uint32) (xes << 23); // Exponent |
|
74 |
xm = ((uint32) (hm & 0x03FFu)) << 13; // Mantissa |
|
75 |
u.u32 = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits |
|
76 |
} else if( he == 0x7C00u ) { // Inf or NaN (all the exponent bits are set) |
|
77 |
if( hm == 0 ) { // If mantissa is zero ... |
|
78 |
u.u32 = (((uint32) hs) << 16) | ((uint32) 0x7F800000u); // Signed Inf |
|
79 |
} else { |
|
80 |
u.u32 = (uint32) 0xFFC00000u; // NaN, only 1st mantissa bit set |
|
81 |
} |
|
82 |
} else { // Normalized number |
|
83 |
xs = ((uint32) hs) << 16; // Sign bit |
|
84 |
xes = ((uint32) (he >> 10)) - 15 + 127; // Exponent unbias the halfp, then bias the single |
|
85 |
xe = (uint32) (xes << 23); // Exponent |
|
86 |
xm = ((uint32) hm) << 13; // Mantissa |
|
87 |
u.u32 = (xs | xe | xm); // Combine sign bit, exponent bits, and mantissa bits |
|
88 |
} |
|
89 |
} |
|
90 |
return u.f32; |
|
3159 | 91 |
} |
92 |
||
93 |
// |
|
94 |
// convert a float to a halffloat (16-bit float) |
|
95 |
// |
|
96 |
halffloat |
|
97 |
__STX_float_to_halffloat(float f32) { |
|
4888 | 98 |
uint16 hs, he, hm; |
99 |
uint32 x, xs, xe, xm; |
|
100 |
int hes; |
|
101 |
union { |
|
102 |
uint32 u32; |
|
103 |
float f32; |
|
104 |
} u; |
|
105 |
halffloat h; |
|
3159 | 106 |
|
4888 | 107 |
u.f32 = f32; |
108 |
x = u.u32; |
|
109 |
if( (x & 0x7FFFFFFFu) == 0 ) { // Signed zero |
|
110 |
h = (uint16) (x >> 16); // Return the signed zero |
|
111 |
} else { // Not zero |
|
112 |
xs = x & 0x80000000u; // Pick off sign bit |
|
113 |
xe = x & 0x7F800000u; // Pick off exponent bits |
|
114 |
xm = x & 0x007FFFFFu; // Pick off mantissa bits |
|
115 |
if( xe == 0 ) { // Denormal will underflow, return a signed zero |
|
116 |
h = (uint16) (xs >> 16); |
|
117 |
} else if( xe == 0x7F800000u ) { // Inf or NaN (all the exponent bits are set) |
|
118 |
if( xm == 0 ) { // If mantissa is zero ... |
|
119 |
h = (uint16) ((xs >> 16) | 0x7C00u); // Signed Inf |
|
120 |
} else { |
|
121 |
h = (uint16) 0xFE00u; // NaN, only 1st mantissa bit set |
|
122 |
} |
|
123 |
} else { // Normalized number |
|
124 |
hs = (uint16) (xs >> 16); // Sign bit |
|
125 |
hes = ((int)(xe >> 23)) - 127 + 15; // Exponent unbias the single, then bias the halfp |
|
126 |
if( hes >= 0x1F ) { // Overflow |
|
127 |
h = (uint16) ((xs >> 16) | 0x7C00u); // Signed Inf |
|
128 |
} else if( hes <= 0 ) { // Underflow |
|
129 |
if( (14 - hes) > 24 ) { // Mantissa shifted all the way off & no rounding possibility |
|
130 |
hm = (uint16) 0u; // Set mantissa to zero |
|
131 |
} else { |
|
132 |
xm |= 0x00800000u; // Add the hidden leading bit |
|
133 |
hm = (uint16) (xm >> (14 - hes)); // Mantissa |
|
134 |
if( (xm >> (13 - hes)) & 0x00000001u ) // Check for rounding |
|
135 |
hm += (uint16) 1u; // Round, might overflow into exp bit, but this is OK |
|
136 |
} |
|
137 |
h = (hs | hm); // Combine sign bit and mantissa bits, biased exponent is zero |
|
138 |
} else { |
|
139 |
he = (uint16) (hes << 10); // Exponent |
|
140 |
hm = (uint16) (xm >> 13); // Mantissa |
|
141 |
if( xm & 0x00001000u ) // Check for rounding |
|
142 |
h = (hs | he | hm) + (uint16) 1u; // Round, might overflow to inf, this is OK |
|
143 |
else |
|
144 |
h = (hs | he | hm); // No rounding |
|
145 |
} |
|
146 |
} |
|
147 |
} |
|
148 |
return h; |
|
3159 | 149 |
} |
150 |
||
151 |
%} |
|
3160 | 152 |
! ! |
3159 | 153 |
|
154 |
!HalfFloatArray class methodsFor:'documentation'! |
|
155 |
||
156 |
copyright |
|
157 |
" |
|
3221 | 158 |
COPYRIGHT (c) 2014 by Claus Gittinger |
159 |
All Rights Reserved |
|
3159 | 160 |
|
161 |
This software is furnished under a license and may be used |
|
162 |
only in accordance with the terms of that license and with the |
|
163 |
inclusion of the above copyright notice. This software may not |
|
164 |
be provided or otherwise made available to, or used by, any |
|
165 |
other person. No title to or ownership of the software is |
|
166 |
hereby transferred. |
|
167 |
" |
|
168 |
! |
|
169 |
||
170 |
documentation |
|
171 |
" |
|
172 |
HalfFloatArrays store half precision (16bit) floats (and nothing else). |
|
3221 | 173 |
HalfFloats were traditionally seldom used, but seem to become more popular |
3159 | 174 |
these days, as some 3D graphics accelerators and game engines use them |
3304 | 175 |
for very dense and compact storage of texture and vertex data. |
3160 | 176 |
|
3304 | 177 |
Notice, that HalfFloats are not supported as first class objects by the ST/X system; |
3160 | 178 |
i.e. outside of a HalfFloatArray, these values are represented as floats |
3304 | 179 |
or doubles. When accessing a HalfFloatArray's element via getters/setters, |
180 |
shortFloat (i.e. single precision 32bit floats) are exchanged. |
|
181 |
||
3160 | 182 |
Be aware that the numeric range of a half-float is very very limited. |
3159 | 183 |
|
184 |
[memory requirements:] |
|
3160 | 185 |
OBJ-HEADER + (size * 2) |
3159 | 186 |
|
187 |
[See also:] |
|
3160 | 188 |
FloatArray DoubleArray Array |
3304 | 189 |
http://www.opengl.org/wiki/Small_Float_Formats |
3159 | 190 |
|
191 |
[author:] |
|
3160 | 192 |
Claus Gittinger |
3159 | 193 |
" |
194 |
! ! |
|
195 |
||
196 |
!HalfFloatArray class methodsFor:'queries'! |
|
197 |
||
198 |
elementByteSize |
|
3335
deeaf91b9227
comment/format in: #elementByteSize
Claus Gittinger <cg@exept.de>
parents:
3305
diff
changeset
|
199 |
"for bit-like containers, return the number of bytes stored per element. |
deeaf91b9227
comment/format in: #elementByteSize
Claus Gittinger <cg@exept.de>
parents:
3305
diff
changeset
|
200 |
Here, 2 is returned" |
deeaf91b9227
comment/format in: #elementByteSize
Claus Gittinger <cg@exept.de>
parents:
3305
diff
changeset
|
201 |
|
3159 | 202 |
^ 2 |
203 |
! ! |
|
204 |
||
205 |
!HalfFloatArray methodsFor:'accessing'! |
|
206 |
||
207 |
at:index |
|
208 |
%{ /* NOCONTEXT */ |
|
209 |
if (__isSmallInteger(index)) { |
|
210 |
int i = __intVal(index); |
|
3169 | 211 |
int n = __wordArraySize(self); |
3159 | 212 |
|
3169 | 213 |
if ((unsigned)i <= n) { |
3159 | 214 |
unsigned short h; |
215 |
OBJ newFloat; |
|
216 |
float f; |
|
217 |
||
3169 | 218 |
h = __WordArrayInstPtr(self)->s_element[i-1]; |
3159 | 219 |
|
220 |
f = __STX_halffloat_to_float(h); |
|
221 |
__qMKSFLOAT(newFloat, f); |
|
222 |
RETURN ( newFloat ); |
|
223 |
} |
|
224 |
} |
|
225 |
%}. |
|
226 |
self primitiveFailed |
|
227 |
! |
|
228 |
||
229 |
at:index put:aFloat |
|
230 |
%{ |
|
231 |
if (__isSmallInteger(index)) { |
|
232 |
int i = __intVal(index); |
|
3169 | 233 |
int n = __wordArraySize(self); |
3159 | 234 |
|
3169 | 235 |
if ((unsigned)i <= n) { |
3159 | 236 |
unsigned short h; |
237 |
float f; |
|
238 |
||
239 |
if (__isFloat(aFloat)) { |
|
240 |
f = (float)(__floatVal(aFloat)); |
|
241 |
} else if (__isShortFloat(aFloat)) { |
|
242 |
f = __shortFloatVal(aFloat); |
|
243 |
} else if (__isSmallInteger(aFloat)) { |
|
244 |
f = (float)(__intVal(aFloat)); |
|
245 |
} else |
|
246 |
goto error; |
|
247 |
||
248 |
h = __STX_float_to_halffloat(f); |
|
3169 | 249 |
__WordArrayInstPtr(self)->s_element[i-1] = h; |
3159 | 250 |
RETURN (aFloat); |
251 |
} |
|
252 |
} |
|
253 |
error: ; |
|
254 |
%}. |
|
255 |
self primitiveFailed |
|
256 |
! ! |
|
257 |
||
258 |
!HalfFloatArray methodsFor:'queries'! |
|
259 |
||
260 |
defaultElement |
|
261 |
^ ShortFloat zero |
|
262 |
! |
|
263 |
||
4044 | 264 |
isValidElement:anObject |
265 |
"return true, if I can hold this kind of object" |
|
266 |
||
267 |
^ anObject isNumber |
|
268 |
! |
|
269 |
||
3159 | 270 |
numFloats |
271 |
^ self size |
|
272 |
! ! |
|
273 |
||
4834 | 274 |
!HalfFloatArray methodsFor:'testing'! |
275 |
||
276 |
isFloatArray |
|
277 |
"return true if the receiver has float elements. |
|
278 |
These are Float, Double- and HalfFloat arrays" |
|
279 |
||
280 |
^ true |
|
281 |
||
282 |
"Created: / 02-03-2019 / 23:14:00 / Claus Gittinger" |
|
283 |
! ! |
|
284 |
||
3159 | 285 |
!HalfFloatArray class methodsFor:'documentation'! |
286 |
||
3305 | 287 |
version |
4044 | 288 |
^ '$Header$' |
3305 | 289 |
! |
290 |
||
3159 | 291 |
version_CVS |
4044 | 292 |
^ '$Header$' |
3159 | 293 |
! ! |
3160 | 294 |