Changes.
[cairo/gpu.git] / src / cairo-half-float.c
blob7301f41fa4185ab0dfa6b6681b2223e36255bb66
1 /*
2 * Based on Mesa code
4 * Mesa 3-D graphics library
5 * Version: 7.1
7 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 #include "cairoint.h"
29 /**
30 * Convert a 4-byte float to a 2-byte half float.
31 * Based on code from:
32 * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
34 unsigned short
35 _cairo_float_to_half(float val)
37 const int flt = *((int *) (void *) &val);
38 const int flt_m = flt & 0x7fffff;
39 const int flt_e = (flt >> 23) & 0xff;
40 const int flt_s = (flt >> 31) & 0x1;
41 int s, e, m = 0;
42 unsigned short result;
44 /* sign bit */
45 s = flt_s;
47 /* handle special cases */
48 if ((flt_e == 0) && (flt_m == 0)) {
49 /* zero */
50 /* m = 0; - already set */
51 e = 0;
53 else if ((flt_e == 0) && (flt_m != 0)) {
54 /* denorm -- denorm float maps to 0 half */
55 /* m = 0; - already set */
56 e = 0;
58 else if ((flt_e == 0xff) && (flt_m == 0)) {
59 /* infinity */
60 /* m = 0; - already set */
61 e = 31;
63 else if ((flt_e == 0xff) && (flt_m != 0)) {
64 /* NaN */
65 m = 1;
66 e = 31;
68 else {
69 /* regular number */
70 const int new_exp = flt_e - 127;
71 if (new_exp < -24) {
72 /* this maps to 0 */
73 /* m = 0; - already set */
74 e = 0;
76 else if (new_exp < -14) {
77 /* this maps to a denorm */
78 unsigned int exp_val = (unsigned int) (-14 - new_exp); /* 2^-exp_val*/
79 e = 0;
80 switch (exp_val) {
81 case 0:
82 /* m = 0; - already set */
83 break;
84 case 1: m = 512 + (flt_m >> 14); break;
85 case 2: m = 256 + (flt_m >> 15); break;
86 case 3: m = 128 + (flt_m >> 16); break;
87 case 4: m = 64 + (flt_m >> 17); break;
88 case 5: m = 32 + (flt_m >> 18); break;
89 case 6: m = 16 + (flt_m >> 19); break;
90 case 7: m = 8 + (flt_m >> 20); break;
91 case 8: m = 4 + (flt_m >> 21); break;
92 case 9: m = 2 + (flt_m >> 22); break;
93 case 10: m = 1; break;
96 else if (new_exp > 15) {
97 /* map this value to infinity */
98 /* m = 0; - already set */
99 e = 31;
101 else {
102 /* regular */
103 e = new_exp + 15;
104 m = flt_m >> 13;
108 result = (s << 15) | (e << 10) | m;
109 return result;
114 * Convert a 2-byte half float to a 4-byte float.
115 * Based on code from:
116 * http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/008786.html
118 float
119 _cairo_half_to_float(unsigned short val)
121 /* XXX could also use a 64K-entry lookup table */
122 const int m = val & 0x3ff;
123 const int e = (val >> 10) & 0x1f;
124 const int s = (val >> 15) & 0x1;
125 int flt_m, flt_e, flt_s, flt;
126 float result;
128 /* sign bit */
129 flt_s = s;
131 /* handle special cases */
132 if ((e == 0) && (m == 0)) {
133 /* zero */
134 flt_m = 0;
135 flt_e = 0;
137 else if ((e == 0) && (m != 0)) {
138 /* denorm -- denorm half will fit in non-denorm single */
139 const float half_denorm = 1.0f / 16384.0f; /* 2^-14 */
140 float mantissa = ((float) (m)) / 1024.0f;
141 float sign = s ? -1.0f : 1.0f;
142 return sign * mantissa * half_denorm;
144 else if ((e == 31) && (m == 0)) {
145 /* infinity */
146 flt_e = 0xff;
147 flt_m = 0;
149 else if ((e == 31) && (m != 0)) {
150 /* NaN */
151 flt_e = 0xff;
152 flt_m = 1;
154 else {
155 /* regular */
156 flt_e = e + 112;
157 flt_m = m << 13;
160 flt = (flt_s << 31) | (flt_e << 23) | flt_m;
161 result = *((float *) (void *) &flt);
162 return result;