diff options
Diffstat (limited to 'lib/mesa/src/util')
-rw-r--r-- | lib/mesa/src/util/Makefile.sources | 14 | ||||
-rw-r--r-- | lib/mesa/src/util/SConscript | 7 | ||||
-rw-r--r-- | lib/mesa/src/util/bitscan.c | 80 | ||||
-rw-r--r-- | lib/mesa/src/util/bitscan.h | 234 | ||||
-rw-r--r-- | lib/mesa/src/util/bitset.h | 2 | ||||
-rw-r--r-- | lib/mesa/src/util/format_r11g11b10f.h | 227 | ||||
-rw-r--r-- | lib/mesa/src/util/format_rgb9e5.h | 120 | ||||
-rw-r--r-- | lib/mesa/src/util/hash_table.c | 2 | ||||
-rw-r--r-- | lib/mesa/src/util/hash_table.h | 13 | ||||
-rw-r--r-- | lib/mesa/src/util/list.h | 36 | ||||
-rw-r--r-- | lib/mesa/src/util/macros.h | 25 | ||||
-rw-r--r-- | lib/mesa/src/util/mesa-sha1.c | 20 | ||||
-rw-r--r-- | lib/mesa/src/util/mesa-sha1.h | 4 | ||||
-rw-r--r-- | lib/mesa/src/util/ralloc.c | 21 | ||||
-rw-r--r-- | lib/mesa/src/util/rounding.h | 7 | ||||
-rw-r--r-- | lib/mesa/src/util/slab.c | 316 | ||||
-rw-r--r-- | lib/mesa/src/util/slab.h | 94 | ||||
-rw-r--r-- | lib/mesa/src/util/string_to_uint_map.cpp | 42 | ||||
-rw-r--r-- | lib/mesa/src/util/string_to_uint_map.h | 177 | ||||
-rw-r--r-- | lib/mesa/src/util/u_endian.h | 69 | ||||
-rw-r--r-- | lib/mesa/src/util/u_vector.c | 98 | ||||
-rw-r--r-- | lib/mesa/src/util/u_vector.h | 92 | ||||
-rw-r--r-- | lib/mesa/src/util/vk_alloc.h | 75 |
23 files changed, 1741 insertions, 34 deletions
diff --git a/lib/mesa/src/util/Makefile.sources b/lib/mesa/src/util/Makefile.sources index a87114601..c5531c82d 100644 --- a/lib/mesa/src/util/Makefile.sources +++ b/lib/mesa/src/util/Makefile.sources @@ -1,7 +1,11 @@ MESA_UTIL_FILES := \ + bitscan.c \ + bitscan.h \ bitset.h \ debug.c \ debug.h \ + format_r11g11b10f.h \ + format_rgb9e5.h \ format_srgb.h \ half_float.c \ half_float.h \ @@ -21,12 +25,20 @@ MESA_UTIL_FILES := \ set.c \ set.h \ simple_list.h \ + slab.c \ + slab.h \ + string_to_uint_map.h \ + string_to_uint_map.cpp \ strndup.c \ strndup.h \ strtod.c \ strtod.h \ texcompress_rgtc_tmp.h \ - u_atomic.h + u_atomic.h \ + u_endian.h \ + u_vector.c \ + u_vector.h \ + vk_alloc.h MESA_UTIL_GENERATED_FILES = \ format_srgb.c diff --git a/lib/mesa/src/util/SConscript b/lib/mesa/src/util/SConscript index 5f3ecc1cd..73f343039 100644 --- a/lib/mesa/src/util/SConscript +++ b/lib/mesa/src/util/SConscript @@ -47,17 +47,14 @@ env.Alias('mesautil', mesautil) Export('mesautil') -# http://www.scons.org/wiki/UnitTests u_atomic_test = env.Program( target = 'u_atomic_test', source = ['u_atomic_test.c'], ) -alias = env.Alias("u_atomic_test", u_atomic_test, u_atomic_test[0].abspath) -AlwaysBuild(alias) +env.UnitTest("u_atomic_test", u_atomic_test) roundeven_test = env.Program( target = 'roundeven_test', source = ['roundeven_test.c'], ) -alias = env.Alias("roundeven_test", roundeven_test, roundeven_test[0].abspath) -AlwaysBuild(alias) +env.UnitTest("roundeven_test", roundeven_test) diff --git a/lib/mesa/src/util/bitscan.c b/lib/mesa/src/util/bitscan.c new file mode 100644 index 000000000..ceca59eba --- /dev/null +++ b/lib/mesa/src/util/bitscan.c @@ -0,0 +1,80 @@ +/************************************************************************** + * + * Copyright 2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#include "bitscan.h" + +#ifdef HAVE___BUILTIN_FFS +#elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64) +#else +int +ffs(unsigned i) +{ + int bit = 0; + if (!i) + return bit; + if (!(i & 0xffff)) { + bit += 16; + i >>= 16; + } + if (!(i & 0xff)) { + bit += 8; + i >>= 8; + } + if (!(i & 0xf)) { + bit += 4; + i >>= 4; + } + if (!(i & 0x3)) { + bit += 2; + i >>= 2; + } + if (!(i & 0x1)) + bit += 1; + return bit + 1; +} +#endif + +#ifdef HAVE___BUILTIN_FFSLL +#elif defined(_MSC_VER) && (_M_AMD64 || _M_ARM || _M_IA64) +#else +int +ffsll(uint64_t val) +{ + int bit; + + bit = ffs((unsigned) (val & 0xffffffff)); + if (bit != 0) + return bit; + + bit = ffs((unsigned) (val >> 32)); + if (bit != 0) + return 32 + bit; + + return 0; +} +#endif diff --git a/lib/mesa/src/util/bitscan.h b/lib/mesa/src/util/bitscan.h new file mode 100644 index 000000000..a5dfa1f9e --- /dev/null +++ b/lib/mesa/src/util/bitscan.h @@ -0,0 +1,234 @@ +/************************************************************************** + * + * Copyright 2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + + +#ifndef BITSCAN_H +#define BITSCAN_H + +#include <assert.h> +#include <stdint.h> +#include <string.h> + +#if defined(_MSC_VER) +#include <intrin.h> +#endif + +#include "c99_compat.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Find first bit set in word. Least significant bit is 1. + * Return 0 if no bits set. + */ +#ifdef HAVE___BUILTIN_FFS +#define ffs __builtin_ffs +#elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64) +static inline +int ffs(unsigned i) +{ + unsigned long index; + if (_BitScanForward(&index, i)) + return index + 1; + else + return 0; +} +#else +extern +int ffs(unsigned i); +#endif + +#ifdef HAVE___BUILTIN_FFSLL +#define ffsll __builtin_ffsll +#elif defined(_MSC_VER) && (_M_AMD64 || _M_ARM || _M_IA64) +static inline int +ffsll(uint64_t i) +{ + unsigned long index; + if (_BitScanForward64(&index, i)) + return index + 1; + else + return 0; +} +#else +extern int +ffsll(uint64_t val); +#endif + + +/* Destructively loop over all of the bits in a mask as in: + * + * while (mymask) { + * int i = u_bit_scan(&mymask); + * ... process element i + * } + * + */ +static inline int +u_bit_scan(unsigned *mask) +{ + const int i = ffs(*mask) - 1; + *mask ^= (1u << i); + return i; +} + +static inline int +u_bit_scan64(uint64_t *mask) +{ + const int i = ffsll(*mask) - 1; + *mask ^= (((uint64_t)1) << i); + return i; +} + +/* For looping over a bitmask when you want to loop over consecutive bits + * manually, for example: + * + * while (mask) { + * int start, count, i; + * + * u_bit_scan_consecutive_range(&mask, &start, &count); + * + * for (i = 0; i < count; i++) + * ... process element (start+i) + * } + */ +static inline void +u_bit_scan_consecutive_range(unsigned *mask, int *start, int *count) +{ + if (*mask == 0xffffffff) { + *start = 0; + *count = 32; + *mask = 0; + return; + } + *start = ffs(*mask) - 1; + *count = ffs(~(*mask >> *start)) - 1; + *mask &= ~(((1u << *count) - 1) << *start); +} + +static inline void +u_bit_scan_consecutive_range64(uint64_t *mask, int *start, int *count) +{ + if (*mask == ~0llu) { + *start = 0; + *count = 64; + *mask = 0; + return; + } + *start = ffsll(*mask) - 1; + *count = ffsll(~(*mask >> *start)) - 1; + *mask &= ~(((((uint64_t)1) << *count) - 1) << *start); +} + + +/** + * Find last bit set in a word. The least significant bit is 1. + * Return 0 if no bits are set. + * Essentially ffs() in the reverse direction. + */ +static inline unsigned +util_last_bit(unsigned u) +{ +#if defined(HAVE___BUILTIN_CLZ) + return u == 0 ? 0 : 32 - __builtin_clz(u); +#elif defined(_MSC_VER) && (_M_IX86 || _M_ARM || _M_AMD64 || _M_IA64) + unsigned long index; + if (_BitScanReverse(&index, u)) + return index + 1; + else + return 0; +#else + unsigned r = 0; + while (u) { + r++; + u >>= 1; + } + return r; +#endif +} + +/** + * Find last bit set in a word. The least significant bit is 1. + * Return 0 if no bits are set. + * Essentially ffsll() in the reverse direction. + */ +static inline unsigned +util_last_bit64(uint64_t u) +{ +#if defined(HAVE___BUILTIN_CLZLL) + return u == 0 ? 0 : 64 - __builtin_clzll(u); +#elif defined(_MSC_VER) && (_M_AMD64 || _M_ARM || _M_IA64) + unsigned long index; + if (_BitScanReverse64(&index, u)) + return index + 1; + else + return 0; +#else + unsigned r = 0; + while (u) { + r++; + u >>= 1; + } + return r; +#endif +} + +/** + * Find last bit in a word that does not match the sign bit. The least + * significant bit is 1. + * Return 0 if no bits are set. + */ +static inline unsigned +util_last_bit_signed(int i) +{ + if (i >= 0) + return util_last_bit(i); + else + return util_last_bit(~(unsigned)i); +} + +/* Returns a bitfield in which the first count bits starting at start are + * set. + */ +static inline unsigned +u_bit_consecutive(unsigned start, unsigned count) +{ + assert(start + count <= 32); + if (count == 32) + return ~0; + return ((1u << count) - 1) << start; +} + + +#ifdef __cplusplus +} +#endif + +#endif /* BITSCAN_H */ diff --git a/lib/mesa/src/util/bitset.h b/lib/mesa/src/util/bitset.h index c45281941..2404ce7f6 100644 --- a/lib/mesa/src/util/bitset.h +++ b/lib/mesa/src/util/bitset.h @@ -98,7 +98,7 @@ __bitset_ffs(const BITSET_WORD *x, int n) static inline unsigned __bitset_next_set(unsigned i, BITSET_WORD *tmp, - BITSET_WORD *set, unsigned size) + const BITSET_WORD *set, unsigned size) { unsigned bit, word; diff --git a/lib/mesa/src/util/format_r11g11b10f.h b/lib/mesa/src/util/format_r11g11b10f.h new file mode 100644 index 000000000..f6cd4ac69 --- /dev/null +++ b/lib/mesa/src/util/format_r11g11b10f.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2011 Marek Olšák <maraeo@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Based on code from The OpenGL Programming Guide / 7th Edition, Appendix J. + * Available here: http://www.opengl-redbook.com/appendices/ + * The algorithm in the book contains a bug though, which is fixed in the code + * below. + */ + +#include <stdint.h> + +#define UF11(e, m) ((e << 6) | (m)) +#define UF11_EXPONENT_BIAS 15 +#define UF11_EXPONENT_BITS 0x1F +#define UF11_EXPONENT_SHIFT 6 +#define UF11_MANTISSA_BITS 0x3F +#define UF11_MANTISSA_SHIFT (23 - UF11_EXPONENT_SHIFT) +#define UF11_MAX_EXPONENT (UF11_EXPONENT_BITS << UF11_EXPONENT_SHIFT) + +#define UF10(e, m) ((e << 5) | (m)) +#define UF10_EXPONENT_BIAS 15 +#define UF10_EXPONENT_BITS 0x1F +#define UF10_EXPONENT_SHIFT 5 +#define UF10_MANTISSA_BITS 0x1F +#define UF10_MANTISSA_SHIFT (23 - UF10_EXPONENT_SHIFT) +#define UF10_MAX_EXPONENT (UF10_EXPONENT_BITS << UF10_EXPONENT_SHIFT) + +#define F32_INFINITY 0x7f800000 + +static inline uint32_t f32_to_uf11(float val) +{ + union { + float f; + uint32_t ui; + } f32 = {val}; + + uint16_t uf11 = 0; + + /* Decode little-endian 32-bit floating-point value */ + int sign = (f32.ui >> 16) & 0x8000; + /* Map exponent to the range [-127,128] */ + int exponent = ((f32.ui >> 23) & 0xff) - 127; + int mantissa = f32.ui & 0x007fffff; + + if (exponent == 128) { /* Infinity or NaN */ + /* From the GL_EXT_packed_float spec: + * + * "Additionally: negative infinity is converted to zero; positive + * infinity is converted to positive infinity; and both positive and + * negative NaN are converted to positive NaN." + */ + uf11 = UF11_MAX_EXPONENT; + if (mantissa) { + uf11 |= 1; /* NaN */ + } else { + if (sign) + uf11 = 0; /* 0.0 */ + } + } else if (sign) { + return 0; + } else if (val > 65024.0f) { + /* From the GL_EXT_packed_float spec: + * + * "Likewise, finite positive values greater than 65024 (the maximum + * finite representable unsigned 11-bit floating-point value) are + * converted to 65024." + */ + uf11 = UF11(30, 63); + } else if (exponent > -15) { /* Representable value */ + exponent += UF11_EXPONENT_BIAS; + mantissa >>= UF11_MANTISSA_SHIFT; + uf11 = exponent << UF11_EXPONENT_SHIFT | mantissa; + } + + return uf11; +} + +static inline float uf11_to_f32(uint16_t val) +{ + union { + float f; + uint32_t ui; + } f32; + + int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT; + int mantissa = (val & 0x003f); + + f32.f = 0.0; + + if (exponent == 0) { + if (mantissa != 0) { + const float scale = 1.0 / (1 << 20); + f32.f = scale * mantissa; + } + } else if (exponent == 31) { + f32.ui = F32_INFINITY | mantissa; + } else { + float scale, decimal; + exponent -= 15; + if (exponent < 0) { + scale = 1.0f / (1 << -exponent); + } else { + scale = (float) (1 << exponent); + } + decimal = 1.0f + (float) mantissa / 64; + f32.f = scale * decimal; + } + + return f32.f; +} + +static inline uint32_t f32_to_uf10(float val) +{ + union { + float f; + uint32_t ui; + } f32 = {val}; + + uint16_t uf10 = 0; + + /* Decode little-endian 32-bit floating-point value */ + int sign = (f32.ui >> 16) & 0x8000; + /* Map exponent to the range [-127,128] */ + int exponent = ((f32.ui >> 23) & 0xff) - 127; + int mantissa = f32.ui & 0x007fffff; + + if (exponent == 128) { + /* From the GL_EXT_packed_float spec: + * + * "Additionally: negative infinity is converted to zero; positive + * infinity is converted to positive infinity; and both positive and + * negative NaN are converted to positive NaN." + */ + uf10 = UF10_MAX_EXPONENT; + if (mantissa) { + uf10 |= 1; /* NaN */ + } else { + if (sign) + uf10 = 0; /* 0.0 */ + } + } else if (sign) { + return 0; + } else if (val > 64512.0f) { + /* From the GL_EXT_packed_float spec: + * + * "Likewise, finite positive values greater than 64512 (the maximum + * finite representable unsigned 10-bit floating-point value) are + * converted to 64512." + */ + uf10 = UF10(30, 31); + } else if (exponent > -15) { /* Representable value */ + exponent += UF10_EXPONENT_BIAS; + mantissa >>= UF10_MANTISSA_SHIFT; + uf10 = exponent << UF10_EXPONENT_SHIFT | mantissa; + } + + return uf10; +} + +static inline float uf10_to_f32(uint16_t val) +{ + union { + float f; + uint32_t ui; + } f32; + + int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT; + int mantissa = (val & 0x001f); + + f32.f = 0.0; + + if (exponent == 0) { + if (mantissa != 0) { + const float scale = 1.0 / (1 << 19); + f32.f = scale * mantissa; + } + } else if (exponent == 31) { + f32.ui = F32_INFINITY | mantissa; + } else { + float scale, decimal; + exponent -= 15; + if (exponent < 0) { + scale = 1.0f / (1 << -exponent); + } + else { + scale = (float) (1 << exponent); + } + decimal = 1.0f + (float) mantissa / 32; + f32.f = scale * decimal; + } + + return f32.f; +} + +static inline uint32_t float3_to_r11g11b10f(const float rgb[3]) +{ + return ( f32_to_uf11(rgb[0]) & 0x7ff) | + ((f32_to_uf11(rgb[1]) & 0x7ff) << 11) | + ((f32_to_uf10(rgb[2]) & 0x3ff) << 22); +} + +static inline void r11g11b10f_to_float3(uint32_t rgb, float retval[3]) +{ + retval[0] = uf11_to_f32( rgb & 0x7ff); + retval[1] = uf11_to_f32((rgb >> 11) & 0x7ff); + retval[2] = uf10_to_f32((rgb >> 22) & 0x3ff); +} diff --git a/lib/mesa/src/util/format_rgb9e5.h b/lib/mesa/src/util/format_rgb9e5.h new file mode 100644 index 000000000..70ad04fde --- /dev/null +++ b/lib/mesa/src/util/format_rgb9e5.h @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2011 Marek Olšák <maraeo@gmail.com> + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* Copied from EXT_texture_shared_exponent and edited, getting rid of + * expensive float math bits too. */ + +#ifndef RGB9E5_H +#define RGB9E5_H + +#include <assert.h> +#include <stdint.h> + +#include "c99_math.h" + +#define RGB9E5_EXPONENT_BITS 5 +#define RGB9E5_MANTISSA_BITS 9 +#define RGB9E5_EXP_BIAS 15 +#define RGB9E5_MAX_VALID_BIASED_EXP 31 + +#define MAX_RGB9E5_EXP (RGB9E5_MAX_VALID_BIASED_EXP - RGB9E5_EXP_BIAS) +#define RGB9E5_MANTISSA_VALUES (1<<RGB9E5_MANTISSA_BITS) +#define MAX_RGB9E5_MANTISSA (RGB9E5_MANTISSA_VALUES-1) +#define MAX_RGB9E5 (((float)MAX_RGB9E5_MANTISSA)/RGB9E5_MANTISSA_VALUES * (1<<MAX_RGB9E5_EXP)) + +static inline int rgb9e5_ClampRange(float x) +{ + union { float f; uint32_t u; } f, max; + f.f = x; + max.f = MAX_RGB9E5; + + if (f.u > 0x7f800000) + /* catches neg, NaNs */ + return 0; + else if (f.u >= max.u) + return max.u; + else + return f.u; +} + +static inline uint32_t float3_to_rgb9e5(const float rgb[3]) +{ + int rm, gm, bm, exp_shared; + uint32_t revdenom_biasedexp; + union { float f; uint32_t u; } rc, bc, gc, maxrgb, revdenom; + + rc.u = rgb9e5_ClampRange(rgb[0]); + gc.u = rgb9e5_ClampRange(rgb[1]); + bc.u = rgb9e5_ClampRange(rgb[2]); + maxrgb.u = MAX3(rc.u, gc.u, bc.u); + + /* + * Compared to what the spec suggests, instead of conditionally adjusting + * the exponent after the fact do it here by doing the equivalent of +0.5 - + * the int add will spill over into the exponent in this case. + */ + maxrgb.u += maxrgb.u & (1 << (23-9)); + exp_shared = MAX2((maxrgb.u >> 23), -RGB9E5_EXP_BIAS - 1 + 127) + + 1 + RGB9E5_EXP_BIAS - 127; + revdenom_biasedexp = 127 - (exp_shared - RGB9E5_EXP_BIAS - + RGB9E5_MANTISSA_BITS) + 1; + revdenom.u = revdenom_biasedexp << 23; + assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP); + + /* + * The spec uses strict round-up behavior (d3d10 disagrees, but in any case + * must match what is done above for figuring out exponent). + * We avoid the doubles ((int) rc * revdenom + 0.5) by doing the rounding + * ourselves (revdenom was adjusted by +1, above). + */ + rm = (int) (rc.f * revdenom.f); + gm = (int) (gc.f * revdenom.f); + bm = (int) (bc.f * revdenom.f); + rm = (rm & 1) + (rm >> 1); + gm = (gm & 1) + (gm >> 1); + bm = (bm & 1) + (bm >> 1); + + assert(rm <= MAX_RGB9E5_MANTISSA); + assert(gm <= MAX_RGB9E5_MANTISSA); + assert(bm <= MAX_RGB9E5_MANTISSA); + assert(rm >= 0); + assert(gm >= 0); + assert(bm >= 0); + + return (exp_shared << 27) | (bm << 18) | (gm << 9) | rm; +} + +static inline void rgb9e5_to_float3(uint32_t rgb, float retval[3]) +{ + int exponent; + union { float f; uint32_t u; } scale; + + exponent = (rgb >> 27) - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS; + scale.u = (exponent + 127) << 23; + + retval[0] = ( rgb & 0x1ff) * scale.f; + retval[1] = ((rgb >> 9) & 0x1ff) * scale.f; + retval[2] = ((rgb >> 18) & 0x1ff) * scale.f; +} + +#endif diff --git a/lib/mesa/src/util/hash_table.c b/lib/mesa/src/util/hash_table.c index 4cfe3d932..9e643af8b 100644 --- a/lib/mesa/src/util/hash_table.c +++ b/lib/mesa/src/util/hash_table.c @@ -295,6 +295,8 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, uint32_t start_hash_address, hash_address; struct hash_entry *available_entry = NULL; + assert(key != NULL); + if (ht->entries >= ht->max_entries) { _mesa_hash_table_rehash(ht, ht->size_index + 1); } else if (ht->deleted_entries + ht->entries >= ht->max_entries) { diff --git a/lib/mesa/src/util/hash_table.h b/lib/mesa/src/util/hash_table.h index c69abfa3e..b35ee871b 100644 --- a/lib/mesa/src/util/hash_table.h +++ b/lib/mesa/src/util/hash_table.h @@ -139,6 +139,19 @@ _mesa_fnv32_1a_accumulate_block(uint32_t hash, const void *data, size_t size) entry != NULL; \ entry = _mesa_hash_table_next_entry(ht, entry)) +static inline void +hash_table_call_foreach(struct hash_table *ht, + void (*callback)(const void *key, + void *data, + void *closure), + void *closure) +{ + struct hash_entry *entry; + + hash_table_foreach(ht, entry) + callback(entry->key, entry->data, closure); +} + #ifdef __cplusplus } /* extern C */ #endif diff --git a/lib/mesa/src/util/list.h b/lib/mesa/src/util/list.h index 066f9b8df..e8a99ac8e 100644 --- a/lib/mesa/src/util/list.h +++ b/lib/mesa/src/util/list.h @@ -71,12 +71,18 @@ static inline void list_addtail(struct list_head *item, struct list_head *list) list->prev = item; } +static inline bool list_empty(struct list_head *list); + static inline void list_replace(struct list_head *from, struct list_head *to) { - to->prev = from->prev; - to->next = from->next; - from->next->prev = to; - from->prev->next = to; + if (list_empty(from)) { + list_inithead(to); + } else { + to->prev = from->prev; + to->next = from->next; + from->next->prev = to; + from->prev->next = to; + } } static inline void list_del(struct list_head *item) @@ -116,6 +122,28 @@ static inline unsigned list_length(struct list_head *list) return length; } +static inline void list_splice(struct list_head *src, struct list_head *dst) +{ + if (list_empty(src)) + return; + + src->next->prev = dst; + src->prev->next = dst->next; + dst->next->prev = src->prev; + dst->next = src->next; +} + +static inline void list_splicetail(struct list_head *src, struct list_head *dst) +{ + if (list_empty(src)) + return; + + src->prev->next = dst; + src->next->prev = dst->prev; + dst->prev->next = src->next; + dst->prev = src->prev; +} + static inline void list_validate(struct list_head *list) { struct list_head *node; diff --git a/lib/mesa/src/util/macros.h b/lib/mesa/src/util/macros.h index 71bb15744..27d1b6292 100644 --- a/lib/mesa/src/util/macros.h +++ b/lib/mesa/src/util/macros.h @@ -26,6 +26,8 @@ #include <assert.h> +#include "c99_compat.h" + /* Compute the size of an array */ #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) @@ -152,6 +154,12 @@ do { \ #define ATTRIBUTE_PURE #endif +#ifdef HAVE_FUNC_ATTRIBUTE_RETURNS_NONNULL +#define ATTRIBUTE_RETURNS_NONNULL __attribute__((__returns_nonnull__)) +#else +#define ATTRIBUTE_RETURNS_NONNULL +#endif + #ifdef __cplusplus /** * Macro function that evaluates to true if T is a trivially @@ -204,13 +212,15 @@ do { \ #define UNUSED #endif +#define MAYBE_UNUSED UNUSED + #ifdef HAVE_FUNC_ATTRIBUTE_WARN_UNUSED_RESULT #define MUST_CHECK __attribute__((warn_unused_result)) #else #define MUST_CHECK #endif -#if defined(__GNUC__) || (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x590)) +#if defined(__GNUC__) #define ATTRIBUTE_NOINLINE __attribute__((noinline)) #else #define ATTRIBUTE_NOINLINE @@ -219,4 +229,17 @@ do { \ /** Compute ceiling of integer quotient of A divided by B. */ #define DIV_ROUND_UP( A, B ) ( (A) % (B) == 0 ? (A)/(B) : (A)/(B)+1 ) +/** Clamp X to [MIN,MAX] */ +#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) ) + +/** Minimum of two values: */ +#define MIN2( A, B ) ( (A)<(B) ? (A) : (B) ) + +/** Maximum of two values: */ +#define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) + +/** Minimum and maximum of three values: */ +#define MIN3( A, B, C ) ((A) < (B) ? MIN2(A, C) : MIN2(B, C)) +#define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) + #endif /* UTIL_MACROS_H */ diff --git a/lib/mesa/src/util/mesa-sha1.c b/lib/mesa/src/util/mesa-sha1.c index faa1c871b..b6a192f4d 100644 --- a/lib/mesa/src/util/mesa-sha1.c +++ b/lib/mesa/src/util/mesa-sha1.c @@ -175,21 +175,25 @@ _mesa_sha1_final(struct mesa_sha1 *ctx, unsigned char result[20]) #elif defined(HAVE_SHA1_IN_LIBGCRYPT) /* Use libgcrypt for SHA1 */ #include <gcrypt.h> +#include "c11/threads.h" + +static void _mesa_libgcrypt_init(void) +{ + if (!gcry_check_version(NULL)) + return; + + gcry_control(GCRYCTL_DISABLE_SECMEM, 0); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} struct mesa_sha1 * _mesa_sha1_init(void) { - static int init; + static once_flag flag = ONCE_FLAG_INIT; gcry_md_hd_t h; gcry_error_t err; - if (!init) { - if (!gcry_check_version(NULL)) - return NULL; - gcry_control(GCRYCTL_DISABLE_SECMEM, 0); - gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); - init = 1; - } + call_once(&flag, _mesa_libgcrypt_init); err = gcry_md_open(&h, GCRY_MD_SHA1, 0); if (err) diff --git a/lib/mesa/src/util/mesa-sha1.h b/lib/mesa/src/util/mesa-sha1.h index 1599405cd..0be5485f3 100644 --- a/lib/mesa/src/util/mesa-sha1.h +++ b/lib/mesa/src/util/mesa-sha1.h @@ -23,12 +23,12 @@ #ifndef SHA1_H #define SHA1_H +#include <stdlib.h> + #ifdef __cplusplus extern "C" { #endif -#include <stdlib.h> - struct mesa_sha1; struct mesa_sha1 * diff --git a/lib/mesa/src/util/ralloc.c b/lib/mesa/src/util/ralloc.c index 6d4032bd4..9526011b8 100644 --- a/lib/mesa/src/util/ralloc.c +++ b/lib/mesa/src/util/ralloc.c @@ -110,6 +110,18 @@ ralloc_context(const void *ctx) void * ralloc_size(const void *ctx, size_t size) { + /* ralloc_size was originally implemented using calloc, which meant some + * code accidentally relied on its zero filling behavior. + * + * TODO: Make ralloc_size not zero fill memory, and cleanup any code that + * should instead be using rzalloc. + */ + return rzalloc_size(ctx, size); +} + +void * +rzalloc_size(const void *ctx, size_t size) +{ void *block = calloc(1, size + sizeof(ralloc_header)); ralloc_header *info; ralloc_header *parent; @@ -128,15 +140,6 @@ ralloc_size(const void *ctx, size_t size) return PTR_FROM_HEADER(info); } -void * -rzalloc_size(const void *ctx, size_t size) -{ - void *ptr = ralloc_size(ctx, size); - if (likely(ptr != NULL)) - memset(ptr, 0, size); - return ptr; -} - /* helper function - assumes ptr != NULL */ static void * resize(void *ptr, size_t size) diff --git a/lib/mesa/src/util/rounding.h b/lib/mesa/src/util/rounding.h index afb38fbdb..dfc691eaf 100644 --- a/lib/mesa/src/util/rounding.h +++ b/lib/mesa/src/util/rounding.h @@ -29,7 +29,8 @@ #include <limits.h> #include <stdint.h> -#ifdef __x86_64__ +#if defined(__SSE__) || defined(_MSC_VER) +/* MSVC always has SSE nowadays */ #include <xmmintrin.h> #include <emmintrin.h> #endif @@ -95,7 +96,7 @@ _mesa_roundeven(double x) static inline long _mesa_lroundevenf(float x) { -#ifdef __x86_64__ +#if defined(__SSE__) || defined(_MSC_VER) #if LONG_MAX == INT64_MAX return _mm_cvtss_si64(_mm_load_ss(&x)); #elif LONG_MAX == INT32_MAX @@ -115,7 +116,7 @@ _mesa_lroundevenf(float x) static inline long _mesa_lroundeven(double x) { -#ifdef __x86_64__ +#if defined(__SSE__) || defined(_MSC_VER) #if LONG_MAX == INT64_MAX return _mm_cvtsd_si64(_mm_load_sd(&x)); #elif LONG_MAX == INT32_MAX diff --git a/lib/mesa/src/util/slab.c b/lib/mesa/src/util/slab.c new file mode 100644 index 000000000..4264814ca --- /dev/null +++ b/lib/mesa/src/util/slab.c @@ -0,0 +1,316 @@ +/* + * Copyright 2010 Marek Olšák <maraeo@gmail.com> + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#include "slab.h" +#include "macros.h" +#include "u_atomic.h" +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +#define ALIGN(value, align) (((value) + (align) - 1) & ~((align) - 1)) + +#define SLAB_MAGIC_ALLOCATED 0xcafe4321 +#define SLAB_MAGIC_FREE 0x7ee01234 + +#ifdef DEBUG +#define SET_MAGIC(element, value) (element)->magic = (value) +#define CHECK_MAGIC(element, value) assert((element)->magic == (value)) +#else +#define SET_MAGIC(element, value) +#define CHECK_MAGIC(element, value) +#endif + +/* One array element within a big buffer. */ +struct slab_element_header { + /* The next element in the free or migrated list. */ + struct slab_element_header *next; + + /* This is either + * - a pointer to the child pool to which this element belongs, or + * - a pointer to the orphaned page of the element, with the least + * significant bit set to 1. + */ + intptr_t owner; + +#ifdef DEBUG + intptr_t magic; +#endif +}; + +/* The page is an array of allocations in one block. */ +struct slab_page_header { + union { + /* Next page in the same child pool. */ + struct slab_page_header *next; + + /* Number of remaining, non-freed elements (for orphaned pages). */ + unsigned num_remaining; + } u; + /* Memory after the last member is dedicated to the page itself. + * The allocated size is always larger than this structure. + */ +}; + + +static struct slab_element_header * +slab_get_element(struct slab_parent_pool *parent, + struct slab_page_header *page, unsigned index) +{ + return (struct slab_element_header*) + ((uint8_t*)&page[1] + (parent->element_size * index)); +} + +/* The given object/element belongs to an orphaned page (i.e. the owning child + * pool has been destroyed). Mark the element as freed and free the whole page + * when no elements are left in it. + */ +static void +slab_free_orphaned(struct slab_element_header *elt) +{ + struct slab_page_header *page; + + assert(elt->owner & 1); + + page = (struct slab_page_header *)(elt->owner & ~(intptr_t)1); + if (!p_atomic_dec_return(&page->u.num_remaining)) + free(page); +} + +/** + * Create a parent pool for the allocation of same-sized objects. + * + * \param item_size Size of one object. + * \param num_items Number of objects to allocate at once. + */ +void +slab_create_parent(struct slab_parent_pool *parent, + unsigned item_size, + unsigned num_items) +{ + mtx_init(&parent->mutex, mtx_plain); + parent->element_size = ALIGN(sizeof(struct slab_element_header) + item_size, + sizeof(intptr_t)); + parent->num_elements = num_items; +} + +void +slab_destroy_parent(struct slab_parent_pool *parent) +{ + mtx_destroy(&parent->mutex); +} + +/** + * Create a child pool linked to the given parent. + */ +void slab_create_child(struct slab_child_pool *pool, + struct slab_parent_pool *parent) +{ + pool->parent = parent; + pool->pages = NULL; + pool->free = NULL; + pool->migrated = NULL; +} + +/** + * Destroy the child pool. + * + * Pages associated to the pool will be orphaned. They are eventually freed + * when all objects in them are freed. + */ +void slab_destroy_child(struct slab_child_pool *pool) +{ + mtx_lock(&pool->parent->mutex); + + while (pool->pages) { + struct slab_page_header *page = pool->pages; + pool->pages = page->u.next; + p_atomic_set(&page->u.num_remaining, pool->parent->num_elements); + + for (unsigned i = 0; i < pool->parent->num_elements; ++i) { + struct slab_element_header *elt = slab_get_element(pool->parent, page, i); + p_atomic_set(&elt->owner, (intptr_t)page | 1); + } + } + + while (pool->migrated) { + struct slab_element_header *elt = pool->migrated; + pool->migrated = elt->next; + slab_free_orphaned(elt); + } + + mtx_unlock(&pool->parent->mutex); + + while (pool->free) { + struct slab_element_header *elt = pool->free; + pool->free = elt->next; + slab_free_orphaned(elt); + } + + /* Guard against use-after-free. */ + pool->parent = NULL; +} + +static bool +slab_add_new_page(struct slab_child_pool *pool) +{ + struct slab_page_header *page = malloc(sizeof(struct slab_page_header) + + pool->parent->num_elements * pool->parent->element_size); + + if (!page) + return false; + + for (unsigned i = 0; i < pool->parent->num_elements; ++i) { + struct slab_element_header *elt = slab_get_element(pool->parent, page, i); + elt->owner = (intptr_t)pool; + assert(!(elt->owner & 1)); + + elt->next = pool->free; + pool->free = elt; + SET_MAGIC(elt, SLAB_MAGIC_FREE); + } + + page->u.next = pool->pages; + pool->pages = page; + + return true; +} + +/** + * Allocate an object from the child pool. Single-threaded (i.e. the caller + * must ensure that no operation happens on the same child pool in another + * thread). + */ +void * +slab_alloc(struct slab_child_pool *pool) +{ + struct slab_element_header *elt; + + if (!pool->free) { + /* First, collect elements that belong to us but were freed from a + * different child pool. + */ + mtx_lock(&pool->parent->mutex); + pool->free = pool->migrated; + pool->migrated = NULL; + mtx_unlock(&pool->parent->mutex); + + /* Now allocate a new page. */ + if (!pool->free && !slab_add_new_page(pool)) + return NULL; + } + + elt = pool->free; + pool->free = elt->next; + + CHECK_MAGIC(elt, SLAB_MAGIC_FREE); + SET_MAGIC(elt, SLAB_MAGIC_ALLOCATED); + + return &elt[1]; +} + +/** + * Free an object allocated from the slab. Single-threaded (i.e. the caller + * must ensure that no operation happens on the same child pool in another + * thread). + * + * Freeing an object in a different child pool from the one where it was + * allocated is allowed, as long the pool belong to the same parent. No + * additional locking is required in this case. + */ +void slab_free(struct slab_child_pool *pool, void *ptr) +{ + struct slab_element_header *elt = ((struct slab_element_header*)ptr - 1); + intptr_t owner_int; + + CHECK_MAGIC(elt, SLAB_MAGIC_ALLOCATED); + SET_MAGIC(elt, SLAB_MAGIC_FREE); + + if (p_atomic_read(&elt->owner) == (intptr_t)pool) { + /* This is the simple case: The caller guarantees that we can safely + * access the free list. + */ + elt->next = pool->free; + pool->free = elt; + return; + } + + /* The slow case: migration or an orphaned page. */ + mtx_lock(&pool->parent->mutex); + + /* Note: we _must_ re-read elt->owner here because the owning child pool + * may have been destroyed by another thread in the meantime. + */ + owner_int = p_atomic_read(&elt->owner); + + if (!(owner_int & 1)) { + struct slab_child_pool *owner = (struct slab_child_pool *)owner_int; + elt->next = owner->migrated; + owner->migrated = elt; + mtx_unlock(&pool->parent->mutex); + } else { + mtx_unlock(&pool->parent->mutex); + + slab_free_orphaned(elt); + } +} + +/** + * Allocate an object from the slab. Single-threaded (no mutex). + */ +void * +slab_alloc_st(struct slab_mempool *pool) +{ + return slab_alloc(&pool->child); +} + +/** + * Free an object allocated from the slab. Single-threaded (no mutex). + */ +void +slab_free_st(struct slab_mempool *pool, void *ptr) +{ + slab_free(&pool->child, ptr); +} + +void +slab_destroy(struct slab_mempool *pool) +{ + slab_destroy_child(&pool->child); + slab_destroy_parent(&pool->parent); +} + +/** + * Create an allocator for same-sized objects. + * + * \param item_size Size of one object. + * \param num_items Number of objects to allocate at once. + */ +void +slab_create(struct slab_mempool *pool, + unsigned item_size, + unsigned num_items) +{ + slab_create_parent(&pool->parent, item_size, num_items); + slab_create_child(&pool->child, &pool->parent); +} diff --git a/lib/mesa/src/util/slab.h b/lib/mesa/src/util/slab.h new file mode 100644 index 000000000..e83f8ec1a --- /dev/null +++ b/lib/mesa/src/util/slab.h @@ -0,0 +1,94 @@ +/* + * Copyright 2010 Marek Olšák <maraeo@gmail.com> + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * on the rights to use, copy, modify, merge, publish, distribute, sub + * license, and/or sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE + * USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +/** + * Slab allocator for equally sized memory allocations. + * + * Objects are allocated from "child" pools that are connected to a "parent" + * pool. + * + * Calls to slab_alloc/slab_free for the same child pool must not occur from + * multiple threads simultaneously. + * + * Allocations obtained from one child pool should usually be freed in the + * same child pool. Freeing an allocation in a different child pool associated + * to the same parent is allowed (and requires no locking by the caller), but + * it is discouraged because it implies a performance penalty. + * + * For convenience and to ease the transition, there is also a set of wrapper + * functions around a single parent-child pair. + */ + +#ifndef SLAB_H +#define SLAB_H + +#include "c11/threads.h" + +struct slab_element_header; +struct slab_page_header; + +struct slab_parent_pool { + mtx_t mutex; + unsigned element_size; + unsigned num_elements; +}; + +struct slab_child_pool { + struct slab_parent_pool *parent; + + struct slab_page_header *pages; + + /* Free elements. */ + struct slab_element_header *free; + + /* Elements that are owned by this pool but were freed with a different + * pool as the argument to slab_free. + * + * This list is protected by the parent mutex. + */ + struct slab_element_header *migrated; +}; + +void slab_create_parent(struct slab_parent_pool *parent, + unsigned item_size, + unsigned num_items); +void slab_destroy_parent(struct slab_parent_pool *parent); +void slab_create_child(struct slab_child_pool *pool, + struct slab_parent_pool *parent); +void slab_destroy_child(struct slab_child_pool *pool); +void *slab_alloc(struct slab_child_pool *pool); +void slab_free(struct slab_child_pool *pool, void *ptr); + +struct slab_mempool { + struct slab_parent_pool parent; + struct slab_child_pool child; +}; + +void slab_create(struct slab_mempool *pool, + unsigned item_size, + unsigned num_items); +void slab_destroy(struct slab_mempool *pool); +void *slab_alloc_st(struct slab_mempool *pool); +void slab_free_st(struct slab_mempool *pool, void *ptr); + +#endif diff --git a/lib/mesa/src/util/string_to_uint_map.cpp b/lib/mesa/src/util/string_to_uint_map.cpp new file mode 100644 index 000000000..35fb76bf7 --- /dev/null +++ b/lib/mesa/src/util/string_to_uint_map.cpp @@ -0,0 +1,42 @@ +/* + * Copyright © 2011 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/** + * \file string_to_uint_map.cpp + * \brief Dumb wrapprs so that C code can create and destroy maps. + * + * \author Ian Romanick <ian.d.romanick@intel.com> + */ +#include "string_to_uint_map.h" + +extern "C" struct string_to_uint_map * +string_to_uint_map_ctor() +{ + return new string_to_uint_map; +} + +extern "C" void +string_to_uint_map_dtor(struct string_to_uint_map *map) +{ + delete map; +} diff --git a/lib/mesa/src/util/string_to_uint_map.h b/lib/mesa/src/util/string_to_uint_map.h new file mode 100644 index 000000000..e0533ec6e --- /dev/null +++ b/lib/mesa/src/util/string_to_uint_map.h @@ -0,0 +1,177 @@ +/* + * Copyright © 2008 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + */ + +#ifndef STRING_TO_UINT_MAP_H +#define STRING_TO_UINT_MAP_H + +#include <string.h> +#include <limits.h> +#include "util/hash_table.h" + +struct string_to_uint_map; + +#ifdef __cplusplus +extern "C" { +#endif + +struct string_to_uint_map * +string_to_uint_map_ctor(); + +void +string_to_uint_map_dtor(struct string_to_uint_map *); + + +#ifdef __cplusplus +} + +struct string_map_iterate_wrapper_closure { + void (*callback)(const char *key, unsigned value, void *closure); + void *closure; +}; + +/** + * Map from a string (name) to an unsigned integer value + * + * \note + * Because of the way this class interacts with the \c hash_table + * implementation, values of \c UINT_MAX cannot be stored in the map. + */ +struct string_to_uint_map { +public: + string_to_uint_map() + { + this->ht = _mesa_hash_table_create(NULL, _mesa_key_hash_string, + _mesa_key_string_equal); + } + + ~string_to_uint_map() + { + hash_table_call_foreach(this->ht, delete_key, NULL); + _mesa_hash_table_destroy(this->ht, NULL); + } + + /** + * Remove all mappings from this map. + */ + void clear() + { + hash_table_call_foreach(this->ht, delete_key, NULL); + _mesa_hash_table_clear(this->ht, NULL); + } + + /** + * Runs a passed callback for the hash + */ + void iterate(void (*func)(const char *, unsigned, void *), void *closure) + { + struct string_map_iterate_wrapper_closure *wrapper; + + wrapper = (struct string_map_iterate_wrapper_closure *) + malloc(sizeof(struct string_map_iterate_wrapper_closure)); + if (wrapper == NULL) + return; + + wrapper->callback = func; + wrapper->closure = closure; + + hash_table_call_foreach(this->ht, subtract_one_wrapper, wrapper); + free(wrapper); + } + + /** + * Get the value associated with a particular key + * + * \return + * If \c key is found in the map, \c true is returned. Otherwise \c false + * is returned. + * + * \note + * If \c key is not found in the table, \c value is not modified. + */ + bool get(unsigned &value, const char *key) + { + hash_entry *entry = _mesa_hash_table_search(this->ht, + (const void *) key); + + if (!entry) + return false; + + const intptr_t v = (intptr_t) entry->data; + value = (unsigned)(v - 1); + return true; + } + + void put(unsigned value, const char *key) + { + /* The low-level hash table structure returns NULL if key is not in the + * hash table. However, users of this map might want to store zero as a + * valid value in the table. Bias the value by +1 so that a + * user-specified zero is stored as 1. This enables ::get to tell the + * difference between a user-specified zero (returned as 1 by + * _mesa_hash_table_search) and the key not in the table (returned as 0 by + * _mesa_hash_table_search). + * + * The net effect is that we can't store UINT_MAX in the table. This is + * because UINT_MAX+1 = 0. + */ + assert(value != UINT_MAX); + char *dup_key = strdup(key); + + struct hash_entry *entry = _mesa_hash_table_search(this->ht, dup_key); + if (entry) { + entry->data = (void *) (intptr_t) (value + 1); + } else { + _mesa_hash_table_insert(this->ht, dup_key, + (void *) (intptr_t) (value + 1)); + } + + if (entry) + free(dup_key); + } + +private: + static void delete_key(const void *key, void *data, void *closure) + { + (void) data; + (void) closure; + + free((char *)key); + } + + static void subtract_one_wrapper(const void *key, void *data, void *closure) + { + struct string_map_iterate_wrapper_closure *wrapper = + (struct string_map_iterate_wrapper_closure *) closure; + unsigned value = (intptr_t) data; + + value -= 1; + + wrapper->callback((const char *) key, value, wrapper->closure); + } + + struct hash_table *ht; +}; + +#endif /* __cplusplus */ +#endif /* STRING_TO_UINT_MAP_H */ diff --git a/lib/mesa/src/util/u_endian.h b/lib/mesa/src/util/u_endian.h new file mode 100644 index 000000000..b9d563dd4 --- /dev/null +++ b/lib/mesa/src/util/u_endian.h @@ -0,0 +1,69 @@ +/************************************************************************** + * + * Copyright 2007-2008 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ +#ifndef U_ENDIAN_H +#define U_ENDIAN_H + +#if defined(__GLIBC__) || defined(ANDROID) +#include <endian.h> + +#if __BYTE_ORDER == __LITTLE_ENDIAN +# define PIPE_ARCH_LITTLE_ENDIAN +#elif __BYTE_ORDER == __BIG_ENDIAN +# define PIPE_ARCH_BIG_ENDIAN +#endif + +#elif defined(__APPLE__) +#include <machine/endian.h> + +#if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN +# define PIPE_ARCH_LITTLE_ENDIAN +#elif __DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN +# define PIPE_ARCH_BIG_ENDIAN +#endif + +#elif defined(__sun) +#include <sys/isa_defs.h> + +#if defined(_LITTLE_ENDIAN) +# define PIPE_ARCH_LITTLE_ENDIAN +#elif defined(_BIG_ENDIAN) +# define PIPE_ARCH_BIG_ENDIAN +#endif + +#elif defined(__OpenBSD__) || defined(__NetBSD__) +#include <sys/types.h> +#include <machine/endian.h> + +#if _BYTE_ORDER == _LITTLE_ENDIAN +# define PIPE_ARCH_LITTLE_ENDIAN +#elif _BYTE_ORDER == _BIG_ENDIAN +# define PIPE_ARCH_BIG_ENDIAN +#endif + +#endif + +#endif diff --git a/lib/mesa/src/util/u_vector.c b/lib/mesa/src/util/u_vector.c new file mode 100644 index 000000000..37c4245eb --- /dev/null +++ b/lib/mesa/src/util/u_vector.c @@ -0,0 +1,98 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#include "util/u_vector.h" + +int +u_vector_init(struct u_vector *vector, uint32_t element_size, uint32_t size) +{ + assert(util_is_power_of_two(size)); + assert(element_size < size && util_is_power_of_two(element_size)); + + vector->head = 0; + vector->tail = 0; + vector->element_size = element_size; + vector->size = size; + vector->data = malloc(size); + + return vector->data != NULL; +} + +void * +u_vector_add(struct u_vector *vector) +{ + uint32_t offset, size, split, src_tail, dst_tail; + void *data; + + if (vector->head - vector->tail == vector->size) { + size = vector->size * 2; + data = malloc(size); + if (data == NULL) + return NULL; + src_tail = vector->tail & (vector->size - 1); + dst_tail = vector->tail & (size - 1); + if (src_tail == 0) { + /* Since we know that the vector is full, this means that it's + * linear from start to end so we can do one copy. + */ + memcpy((char *)data + dst_tail, vector->data, vector->size); + } else { + /* In this case, the vector is split into two pieces and we have + * to do two copies. We have to be careful to make sure each + * piece goes to the right locations. Thanks to the change in + * size, it may or may not still wrap around. + */ + split = u_align_u32(vector->tail, vector->size); + assert(vector->tail <= split && split < vector->head); + memcpy((char *)data + dst_tail, (char *)vector->data + src_tail, + split - vector->tail); + memcpy((char *)data + (split & (size - 1)), vector->data, + vector->head - split); + } + free(vector->data); + vector->data = data; + vector->size = size; + } + + assert(vector->head - vector->tail < vector->size); + + offset = vector->head & (vector->size - 1); + vector->head += vector->element_size; + + return (char *)vector->data + offset; +} + +void * +u_vector_remove(struct u_vector *vector) +{ + uint32_t offset; + + if (vector->head == vector->tail) + return NULL; + + assert(vector->head - vector->tail <= vector->size); + + offset = vector->tail & (vector->size - 1); + vector->tail += vector->element_size; + + return (char *)vector->data + offset; +} diff --git a/lib/mesa/src/util/u_vector.h b/lib/mesa/src/util/u_vector.h new file mode 100644 index 000000000..8fa4ec483 --- /dev/null +++ b/lib/mesa/src/util/u_vector.h @@ -0,0 +1,92 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +/* + * u_vector is a vector based queue for storing arbitrary + * sized arrays of objects without using a linked list. + */ + +#ifndef U_VECTOR_H +#define U_VECTOR_H + +#include <stdint.h> +#include <stdlib.h> +#include "util/u_math.h" +#include "util/macros.h" + +/* TODO - move to u_math.h - name it better etc */ +static inline uint32_t +u_align_u32(uint32_t v, uint32_t a) +{ + assert(a != 0 && a == (a & -a)); + return (v + a - 1) & ~(a - 1); +} + +struct u_vector { + uint32_t head; + uint32_t tail; + uint32_t element_size; + uint32_t size; + void *data; +}; + +int u_vector_init(struct u_vector *queue, uint32_t element_size, uint32_t size); +void *u_vector_add(struct u_vector *queue); +void *u_vector_remove(struct u_vector *queue); + +static inline int +u_vector_length(struct u_vector *queue) +{ + return (queue->head - queue->tail) / queue->element_size; +} + +static inline void * +u_vector_head(struct u_vector *vector) +{ + assert(vector->tail < vector->head); + return (void *)((char *)vector->data + + ((vector->head - vector->element_size) & + (vector->size - 1))); +} + +static inline void * +u_vector_tail(struct u_vector *vector) +{ + return (void *)((char *)vector->data + (vector->tail & (vector->size - 1))); +} + +static inline void +u_vector_finish(struct u_vector *queue) +{ + free(queue->data); +} + +#define u_vector_foreach(elem, queue) \ + static_assert(__builtin_types_compatible_p(__typeof__(queue), struct u_vector *), ""); \ + for (uint32_t __u_vector_offset = (queue)->tail; \ + elem = (queue)->data + (__u_vector_offset & ((queue)->size - 1)), __u_vector_offset < (queue)->head; \ + __u_vector_offset += (queue)->element_size) + + +#endif + diff --git a/lib/mesa/src/util/vk_alloc.h b/lib/mesa/src/util/vk_alloc.h new file mode 100644 index 000000000..a8e21cade --- /dev/null +++ b/lib/mesa/src/util/vk_alloc.h @@ -0,0 +1,75 @@ +/* + * Copyright © 2015 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ +#ifndef VK_ALLOC_H +#define VK_ALLOC_H + +/* common allocation inlines for vulkan drivers */ + +#include <vulkan/vulkan.h> + +static inline void * +vk_alloc(const VkAllocationCallbacks *alloc, + size_t size, size_t align, + VkSystemAllocationScope scope) +{ + return alloc->pfnAllocation(alloc->pUserData, size, align, scope); +} + +static inline void * +vk_realloc(const VkAllocationCallbacks *alloc, + void *ptr, size_t size, size_t align, + VkSystemAllocationScope scope) +{ + return alloc->pfnReallocation(alloc->pUserData, ptr, size, align, scope); +} + +static inline void +vk_free(const VkAllocationCallbacks *alloc, void *data) +{ + alloc->pfnFree(alloc->pUserData, data); +} + +static inline void * +vk_alloc2(const VkAllocationCallbacks *parent_alloc, + const VkAllocationCallbacks *alloc, + size_t size, size_t align, + VkSystemAllocationScope scope) +{ + if (alloc) + return vk_alloc(alloc, size, align, scope); + else + return vk_alloc(parent_alloc, size, align, scope); +} + +static inline void +vk_free2(const VkAllocationCallbacks *parent_alloc, + const VkAllocationCallbacks *alloc, + void *data) +{ + if (alloc) + vk_free(alloc, data); + else + vk_free(parent_alloc, data); +} + +#endif |