Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 Marek Olšák <maraeo@gmail.com> |
| 3 | * |
| 4 | * Permission is hereby granted, free of charge, to any person obtaining a |
| 5 | * copy of this software and associated documentation files (the "Software"), |
| 6 | * to deal in the Software without restriction, including without limitation |
| 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| 8 | * and/or sell copies of the Software, and to permit persons to whom the |
| 9 | * Software is furnished to do so, subject to the following conditions: |
| 10 | * |
| 11 | * The above copyright notice and this permission notice (including the next |
| 12 | * paragraph) shall be included in all copies or substantial portions of the |
| 13 | * Software. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| 18 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| 20 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
| 21 | * DEALINGS IN THE SOFTWARE. |
| 22 | */ |
| 23 | |
Roland Scheidegger | 941346a | 2015-08-09 02:03:33 +0200 | [diff] [blame] | 24 | /* Copied from EXT_texture_shared_exponent and edited, getting rid of |
| 25 | * expensive float math bits too. */ |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 26 | |
| 27 | #ifndef RGB9E5_H |
| 28 | #define RGB9E5_H |
| 29 | |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 30 | #include <assert.h> |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 31 | #include <stdint.h> |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 32 | |
Jose Fonseca | 8413822 | 2015-07-29 20:45:09 +0100 | [diff] [blame] | 33 | #include "c99_math.h" |
| 34 | |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 35 | #define RGB9E5_EXPONENT_BITS 5 |
| 36 | #define RGB9E5_MANTISSA_BITS 9 |
| 37 | #define RGB9E5_EXP_BIAS 15 |
| 38 | #define RGB9E5_MAX_VALID_BIASED_EXP 31 |
| 39 | |
| 40 | #define MAX_RGB9E5_EXP (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS) |
| 41 | #define RGB9E5_MANTISSA_VALUES (1<<RGB9E5_MANTISSA_BITS) |
| 42 | #define MAX_RGB9E5_MANTISSA (RGB9E5_MANTISSA_VALUES-1) |
| 43 | #define MAX_RGB9E5 (((float)MAX_RGB9E5_MANTISSA)/RGB9E5_MANTISSA_VALUES * (1<<MAX_RGB9E5_EXP)) |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 44 | |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 45 | static inline int rgb9e5_ClampRange(float x) |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 46 | { |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 47 | union { float f; uint32_t u; } f, max; |
| 48 | f.f = x; |
| 49 | max.f = MAX_RGB9E5; |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 50 | |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 51 | if (f.u > 0x7f800000) |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 52 | /* catches neg, NaNs */ |
| 53 | return 0; |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 54 | else if (f.u >= max.u) |
| 55 | return max.u; |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 56 | else |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 57 | return f.u; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 58 | } |
| 59 | |
Jason Ekstrand | ffcf8e1 | 2016-08-03 09:58:13 -0700 | [diff] [blame] | 60 | static inline uint32_t float3_to_rgb9e5(const float rgb[3]) |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 61 | { |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 62 | int rm, gm, bm, exp_shared; |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 63 | uint32_t revdenom_biasedexp; |
| 64 | union { float f; uint32_t u; } rc, bc, gc, maxrgb, revdenom; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 65 | |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 66 | rc.u = rgb9e5_ClampRange(rgb[0]); |
| 67 | gc.u = rgb9e5_ClampRange(rgb[1]); |
| 68 | bc.u = rgb9e5_ClampRange(rgb[2]); |
| 69 | maxrgb.u = MAX3(rc.u, gc.u, bc.u); |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 70 | |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 71 | /* |
| 72 | * Compared to what the spec suggests, instead of conditionally adjusting |
| 73 | * the exponent after the fact do it here by doing the equivalent of +0.5 - |
| 74 | * the int add will spill over into the exponent in this case. |
| 75 | */ |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 76 | maxrgb.u += maxrgb.u & (1 << (23-9)); |
| 77 | exp_shared = MAX2((maxrgb.u >> 23), -RGB9E5_EXP_BIAS - 1 + 127) + |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 78 | 1 + RGB9E5_EXP_BIAS - 127; |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 79 | revdenom_biasedexp = 127 - (exp_shared - RGB9E5_EXP_BIAS - |
| 80 | RGB9E5_MANTISSA_BITS) + 1; |
| 81 | revdenom.u = revdenom_biasedexp << 23; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 82 | assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 83 | |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 84 | /* |
| 85 | * The spec uses strict round-up behavior (d3d10 disagrees, but in any case |
| 86 | * must match what is done above for figuring out exponent). |
| 87 | * We avoid the doubles ((int) rc * revdenom + 0.5) by doing the rounding |
| 88 | * ourselves (revdenom was adjusted by +1, above). |
| 89 | */ |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 90 | rm = (int) (rc.f * revdenom.f); |
| 91 | gm = (int) (gc.f * revdenom.f); |
| 92 | bm = (int) (bc.f * revdenom.f); |
Roland Scheidegger | 48e6404 | 2015-08-09 02:50:10 +0200 | [diff] [blame] | 93 | rm = (rm & 1) + (rm >> 1); |
| 94 | gm = (gm & 1) + (gm >> 1); |
| 95 | bm = (bm & 1) + (bm >> 1); |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 96 | |
| 97 | assert(rm <= MAX_RGB9E5_MANTISSA); |
| 98 | assert(gm <= MAX_RGB9E5_MANTISSA); |
| 99 | assert(bm <= MAX_RGB9E5_MANTISSA); |
| 100 | assert(rm >= 0); |
| 101 | assert(gm >= 0); |
| 102 | assert(bm >= 0); |
| 103 | |
Jason Ekstrand | cda8d95 | 2016-08-03 09:39:00 -0700 | [diff] [blame] | 104 | return (exp_shared << 27) | (bm << 18) | (gm << 9) | rm; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 105 | } |
| 106 | |
Jason Ekstrand | ffcf8e1 | 2016-08-03 09:58:13 -0700 | [diff] [blame] | 107 | static inline void rgb9e5_to_float3(uint32_t rgb, float retval[3]) |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 108 | { |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 109 | int exponent; |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 110 | union { float f; uint32_t u; } scale; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 111 | |
Jason Ekstrand | cda8d95 | 2016-08-03 09:39:00 -0700 | [diff] [blame] | 112 | exponent = (rgb >> 27) - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS; |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 113 | scale.u = (exponent + 127) << 23; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 114 | |
Jason Ekstrand | c7eb9a7 | 2016-08-03 09:54:03 -0700 | [diff] [blame] | 115 | retval[0] = ( rgb & 0x1ff) * scale.f; |
| 116 | retval[1] = ((rgb >> 9) & 0x1ff) * scale.f; |
| 117 | retval[2] = ((rgb >> 18) & 0x1ff) * scale.f; |
Marek Olšák | 9d7698c | 2011-04-26 02:18:24 +0200 | [diff] [blame] | 118 | } |
| 119 | |
| 120 | #endif |