diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2024-04-02 10:42:24 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2024-04-02 10:42:24 +0000 |
commit | a3f73acb9d2cdc62692af7ff93c51f910dff2d0d (patch) | |
tree | 303d205e8e6ed9676bdcbe006a402c23bf668f6c /lib/mesa/src/util | |
parent | f54e142455cb3c9d1662dae7e096a32a47e5409b (diff) |
Merge Mesa 23.3.6
Diffstat (limited to 'lib/mesa/src/util')
28 files changed, 879 insertions, 989 deletions
diff --git a/lib/mesa/src/util/bitscan.h b/lib/mesa/src/util/bitscan.h index 53cbb91e9..3da2e9639 100644 --- a/lib/mesa/src/util/bitscan.h +++ b/lib/mesa/src/util/bitscan.h @@ -42,6 +42,8 @@ #include <popcntintrin.h> #endif +#include "macros.h" + #ifdef __cplusplus extern "C" { #endif @@ -120,15 +122,15 @@ u_bit_scan64(uint64_t *mask) ((b) = ffsll(__dword) - 1, __dword); \ __dword &= ~(1ull << (b))) -/* Determine if an unsigned value is a power of two. +/* Determine if an uint32_t value is a power of two. * * \note * Zero is treated as a power of two. */ static inline bool -util_is_power_of_two_or_zero(unsigned v) +util_is_power_of_two_or_zero(uint32_t v) { - return (v & (v - 1)) == 0; + return IS_POT(v); } /* Determine if an uint64_t value is a power of two. @@ -139,16 +141,16 @@ util_is_power_of_two_or_zero(unsigned v) static inline bool util_is_power_of_two_or_zero64(uint64_t v) { - return (v & (v - 1)) == 0; + return IS_POT(v); } -/* Determine if an unsigned value is a power of two. +/* Determine if an uint32_t value is a power of two. * * \note * Zero is \b not treated as a power of two. */ static inline bool -util_is_power_of_two_nonzero(unsigned v) +util_is_power_of_two_nonzero(uint32_t v) { /* __POPCNT__ is different from HAVE___BUILTIN_POPCOUNT. The latter * indicates the existence of the __builtin_popcount function. The former @@ -162,10 +164,21 @@ util_is_power_of_two_nonzero(unsigned v) #ifdef __POPCNT__ return _mm_popcnt_u32(v) == 1; #else - return v != 0 && (v & (v - 1)) == 0; + return v != 0 && IS_POT(v); #endif } +/* Determine if an uint64_t value is a power of two. + * + * \note + * Zero is \b not treated as a power of two. + */ +static inline bool +util_is_power_of_two_nonzero64(uint64_t v) +{ + return v != 0 && IS_POT(v); +} + /* For looping over a bitmask when you want to loop over consecutive bits * manually, for example: * diff --git a/lib/mesa/src/util/compiler.h b/lib/mesa/src/util/compiler.h index 20190cbf1..906c36feb 100644 --- a/lib/mesa/src/util/compiler.h +++ b/lib/mesa/src/util/compiler.h @@ -35,10 +35,16 @@ #include <assert.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include "util/detect.h" #include "util/macros.h" -#include "util/u_endian.h" -#include "util/detect_arch.h" /** * Define CPU_TO_LE32 @@ -101,4 +107,18 @@ #define FALLTHROUGH do { } while(0) #endif +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__HAIKU__) && !defined(__USE_MISC) +#if !DETECT_OS_ANDROID +typedef unsigned int uint; +#endif +#endif + +#if defined(__cplusplus) +} +#endif + #endif /* COMPILER_H */ diff --git a/lib/mesa/src/util/disk_cache.c b/lib/mesa/src/util/disk_cache.c index c4872e59e..1d23b92af 100644 --- a/lib/mesa/src/util/disk_cache.c +++ b/lib/mesa/src/util/disk_cache.c @@ -87,7 +87,6 @@ disk_cache_init_queue(struct disk_cache *cache) * doesn't stall. */ return util_queue_init(&cache->cache_queue, "disk$", 32, 4, - UTIL_QUEUE_INIT_SCALE_THREADS | UTIL_QUEUE_INIT_RESIZE_IF_FULL | UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY | UTIL_QUEUE_INIT_SET_FULL_THREAD_AFFINITY, NULL); @@ -107,9 +106,6 @@ disk_cache_type_create(const char *gpu_name, uint8_t cache_version = CACHE_VERSION; size_t cv_size = sizeof(cache_version); - if (!disk_cache_enabled()) - return NULL; - /* A ralloc context for transient data during this invocation. */ local = ralloc_context(NULL); if (local == NULL) @@ -123,13 +119,8 @@ disk_cache_type_create(const char *gpu_name, cache->path_init_failed = true; cache->type = DISK_CACHE_NONE; -#ifdef ANDROID - /* Android needs the "disk cache" to be enabled for - * EGL_ANDROID_blob_cache's callbacks to be called, but it doesn't actually - * want any storing to disk to happen inside of the driver. - */ - goto path_fail; -#endif + if (!disk_cache_enabled()) + goto path_fail; char *path = disk_cache_generate_cache_dir(local, gpu_name, driver_id, cache_type); @@ -445,7 +436,7 @@ cache_put(void *job, void *gdata, int thread_index) disk_cache_write_item_to_disk_foz(dc_job); } else if (dc_job->cache->type == DISK_CACHE_DATABASE) { disk_cache_db_write_item_to_disk(dc_job); - } else { + } else if (dc_job->cache->type == DISK_CACHE_MULTI_FILE) { filename = disk_cache_get_cache_filename(dc_job->cache, dc_job->key); if (filename == NULL) goto done; @@ -482,17 +473,17 @@ blob_put_compressed(struct disk_cache *cache, const cache_key key, entry->uncompressed_size = size; - MESA_TRACE_BEGIN("deflate"); size_t compressed_size = util_compress_deflate(data, size, entry->compressed_data, max_buf); - MESA_TRACE_END(); if (!compressed_size) goto out; unsigned entry_size = compressed_size + sizeof(*entry); - MESA_TRACE_BEGIN("blob_put"); - cache->blob_put_cb(key, CACHE_KEY_SIZE, entry, entry_size); - MESA_TRACE_END(); + // The curly brackets are here to only trace the blob_put_cb call + { + MESA_TRACE_SCOPE("blob_put"); + cache->blob_put_cb(key, CACHE_KEY_SIZE, entry, entry_size); + } out: free(entry); @@ -512,10 +503,12 @@ blob_get_compressed(struct disk_cache *cache, const cache_key key, if (!entry) return NULL; - MESA_TRACE_BEGIN("blob_get"); - signed long entry_size = - cache->blob_get_cb(key, CACHE_KEY_SIZE, entry, max_blob_size); - MESA_TRACE_END(); + signed long entry_size; + // The curly brackets are here to only trace the blob_get_cb call + { + MESA_TRACE_SCOPE("blob_get"); + entry_size = cache->blob_get_cb(key, CACHE_KEY_SIZE, entry, max_blob_size); + } if (!entry_size) { free(entry); @@ -529,10 +522,8 @@ blob_get_compressed(struct disk_cache *cache, const cache_key key, } unsigned compressed_size = entry_size - sizeof(*entry); - MESA_TRACE_BEGIN("inflate"); bool ret = util_compress_inflate(entry->compressed_data, compressed_size, data, entry->uncompressed_size); - MESA_TRACE_END(); if (!ret) { free(data); free(entry); @@ -603,7 +594,7 @@ disk_cache_get(struct disk_cache *cache, const cache_key key, size_t *size) buf = disk_cache_load_item_foz(cache, key, size); } else if (cache->type == DISK_CACHE_DATABASE) { buf = disk_cache_db_load_item(cache, key, size); - } else { + } else if (cache->type == DISK_CACHE_MULTI_FILE) { char *filename = disk_cache_get_cache_filename(cache, key); if (filename) buf = disk_cache_load_item(cache, filename, size); diff --git a/lib/mesa/src/util/disk_cache.h b/lib/mesa/src/util/disk_cache.h index 5cb3b6a94..76a46f7ea 100644 --- a/lib/mesa/src/util/disk_cache.h +++ b/lib/mesa/src/util/disk_cache.h @@ -79,21 +79,6 @@ struct cache_item_metadata { struct disk_cache; -static inline char * -disk_cache_format_hex_id(char *buf, const uint8_t *hex_id, unsigned size) -{ - static const char hex_digits[] = "0123456789abcdef"; - unsigned i; - - for (i = 0; i < size; i += 2) { - buf[i] = hex_digits[hex_id[i >> 1] >> 4]; - buf[i + 1] = hex_digits[hex_id[i >> 1] & 0x0f]; - } - buf[i] = '\0'; - - return buf; -} - #ifdef HAVE_DLADDR static inline bool disk_cache_get_function_timestamp(void *ptr, uint32_t* timestamp) diff --git a/lib/mesa/src/util/hash_table.c b/lib/mesa/src/util/hash_table.c index dc00b2de8..a76ebbc03 100644 --- a/lib/mesa/src/util/hash_table.c +++ b/lib/mesa/src/util/hash_table.c @@ -427,8 +427,7 @@ _mesa_hash_table_rehash(struct hash_table *ht, unsigned new_size_index) } static struct hash_entry * -hash_table_insert(struct hash_table *ht, uint32_t hash, - const void *key, void *data) +hash_table_get_entry(struct hash_table *ht, uint32_t hash, const void *key) { struct hash_entry *available_entry = NULL; @@ -469,11 +468,8 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, */ if (!entry_is_deleted(ht, entry) && entry->hash == hash && - ht->key_equals_function(key, entry->key)) { - entry->key = key; - entry->data = data; + ht->key_equals_function(key, entry->key)) return entry; - } hash_address += double_hash; if (hash_address >= size) @@ -484,8 +480,6 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, if (entry_is_deleted(ht, available_entry)) ht->deleted_entries--; available_entry->hash = hash; - available_entry->key = key; - available_entry->data = data; ht->entries++; return available_entry; } @@ -496,6 +490,20 @@ hash_table_insert(struct hash_table *ht, uint32_t hash, return NULL; } +static struct hash_entry * +hash_table_insert(struct hash_table *ht, uint32_t hash, + const void *key, void *data) +{ + struct hash_entry *entry = hash_table_get_entry(ht, hash, key); + + if (entry) { + entry->key = key; + entry->data = data; + } + + return entry; +} + /** * Inserts the key with the given hash into the table. * @@ -769,6 +777,13 @@ key_u64_equals(const void *a, const void *b) #define FREED_KEY_VALUE 0 +static void _mesa_hash_table_u64_delete_keys(void *data) +{ + struct hash_table_u64 *ht = ralloc_parent(data); + + _mesa_hash_table_u64_clear(ht); +} + struct hash_table_u64 * _mesa_hash_table_u64_create(void *mem_ctx) { @@ -785,6 +800,31 @@ _mesa_hash_table_u64_create(void *mem_ctx) } else { ht->table = _mesa_hash_table_create(ht, key_u64_hash, key_u64_equals); + + /* Allocate a ralloc sub-context which takes the u64 hash table + * as a parent and attach a destructor to it so we can free the + * hash_key_u64 objects that were allocated by + * _mesa_hash_table_u64_insert(). + * + * The order of creation of this sub-context is crucial: it needs + * to happen after the _mesa_hash_table_create() call to guarantee + * that the destructor is called before ht->table and its children + * are freed, otherwise the _mesa_hash_table_u64_clear() call in the + * destructor leads to a use-after-free situation. + */ + if (ht->table) { + void *dummy_ctx = ralloc_context(ht); + + /* If we can't allocate a sub-context, free the hash table + * immediately and return NULL to avoid future leaks. + */ + if (!dummy_ctx) { + ralloc_free(ht); + return NULL; + } + + ralloc_set_destructor(dummy_ctx, _mesa_hash_table_u64_delete_keys); + } } if (ht->table) @@ -802,7 +842,7 @@ _mesa_hash_table_u64_delete_key(struct hash_entry *entry) struct hash_key_u64 *_key = (struct hash_key_u64 *)entry->key; if (_key) - free(_key); + FREE(_key); } void @@ -847,7 +887,19 @@ _mesa_hash_table_u64_insert(struct hash_table_u64 *ht, uint64_t key, return; _key->value = key; - _mesa_hash_table_insert(ht->table, _key, data); + struct hash_entry *entry = + hash_table_get_entry(ht->table, key_u64_hash(_key), _key); + + if (!entry) { + FREE(_key); + return; + } + + entry->data = data; + if (!entry_is_present(ht->table, entry)) + entry->key = _key; + else + FREE(_key); } } @@ -905,6 +957,6 @@ _mesa_hash_table_u64_remove(struct hash_table_u64 *ht, uint64_t key) struct hash_key *_key = (struct hash_key *)entry->key; _mesa_hash_table_remove(ht->table, entry); - free(_key); + FREE(_key); } } diff --git a/lib/mesa/src/util/macros.h b/lib/mesa/src/util/macros.h index 580fc8dcc..cfcda53ac 100644 --- a/lib/mesa/src/util/macros.h +++ b/lib/mesa/src/util/macros.h @@ -122,17 +122,17 @@ #if defined(HAVE___BUILTIN_UNREACHABLE) || __has_builtin(__builtin_unreachable) #define unreachable(str) \ do { \ - assert(!str); \ + assert(!"" str); \ __builtin_unreachable(); \ } while (0) #elif defined (_MSC_VER) #define unreachable(str) \ do { \ - assert(!str); \ + assert(!"" str); \ __assume(0); \ } while (0) #else -#define unreachable(str) assert(!str) +#define unreachable(str) assert(!"" str) #endif /** @@ -204,9 +204,15 @@ do { \ * packed, to trade off performance for space. */ #ifdef HAVE_FUNC_ATTRIBUTE_PACKED -#define PACKED __attribute__((__packed__)) +# if defined(__MINGW32__) || defined(__MINGW64__) +# define PACKED __attribute__((gcc_struct,__packed__)) +# else +# define PACKED __attribute__((__packed__)) +# endif +# define ENUM_PACKED __attribute__((packed)) #else #define PACKED +#define ENUM_PACKED #endif /* Attribute pure is used for functions that have no effects other than their @@ -344,7 +350,11 @@ do { \ /** Compute ceiling of integer quotient of A divided by B. */ #define DIV_ROUND_UP( A, B ) ( ((A) + (B) - 1) / (B) ) -/** Clamp X to [MIN,MAX]. Turn NaN into MIN, arbitrarily. */ +/** + * Clamp X to [MIN, MAX]. + * This is a macro to allow float, int, unsigned, etc. types. + * We arbitrarily turn NaN into MIN. + */ #define CLAMP( X, MIN, MAX ) ( (X)>(MIN) ? ((X)>(MAX) ? (MAX) : (X)) : (MIN) ) /* Syntax sugar occuring frequently in graphics code */ @@ -356,10 +366,18 @@ do { \ /** Maximum of two values: */ #define MAX2( A, B ) ( (A)>(B) ? (A) : (B) ) -/** Minimum and maximum of three values: */ +/** Minimum of three values: */ #define MIN3( A, B, C ) ((A) < (B) ? MIN2(A, C) : MIN2(B, C)) + +/** Maximum of three values: */ #define MAX3( A, B, C ) ((A) > (B) ? MAX2(A, C) : MAX2(B, C)) +/** Minimum of four values: */ +#define MIN4( A, B, C, D ) ((A) < (B) ? MIN3(A, C, D) : MIN3(B, C, D)) + +/** Maximum of four values: */ +#define MAX4( A, B, C, D ) ((A) > (B) ? MAX3(A, C, D) : MAX3(B, C, D)) + /** Align a value to a power of two */ #define ALIGN_POT(x, pot_align) (((x) + (pot_align) - 1) & ~((pot_align) - 1)) @@ -370,7 +388,7 @@ do { \ #define BITFIELD_BIT(b) (1u << (b)) /** Set all bits up to excluding bit b */ #define BITFIELD_MASK(b) \ - ((b) == 32 ? (~0u) : BITFIELD_BIT((b) % 32) - 1) + ((b) == 32 ? (~0u) : BITFIELD_BIT((b) & 31) - 1) /** Set count bits starting from bit b */ #define BITFIELD_RANGE(b, count) \ (BITFIELD_MASK((b) + (count)) & ~BITFIELD_MASK(b)) @@ -379,7 +397,7 @@ do { \ #define BITFIELD64_BIT(b) (1ull << (b)) /** Set all bits up to excluding bit b */ #define BITFIELD64_MASK(b) \ - ((b) == 64 ? (~0ull) : BITFIELD64_BIT(b) - 1) + ((b) == 64 ? (~0ull) : BITFIELD64_BIT((b) & 63) - 1) /** Set count bits starting from bit b */ #define BITFIELD64_RANGE(b, count) \ (BITFIELD64_MASK((b) + (count)) & ~BITFIELD64_MASK(b)) diff --git a/lib/mesa/src/util/mesa-sha1.c b/lib/mesa/src/util/mesa-sha1.c index bdca1233a..eed6e34fa 100644 --- a/lib/mesa/src/util/mesa-sha1.c +++ b/lib/mesa/src/util/mesa-sha1.c @@ -26,6 +26,7 @@ #include "sha1/sha1.h" #include "mesa-sha1.h" +#include "hex.h" #include <string.h> #include <inttypes.h> @@ -42,14 +43,7 @@ _mesa_sha1_compute(const void *data, size_t size, unsigned char result[20]) void _mesa_sha1_format(char *buf, const unsigned char *sha1) { - static const char hex_digits[] = "0123456789abcdef"; - int i; - - for (i = 0; i < 40; i += 2) { - buf[i] = hex_digits[sha1[i >> 1] >> 4]; - buf[i + 1] = hex_digits[sha1[i >> 1] & 0x0f]; - } - buf[i] = '\0'; + mesa_bytes_to_hex(buf, sha1, SHA1_DIGEST_LENGTH); } /* Convert a hashs string hexidecimal representation into its more compact @@ -58,13 +52,7 @@ _mesa_sha1_format(char *buf, const unsigned char *sha1) void _mesa_sha1_hex_to_sha1(unsigned char *buf, const char *hex) { - for (unsigned i = 0; i < 20; i++) { - char tmp[3]; - tmp[0] = hex[i * 2]; - tmp[1] = hex[(i * 2) + 1]; - tmp[2] = '\0'; - buf[i] = strtol(tmp, NULL, 16); - } + mesa_hex_to_bytes(buf, hex, SHA1_DIGEST_LENGTH); } static void diff --git a/lib/mesa/src/util/mesa-sha1.h b/lib/mesa/src/util/mesa-sha1.h index 809fabc52..c264927d5 100644 --- a/lib/mesa/src/util/mesa-sha1.h +++ b/lib/mesa/src/util/mesa-sha1.h @@ -44,7 +44,8 @@ _mesa_sha1_init(struct mesa_sha1 *ctx) static inline void _mesa_sha1_update(struct mesa_sha1 *ctx, const void *data, size_t size) { - SHA1Update(ctx, (const unsigned char *)data, size); + if (size) + SHA1Update(ctx, (const unsigned char *)data, size); } static inline void diff --git a/lib/mesa/src/util/meson.build b/lib/mesa/src/util/meson.build index e74b187ed..eb88f235c 100644 --- a/lib/mesa/src/util/meson.build +++ b/lib/mesa/src/util/meson.build @@ -23,7 +23,11 @@ # util is self contained. inc_util = [inc_include, include_directories('..')] -subdir('format') +if with_platform_android +subdir('u_gralloc') +endif + +subdir('blake3') files_mesa_util = files( 'anon_file.h', @@ -32,6 +36,7 @@ files_mesa_util = files( 'bitscan.c', 'bitscan.h', 'bitset.h', + 'blend.h', 'blob.c', 'blob.h', 'build_id.c', @@ -64,6 +69,7 @@ files_mesa_util = files( 'half_float.h', 'hash_table.c', 'hash_table.h', + 'hex.h', 'u_idalloc.c', 'u_idalloc.h', 'list.h', @@ -73,6 +79,8 @@ files_mesa_util = files( 'memstream.h', 'mesa-sha1.c', 'mesa-sha1.h', + 'mesa-blake3.c', + 'mesa-blake3.h', 'os_time.c', 'os_time.h', 'os_file.c', @@ -119,18 +127,18 @@ files_mesa_util = files( 'strndup.h', 'strtod.c', 'strtod.h', - 'texcompress_rgtc_tmp.h', + 'texcompress_astc_luts.cpp', + 'texcompress_astc_luts.h', + 'texcompress_astc_luts_wrap.cpp', + 'texcompress_astc_luts_wrap.h', 'timespec.h', 'u_atomic.c', 'u_atomic.h', 'u_call_once.c', 'u_call_once.h', - 'u_debug_describe.c', - 'u_debug_describe.h', - 'u_debug_refcnt.c', - 'u_debug_refcnt.h', 'u_dl.c', 'u_dl.h', + 'u_dynarray.c', 'u_dynarray.h', 'u_endian.h', 'u_hash_table.c', @@ -148,6 +156,7 @@ files_mesa_util = files( 'u_memset.h', 'u_mm.c', 'u_mm.h', + 'u_pack_color.h', 'u_debug.c', 'u_debug.h', 'u_debug_memory.c', @@ -159,6 +168,8 @@ files_mesa_util = files( 'u_worklist.h', 'vl_vlc.h', 'vl_rbsp.h', + 'vl_zscan_data.h', + 'vl_zscan_data.c', 'vma.c', 'vma.h', 'xxhash.h', @@ -219,14 +230,16 @@ deps_for_libmesa_util = [ dep_dl, dep_unwind, dep_futex, + idep_blake3, idep_mesautilc11 ] if with_platform_android deps_for_libmesa_util += dep_android files_debug_stack = files('u_debug_stack_android.cpp') - else +else files_debug_stack = files( + 'dbghelp.h', 'u_debug_stack.c', 'u_debug_symbol.c', 'u_debug_symbol.h', @@ -245,22 +258,34 @@ if with_perfetto deps_for_libmesa_util += dep_perfetto endif +if with_gpuvis + files_mesa_util += files( + 'perf/u_gpuvis.c', + 'perf/u_gpuvis.h', + 'perf/gpuvis_trace_utils.h', + ) +endif + u_trace_py = files('perf/u_trace.py') libmesa_util_sse41 = static_library( 'mesa_util_sse41', files('streaming-load-memcpy.c'), c_args : [c_msvc_compat_args, sse41_args], - include_directories : [inc_include, inc_src, inc_mesa], + include_directories : [inc_util], gnu_symbol_visibility : 'hidden', ) +# subdir format provide files_mesa_format +subdir('format') +files_mesa_util += files_mesa_format + _libmesa_util = static_library( 'mesa_util', [files_mesa_util, files_debug_stack, format_srgb], - include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], + include_directories : [inc_util, include_directories('format')], dependencies : deps_for_libmesa_util, - link_with: [libmesa_format, libmesa_util_sse41], + link_with: [libmesa_util_sse41], c_args : [c_msvc_compat_args], gnu_symbol_visibility : 'hidden', build_by_default : false @@ -268,13 +293,13 @@ _libmesa_util = static_library( idep_mesautil = declare_dependency( link_with : _libmesa_util, - include_directories : [inc_util, inc_gallium], + include_directories : [inc_util], dependencies : deps_for_libmesa_util, ) # Only install the drirc file if we build with support for parsing drirc files if use_xmlconfig - install_data(files_drirc, install_dir : join_paths(get_option('datadir'), 'drirc.d')) + install_data(files_drirc, install_dir : join_paths(get_option('datadir'), 'drirc.d'), install_tag : 'runtime') endif xmlconfig_deps = [] @@ -288,7 +313,6 @@ c_xmlconfig_arg = '-DWITH_XMLCONFIG=@0@'.format(use_xmlconfig.to_int()) _libxmlconfig = static_library( 'xmlconfig', files_xmlconfig, - include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], dependencies : [idep_mesautil, dep_m, xmlconfig_deps], c_args : [ c_msvc_compat_args, @@ -312,6 +336,8 @@ idep_xmlconfig = declare_dependency( files_xxd = files('xxd.py') glsl2spirv = files('glsl2spirv.py') +devenv.set('DRIRC_CONFIGDIR', meson.current_source_dir()) + if with_tests # DRI_CONF macros use designated initializers (required for union # initializaiton), so we need c++2a since gtest forces us to use c++ @@ -319,7 +345,6 @@ if with_tests test('xmlconfig', executable('xmlconfig_test', files('tests/xmlconfig.cpp'), - include_directories : [inc_include, inc_src], dependencies : [idep_mesautil, idep_xmlconfig, idep_gtest], override_options : ['cpp_std=c++2a'], cpp_args: ['-Wno-write-strings', c_xmlconfig_arg] @@ -339,8 +364,10 @@ if with_tests 'tests/dag_test.cpp', 'tests/fast_idiv_by_const_test.cpp', 'tests/fast_urem_by_const_test.cpp', + 'tests/gc_alloc_tests.cpp', 'tests/half_float_test.cpp', 'tests/int_min_max.cpp', + 'tests/linear_test.cpp', 'tests/mesa-sha1_test.cpp', 'tests/os_mman_test.cpp', 'tests/perf/u_trace_test.cpp', @@ -377,7 +404,6 @@ if with_tests executable( 'util_tests', files_util_tests, - include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], dependencies : [idep_mesautil, idep_gtest], ), suite : ['util'], @@ -388,7 +414,6 @@ if with_tests process_test_exe = executable( 'process_test', files('tests/process_test.c'), - include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux], dependencies : idep_mesautil, c_args : [c_msvc_compat_args], ) diff --git a/lib/mesa/src/util/os_misc.c b/lib/mesa/src/util/os_misc.c index 6ae97b983..c378a9e91 100644 --- a/lib/mesa/src/util/os_misc.c +++ b/lib/mesa/src/util/os_misc.c @@ -292,7 +292,7 @@ os_get_total_physical_memory(uint64_t *size) status.dwLength = sizeof(status); ret = GlobalMemoryStatusEx(&status); *size = status.ullTotalPhys; - return (ret == TRUE); + return (ret == true); #else #error unexpected platform in os_misc.c return false; @@ -349,7 +349,7 @@ os_get_available_system_memory(uint64_t *size) status.dwLength = sizeof(status); ret = GlobalMemoryStatusEx(&status); *size = status.ullAvailPhys; - return (ret == TRUE); + return (ret == true); #else return false; #endif diff --git a/lib/mesa/src/util/ralloc.c b/lib/mesa/src/util/ralloc.c index c3a4befc1..c85c61e3d 100644 --- a/lib/mesa/src/util/ralloc.c +++ b/lib/mesa/src/util/ralloc.c @@ -38,9 +38,9 @@ #define CANARY 0x5A1106 #if defined(__LP64__) || defined(_WIN64) -#define HEADER_ALIGN alignas(16) +#define HEADER_ALIGN 16 #else -#define HEADER_ALIGN alignas(8) +#define HEADER_ALIGN 8 #endif /* Align the header's size so that ralloc() allocations will return with the @@ -50,11 +50,12 @@ */ struct ralloc_header { - HEADER_ALIGN + alignas(HEADER_ALIGN) #ifndef NDEBUG /* A canary value used to determine whether a pointer is ralloc'd. */ unsigned canary; + unsigned size; #endif struct ralloc_header *parent; @@ -139,6 +140,7 @@ ralloc_size(const void *ctx, size_t size) #ifndef NDEBUG info->canary = CANARY; + info->size = size; #endif return PTR_FROM_HEADER(info); @@ -548,6 +550,7 @@ ralloc_vasprintf_rewrite_tail(char **str, size_t *start, const char *fmt, /* The size of a slab. */ #define SLAB_SIZE (32 * 1024) +#define GC_CONTEXT_CANARY 0xAF6B6C83 #define GC_CANARY 0xAF6B5B72 enum gc_flags { @@ -578,7 +581,7 @@ typedef struct * allocated using a freelist backed by a simple linear allocator. */ typedef struct gc_slab { - HEADER_ALIGN + alignas(HEADER_ALIGN) gc_ctx *ctx; @@ -603,6 +606,10 @@ typedef struct gc_slab { } gc_slab; struct gc_ctx { +#ifndef NDEBUG + unsigned canary; +#endif + /* Array of slabs for fixed-size allocations. Each slab tracks allocations * of specific sized blocks. User allocations are rounded up to the nearest * fixed size. slabs[N] contains allocations of size @@ -669,31 +676,38 @@ gc_context(const void *parent) list_inithead(&ctx->slabs[i].slabs); list_inithead(&ctx->slabs[i].free_slabs); } +#ifndef NDEBUG + ctx->canary = GC_CONTEXT_CANARY; +#endif return ctx; } -static size_t -gc_bucket_obj_size(unsigned bucket) +static_assert(UINT32_MAX >= MAX_FREELIST_SIZE, "Freelist sizes use uint32_t"); + +static uint32_t +gc_bucket_obj_size(uint32_t bucket) { return (bucket + 1) * FREELIST_ALIGNMENT; } -static unsigned -gc_bucket_for_size(size_t size) +static uint32_t +gc_bucket_for_size(uint32_t size) { return (size - 1) / FREELIST_ALIGNMENT; } -static unsigned -gc_bucket_num_objs(unsigned bucket) +static_assert(UINT32_MAX >= SLAB_SIZE, "SLAB_SIZE use uint32_t"); + +static uint32_t +gc_bucket_num_objs(uint32_t bucket) { return (SLAB_SIZE - sizeof(gc_slab)) / gc_bucket_obj_size(bucket); } static gc_block_header * -alloc_from_slab(gc_slab *slab, unsigned bucket) +alloc_from_slab(gc_slab *slab, uint32_t bucket) { - size_t size = gc_bucket_obj_size(bucket); + uint32_t size = gc_bucket_obj_size(bucket); gc_block_header *header; if (slab->freelist) { /* Prioritize already-allocated chunks, since they probably have a page @@ -758,15 +772,15 @@ free_from_slab(gc_block_header *header, bool keep_empty_slabs) slab->num_free++; } -static unsigned -get_slab_size(unsigned bucket) +static uint32_t +get_slab_size(uint32_t bucket) { /* SLAB_SIZE rounded down to a multiple of the object size so that it's not larger than what can * be used. */ - unsigned obj_size = gc_bucket_obj_size(bucket); - unsigned num_objs = gc_bucket_num_objs(bucket); - return align64(sizeof(gc_slab) + num_objs * obj_size, alignof(gc_slab)); + uint32_t obj_size = gc_bucket_obj_size(bucket); + uint32_t num_objs = gc_bucket_num_objs(bucket); + return align((uint32_t)sizeof(gc_slab) + num_objs * obj_size, alignof(gc_slab)); } static gc_slab * @@ -801,13 +815,16 @@ gc_alloc_size(gc_ctx *ctx, size_t size, size_t align) */ assert((align - alignof(gc_block_header)) <= 127); + /* We can only align as high as the slab is. */ + assert(align <= HEADER_ALIGN); + size_t header_size = align64(sizeof(gc_block_header), align); size = align64(size, align); size += header_size; gc_block_header *header = NULL; if (size <= MAX_FREELIST_SIZE) { - unsigned bucket = gc_bucket_for_size(size); + uint32_t bucket = gc_bucket_for_size((uint32_t)size); if (list_is_empty(&ctx->slabs[bucket].free_slabs) && !create_slab(ctx, bucket)) return NULL; gc_slab *slab = list_first_entry(&ctx->slabs[bucket].free_slabs, gc_slab, free_link); @@ -941,8 +958,7 @@ gc_sweep_end(gc_ctx *ctx) * * The allocator uses a fixed-sized buffer with a monotonically increasing * offset after each allocation. If the buffer is all used, another buffer - * is allocated, sharing the same ralloc parent, so all buffers are at - * the same level in the ralloc hierarchy. + * is allocated, using the linear parent node as ralloc parent. * * The linear parent node is always the first buffer and keeps track of all * other buffers. @@ -950,141 +966,142 @@ gc_sweep_end(gc_ctx *ctx) #define MIN_LINEAR_BUFSIZE 2048 #define SUBALLOC_ALIGNMENT 8 -#define LMAGIC 0x87b9c7d3 +#define LMAGIC_CONTEXT 0x87b9c7d3 +#define LMAGIC_NODE 0x87b910d3 -struct linear_header { +struct linear_ctx { - HEADER_ALIGN + alignas(HEADER_ALIGN) #ifndef NDEBUG unsigned magic; /* for debugging */ #endif - unsigned offset; /* points to the first unused byte in the buffer */ - unsigned size; /* size of the buffer */ - void *ralloc_parent; /* new buffers will use this */ - struct linear_header *next; /* next buffer if we have more */ - struct linear_header *latest; /* the only buffer that has free space */ - - /* After this structure, the buffer begins. - * Each suballocation consists of linear_size_chunk as its header followed - * by the suballocation, so it goes: - * - * - linear_size_chunk - * - allocated space - * - linear_size_chunk - * - allocated space - * etc. - * - * linear_size_chunk is only needed by linear_realloc. - */ + unsigned offset; /* points to the first unused byte in the latest buffer */ + unsigned size; /* size of the latest buffer */ + void *latest; /* the only buffer that has free space */ }; -struct linear_size_chunk { - unsigned size; /* for realloc */ - unsigned _padding; -}; +typedef struct linear_ctx linear_ctx; -typedef struct linear_header linear_header; -typedef struct linear_size_chunk linear_size_chunk; +#ifndef NDEBUG +struct linear_node_canary { + alignas(HEADER_ALIGN) + unsigned magic; + unsigned offset; /* points to the first unused byte in *this* buffer */ +}; -#define LINEAR_PARENT_TO_HEADER(parent) \ - (linear_header*) \ - ((char*)(parent) - sizeof(linear_size_chunk) - sizeof(linear_header)) +typedef struct linear_node_canary linear_node_canary; -/* Allocate the linear buffer with its header. */ -static linear_header * -create_linear_node(void *ralloc_ctx, unsigned min_size) +static linear_node_canary * +get_node_canary(void *ptr) { - linear_header *node; - - min_size += sizeof(linear_size_chunk); - - if (likely(min_size < MIN_LINEAR_BUFSIZE)) - min_size = MIN_LINEAR_BUFSIZE; - - node = ralloc_size(ralloc_ctx, sizeof(linear_header) + min_size); - if (unlikely(!node)) - return NULL; + return (void *)((char *)ptr - sizeof(linear_node_canary)); +} +#endif +static unsigned +get_node_canary_size() +{ #ifndef NDEBUG - node->magic = LMAGIC; + return sizeof(linear_node_canary); +#else + return 0; #endif - node->offset = 0; - node->size = min_size; - node->ralloc_parent = ralloc_ctx; - node->next = NULL; - node->latest = node; - return node; } void * -linear_alloc_child(void *parent, unsigned size) +linear_alloc_child(linear_ctx *ctx, unsigned size) { - linear_header *first = LINEAR_PARENT_TO_HEADER(parent); - linear_header *latest = first->latest; - linear_header *new_node; - linear_size_chunk *ptr; - unsigned full_size; - - assert(first->magic == LMAGIC); - assert(!latest->next); + assert(ctx->magic == LMAGIC_CONTEXT); + assert(get_node_canary(ctx->latest)->magic == LMAGIC_NODE); + assert(get_node_canary(ctx->latest)->offset == ctx->offset); size = ALIGN_POT(size, SUBALLOC_ALIGNMENT); - full_size = sizeof(linear_size_chunk) + size; - if (unlikely(latest->offset + full_size > latest->size)) { + if (unlikely(ctx->offset + size > ctx->size)) { /* allocate a new node */ - new_node = create_linear_node(latest->ralloc_parent, size); - if (unlikely(!new_node)) + unsigned node_size = size; + if (likely(node_size < MIN_LINEAR_BUFSIZE)) + node_size = MIN_LINEAR_BUFSIZE; + + const unsigned canary_size = get_node_canary_size(); + const unsigned full_size = canary_size + node_size; + + /* linear context is also a ralloc context */ + char *ptr = ralloc_size(ctx, full_size); + if (unlikely(!ptr)) return NULL; - first->latest = new_node; - latest->latest = new_node; - latest->next = new_node; - latest = new_node; +#ifndef NDEBUG + linear_node_canary *canary = (void *) ptr; + canary->magic = LMAGIC_NODE; + canary->offset = 0; +#endif + + /* If the new buffer is going to be full, don't update `latest` + * pointer. Either the current one is also full, so doesn't + * matter, or the current one is not full, so there's still chance + * to use that space. + */ + if (unlikely(size == node_size)) { +#ifndef NDEBUG + canary->offset = size; +#endif + assert((uintptr_t)(ptr + canary_size) % SUBALLOC_ALIGNMENT == 0); + return ptr + canary_size; + } + + ctx->offset = 0; + ctx->size = node_size; + ctx->latest = ptr + canary_size; } - ptr = (linear_size_chunk *)((char*)&latest[1] + latest->offset); - ptr->size = size; - latest->offset += full_size; + void *ptr = (char *)ctx->latest + ctx->offset; + ctx->offset += size; + +#ifndef NDEBUG + linear_node_canary *canary = get_node_canary(ctx->latest); + canary->offset += size; +#endif - assert((uintptr_t)&ptr[1] % SUBALLOC_ALIGNMENT == 0); - return &ptr[1]; + assert((uintptr_t)ptr % SUBALLOC_ALIGNMENT == 0); + return ptr; } -void * -linear_alloc_parent(void *ralloc_ctx, unsigned size) +linear_ctx * +linear_context(void *ralloc_ctx) { - linear_header *node; + linear_ctx *ctx; if (unlikely(!ralloc_ctx)) return NULL; - size = ALIGN_POT(size, SUBALLOC_ALIGNMENT); + const unsigned size = MIN_LINEAR_BUFSIZE; + const unsigned canary_size = get_node_canary_size(); + const unsigned full_size = + sizeof(linear_ctx) + canary_size + size; - node = create_linear_node(ralloc_ctx, size); - if (unlikely(!node)) + ctx = ralloc_size(ralloc_ctx, full_size); + if (unlikely(!ctx)) return NULL; - return linear_alloc_child((char*)node + - sizeof(linear_header) + - sizeof(linear_size_chunk), size); -} - -void * -linear_zalloc_child(void *parent, unsigned size) -{ - void *ptr = linear_alloc_child(parent, size); + ctx->offset = 0; + ctx->size = size; + ctx->latest = (char *)&ctx[1] + canary_size; +#ifndef NDEBUG + ctx->magic = LMAGIC_CONTEXT; + linear_node_canary *canary = get_node_canary(ctx->latest); + canary->magic = LMAGIC_NODE; + canary->offset = 0; +#endif - if (likely(ptr)) - memset(ptr, 0, size); - return ptr; + return ctx; } void * -linear_zalloc_parent(void *parent, unsigned size) +linear_zalloc_child(linear_ctx *ctx, unsigned size) { - void *ptr = linear_alloc_parent(parent, size); + void *ptr = linear_alloc_child(ctx, size); if (likely(ptr)) memset(ptr, 0, size); @@ -1092,67 +1109,34 @@ linear_zalloc_parent(void *parent, unsigned size) } void -linear_free_parent(void *ptr) +linear_free_context(linear_ctx *ctx) { - linear_header *node; - - if (unlikely(!ptr)) + if (unlikely(!ctx)) return; - node = LINEAR_PARENT_TO_HEADER(ptr); - assert(node->magic == LMAGIC); - - while (node) { - void *ptr = node; + assert(ctx->magic == LMAGIC_CONTEXT); - node = node->next; - ralloc_free(ptr); - } + /* Linear context is also the ralloc parent of extra nodes. */ + ralloc_free(ctx); } void -ralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr) +ralloc_steal_linear_context(void *new_ralloc_ctx, linear_ctx *ctx) { - linear_header *node; - - if (unlikely(!ptr)) + if (unlikely(!ctx)) return; + + assert(ctx->magic == LMAGIC_CONTEXT); - node = LINEAR_PARENT_TO_HEADER(ptr); - assert(node->magic == LMAGIC); - - while (node) { - ralloc_steal(new_ralloc_ctx, node); - node->ralloc_parent = new_ralloc_ctx; - node = node->next; - } + /* Linear context is also the ralloc parent of extra nodes. */ + ralloc_steal(new_ralloc_ctx, ctx); } void * -ralloc_parent_of_linear_parent(void *ptr) +ralloc_parent_of_linear_context(linear_ctx *ctx) { - linear_header *node = LINEAR_PARENT_TO_HEADER(ptr); - assert(node->magic == LMAGIC); - return node->ralloc_parent; -} - -void * -linear_realloc(void *parent, void *old, unsigned new_size) -{ - unsigned old_size = 0; - ralloc_header *new_ptr; - - new_ptr = linear_alloc_child(parent, new_size); - - if (unlikely(!old)) - return new_ptr; - - old_size = ((linear_size_chunk*)old)[-1].size; - - if (likely(new_ptr && old_size)) - memcpy(new_ptr, old, MIN2(old_size, new_size)); - - return new_ptr; + assert(ctx->magic == LMAGIC_CONTEXT); + return PTR_FROM_HEADER(get_header(ctx)->parent); } /* All code below is pretty much copied from ralloc and only the alloc @@ -1160,7 +1144,7 @@ linear_realloc(void *parent, void *old, unsigned new_size) */ char * -linear_strdup(void *parent, const char *str) +linear_strdup(linear_ctx *ctx, const char *str) { unsigned n; char *ptr; @@ -1169,7 +1153,7 @@ linear_strdup(void *parent, const char *str) return NULL; n = strlen(str); - ptr = linear_alloc_child(parent, n + 1); + ptr = linear_alloc_child(ctx, n + 1); if (unlikely(!ptr)) return NULL; @@ -1179,22 +1163,22 @@ linear_strdup(void *parent, const char *str) } char * -linear_asprintf(void *parent, const char *fmt, ...) +linear_asprintf(linear_ctx *ctx, const char *fmt, ...) { char *ptr; va_list args; va_start(args, fmt); - ptr = linear_vasprintf(parent, fmt, args); + ptr = linear_vasprintf(ctx, fmt, args); va_end(args); return ptr; } char * -linear_vasprintf(void *parent, const char *fmt, va_list args) +linear_vasprintf(linear_ctx *ctx, const char *fmt, va_list args) { unsigned size = u_printf_length(fmt, args) + 1; - char *ptr = linear_alloc_child(parent, size); + char *ptr = linear_alloc_child(ctx, size); if (ptr != NULL) vsnprintf(ptr, size, fmt, args); @@ -1202,39 +1186,39 @@ linear_vasprintf(void *parent, const char *fmt, va_list args) } bool -linear_asprintf_append(void *parent, char **str, const char *fmt, ...) +linear_asprintf_append(linear_ctx *ctx, char **str, const char *fmt, ...) { bool success; va_list args; va_start(args, fmt); - success = linear_vasprintf_append(parent, str, fmt, args); + success = linear_vasprintf_append(ctx, str, fmt, args); va_end(args); return success; } bool -linear_vasprintf_append(void *parent, char **str, const char *fmt, va_list args) +linear_vasprintf_append(linear_ctx *ctx, char **str, const char *fmt, va_list args) { size_t existing_length; assert(str != NULL); existing_length = *str ? strlen(*str) : 0; - return linear_vasprintf_rewrite_tail(parent, str, &existing_length, fmt, args); + return linear_vasprintf_rewrite_tail(ctx, str, &existing_length, fmt, args); } bool -linear_asprintf_rewrite_tail(void *parent, char **str, size_t *start, +linear_asprintf_rewrite_tail(linear_ctx *ctx, char **str, size_t *start, const char *fmt, ...) { bool success; va_list args; va_start(args, fmt); - success = linear_vasprintf_rewrite_tail(parent, str, start, fmt, args); + success = linear_vasprintf_rewrite_tail(ctx, str, start, fmt, args); va_end(args); return success; } bool -linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start, +linear_vasprintf_rewrite_tail(linear_ctx *ctx, char **str, size_t *start, const char *fmt, va_list args) { size_t new_length; @@ -1243,17 +1227,19 @@ linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start, assert(str != NULL); if (unlikely(*str == NULL)) { - *str = linear_vasprintf(parent, fmt, args); + *str = linear_vasprintf(ctx, fmt, args); *start = strlen(*str); return true; } new_length = u_printf_length(fmt, args); - ptr = linear_realloc(parent, *str, *start + new_length + 1); + ptr = linear_alloc_child(ctx, *start + new_length + 1); if (unlikely(ptr == NULL)) return false; + memcpy(ptr, *str, *start); + vsnprintf(ptr + *start, new_length + 1, fmt, args); *str = ptr; *start += new_length; @@ -1262,17 +1248,18 @@ linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start, /* helper routine for strcat/strncat - n is the exact amount to copy */ static bool -linear_cat(void *parent, char **dest, const char *str, unsigned n) +linear_cat(linear_ctx *ctx, char **dest, const char *str, unsigned n) { char *both; unsigned existing_length; assert(dest != NULL && *dest != NULL); existing_length = strlen(*dest); - both = linear_realloc(parent, *dest, existing_length + n + 1); + both = linear_alloc_child(ctx, existing_length + n + 1); if (unlikely(both == NULL)) return false; + memcpy(both, *dest, existing_length); memcpy(both + existing_length, str, n); both[existing_length + n] = '\0'; @@ -1281,7 +1268,143 @@ linear_cat(void *parent, char **dest, const char *str, unsigned n) } bool -linear_strcat(void *parent, char **dest, const char *str) +linear_strcat(linear_ctx *ctx, char **dest, const char *str) +{ + return linear_cat(ctx, dest, str, strlen(str)); +} + +void * +linear_alloc_child_array(linear_ctx *ctx, size_t size, unsigned count) +{ + if (count > SIZE_MAX/size) + return NULL; + + return linear_alloc_child(ctx, size * count); +} + +void * +linear_zalloc_child_array(linear_ctx *ctx, size_t size, unsigned count) { - return linear_cat(parent, dest, str, strlen(str)); + if (count > SIZE_MAX/size) + return NULL; + + return linear_zalloc_child(ctx, size * count); } + +typedef struct { + FILE *f; + unsigned indent; + + unsigned ralloc_count; + unsigned linear_count; + unsigned gc_count; + + /* These don't include padding or metadata from suballocators. */ + unsigned content_bytes; + unsigned ralloc_metadata_bytes; + unsigned linear_metadata_bytes; + unsigned gc_metadata_bytes; + + bool inside_linear; + bool inside_gc; +} ralloc_print_info_state; + +static void +ralloc_print_info_helper(ralloc_print_info_state *state, const ralloc_header *info) +{ + FILE *f = state->f; + + if (f) { + for (unsigned i = 0; i < state->indent; i++) fputc(' ', f); + fprintf(f, "%p", info); + } + + /* TODO: Account for padding used in various places. */ + +#ifndef NDEBUG + assert(info->canary == CANARY); + if (f) fprintf(f, " (%d bytes)", info->size); + state->content_bytes += info->size; + state->ralloc_metadata_bytes += sizeof(ralloc_header); + + const void *ptr = PTR_FROM_HEADER(info); + const linear_ctx *lin_ctx = ptr; + const gc_ctx *gc_ctx = ptr; + + if (lin_ctx->magic == LMAGIC_CONTEXT) { + if (f) fprintf(f, " (linear context)"); + assert(!state->inside_gc && !state->inside_linear); + state->inside_linear = true; + state->linear_metadata_bytes += sizeof(linear_ctx); + state->content_bytes -= sizeof(linear_ctx); + state->linear_count++; + } else if (gc_ctx->canary == GC_CONTEXT_CANARY) { + if (f) fprintf(f, " (gc context)"); + assert(!state->inside_gc && !state->inside_linear); + state->inside_gc = true; + state->gc_metadata_bytes += sizeof(gc_block_header); + } else if (state->inside_linear) { + const linear_node_canary *lin_node = ptr; + if (lin_node->magic == LMAGIC_NODE) { + if (f) fprintf(f, " (linear node buffer)"); + state->content_bytes -= sizeof(linear_node_canary); + state->linear_metadata_bytes += sizeof(linear_node_canary); + state->linear_count++; + } + } else if (state->inside_gc) { + if (f) fprintf(f, " (gc slab or large block)"); + state->gc_count++; + } +#endif + + state->ralloc_count++; + if (f) fprintf(f, "\n"); + + const ralloc_header *c = info->child; + state->indent += 2; + while (c != NULL) { + ralloc_print_info_helper(state, c); + c = c->next; + } + state->indent -= 2; + +#ifndef NDEBUG + if (lin_ctx->magic == LMAGIC_CONTEXT) state->inside_linear = false; + else if (gc_ctx->canary == GC_CONTEXT_CANARY) state->inside_gc = false; +#endif +} + +void +ralloc_print_info(FILE *f, const void *p, unsigned flags) +{ + ralloc_print_info_state state = { + .f = ((flags & RALLOC_PRINT_INFO_SUMMARY_ONLY) == 1) ? NULL : f, + }; + + const ralloc_header *info = get_header(p); + ralloc_print_info_helper(&state, info); + + fprintf(f, "==== RALLOC INFO ptr=%p info=%p\n" + "ralloc allocations = %d\n" + " - linear = %d\n" + " - gc = %d\n" + " - other = %d\n", + p, info, + state.ralloc_count, + state.linear_count, + state.gc_count, + state.ralloc_count - state.linear_count - state.gc_count); + + if (state.content_bytes) { + fprintf(f, + "content bytes = %d\n" + "ralloc metadata bytes = %d\n" + "linear metadata bytes = %d\n", + state.content_bytes, + state.ralloc_metadata_bytes, + state.linear_metadata_bytes); + } + + fprintf(f, "====\n"); +} + diff --git a/lib/mesa/src/util/ralloc.h b/lib/mesa/src/util/ralloc.h index 0fdcb3c30..58d851f18 100644 --- a/lib/mesa/src/util/ralloc.h +++ b/lib/mesa/src/util/ralloc.h @@ -517,7 +517,7 @@ void gc_sweep_end(gc_ctx *ctx); * * which is more idiomatic in C++ than calling ralloc. */ -#define DECLARE_ALLOC_CXX_OPERATORS_TEMPLATE(TYPE, ALLOC_FUNC) \ +#define DECLARE_RALLOC_CXX_OPERATORS_TEMPLATE(TYPE, ALLOC_FUNC) \ private: \ static void _ralloc_destructor(void *p) \ { \ @@ -545,86 +545,166 @@ public: \ } #define DECLARE_RALLOC_CXX_OPERATORS(type) \ - DECLARE_ALLOC_CXX_OPERATORS_TEMPLATE(type, ralloc_size) + DECLARE_RALLOC_CXX_OPERATORS_TEMPLATE(type, ralloc_size) #define DECLARE_RZALLOC_CXX_OPERATORS(type) \ - DECLARE_ALLOC_CXX_OPERATORS_TEMPLATE(type, rzalloc_size) + DECLARE_RALLOC_CXX_OPERATORS_TEMPLATE(type, rzalloc_size) + + +#define DECLARE_LINEAR_ALLOC_CXX_OPERATORS_TEMPLATE(TYPE, ALLOC_FUNC) \ +public: \ + static void* operator new(size_t size, linear_ctx *ctx) \ + { \ + void *p = ALLOC_FUNC(ctx, size); \ + assert(p != NULL); \ + static_assert(HAS_TRIVIAL_DESTRUCTOR(TYPE)); \ + return p; \ + } #define DECLARE_LINEAR_ALLOC_CXX_OPERATORS(type) \ - DECLARE_ALLOC_CXX_OPERATORS_TEMPLATE(type, linear_alloc_child) + DECLARE_LINEAR_ALLOC_CXX_OPERATORS_TEMPLATE(type, linear_alloc_child) #define DECLARE_LINEAR_ZALLOC_CXX_OPERATORS(type) \ - DECLARE_ALLOC_CXX_OPERATORS_TEMPLATE(type, linear_zalloc_child) + DECLARE_LINEAR_ALLOC_CXX_OPERATORS_TEMPLATE(type, linear_zalloc_child) +typedef struct linear_ctx linear_ctx; /** - * Do a fast allocation from the linear buffer, also known as the child node + * Do a fast allocation from the linear context, also known as the child node * from the allocator's point of view. It can't be freed directly. You have - * to free the parent or the ralloc parent. + * to free the linear context or the ralloc parent. * - * \param parent parent node of the linear allocator + * \param ctx linear context of the allocator * \param size size to allocate (max 32 bits) */ -void *linear_alloc_child(void *parent, unsigned size); +void *linear_alloc_child(linear_ctx *ctx, unsigned size); /** - * Allocate a parent node that will hold linear buffers. The returned - * allocation is actually the first child node, but it's also the handle - * of the parent node. Use it for all child node allocations. + * Allocate a linear context that will internally hold linear buffers. + * Use it for all child node allocations. * * \param ralloc_ctx ralloc context, must not be NULL - * \param size size to allocate (max 32 bits) */ -void *linear_alloc_parent(void *ralloc_ctx, unsigned size); +linear_ctx *linear_context(void *ralloc_ctx); /** * Same as linear_alloc_child, but also clears memory. */ -void *linear_zalloc_child(void *parent, unsigned size); +void *linear_zalloc_child(linear_ctx *ctx, unsigned size) MALLOCLIKE; /** - * Same as linear_alloc_parent, but also clears memory. + * Free a linear context. This will free all child nodes too. + * Alternatively, freeing the ralloc parent will also free + * the linear context. */ -void *linear_zalloc_parent(void *ralloc_ctx, unsigned size); +void linear_free_context(linear_ctx *ctx); /** - * Free the linear parent node. This will free all child nodes too. - * Freeing the ralloc parent will also free this. + * Same as ralloc_steal, but steals the entire linear context. */ -void linear_free_parent(void *ptr); +void ralloc_steal_linear_context(void *new_ralloc_ctx, linear_ctx *ctx); /** - * Same as ralloc_steal, but steals the linear parent node. + * Return the ralloc parent of the linear context. */ -void ralloc_steal_linear_parent(void *new_ralloc_ctx, void *ptr); +void *ralloc_parent_of_linear_context(linear_ctx *ctx); /** - * Return the ralloc parent of the linear parent node. + * Do a fast allocation of an array from the linear context and initialize it to zero. + * + * Similar to \c calloc, but does not initialize the memory to zero. + * + * More than a convenience function, this also checks for integer overflow when + * multiplying \p size and \p count. This is necessary for security. */ -void *ralloc_parent_of_linear_parent(void *ptr); +void *linear_alloc_child_array(linear_ctx *ctx, size_t size, unsigned count) MALLOCLIKE; /** - * Same as realloc except that the linear allocator doesn't free child nodes, - * so it's reduced to memory duplication. It's used in places where - * reallocation is required. Don't use it often. It's much slower than - * realloc. + * Do a fast allocation of an array from the linear context. + * + * Similar to \c calloc. + * + * More than a convenience function, this also checks for integer overflow when + * multiplying \p size and \p count. This is necessary for security. */ -void *linear_realloc(void *parent, void *old, unsigned new_size); +void *linear_zalloc_child_array(linear_ctx *ctx, size_t size, unsigned count) MALLOCLIKE; /* The functions below have the same semantics as their ralloc counterparts, * except that they always allocate a linear child node. */ -char *linear_strdup(void *parent, const char *str); -char *linear_asprintf(void *parent, const char *fmt, ...); -char *linear_vasprintf(void *parent, const char *fmt, va_list args); -bool linear_asprintf_append(void *parent, char **str, const char *fmt, ...); -bool linear_vasprintf_append(void *parent, char **str, const char *fmt, +char *linear_strdup(linear_ctx *ctx, const char *str) MALLOCLIKE; +char *linear_asprintf(linear_ctx *ctx, const char *fmt, ...) PRINTFLIKE(2, 3) MALLOCLIKE; +char *linear_vasprintf(linear_ctx *ctx, const char *fmt, va_list args) MALLOCLIKE; +bool linear_asprintf_append(linear_ctx *ctx, char **str, const char *fmt, ...) PRINTFLIKE(3, 4); +bool linear_vasprintf_append(linear_ctx *ctx, char **str, const char *fmt, va_list args); -bool linear_asprintf_rewrite_tail(void *parent, char **str, size_t *start, - const char *fmt, ...); -bool linear_vasprintf_rewrite_tail(void *parent, char **str, size_t *start, +bool linear_asprintf_rewrite_tail(linear_ctx *ctx, char **str, size_t *start, + const char *fmt, ...) PRINTFLIKE(4, 5); +bool linear_vasprintf_rewrite_tail(linear_ctx *ctx, char **str, size_t *start, const char *fmt, va_list args); -bool linear_strcat(void *parent, char **dest, const char *str); +bool linear_strcat(linear_ctx *ctx, char **dest, const char *str); + +/** + * \def linear_alloc(ctx, type) + * Do a fast allocation from the linear context. + * + * This is equivalent to: + * \code + * ((type *) linear_alloc_child(ctx, sizeof(type)) + * \endcode + */ +#define linear_alloc(ctx, type) ((type *) linear_alloc_child(ctx, sizeof(type))) + +/** + * \def linear_zalloc(ctx, type) + * Do a fast allocation from the linear context and initialize it to zero. + * + * This is equivalent to: + * \code + * ((type *) linear_zalloc_child(ctx, sizeof(type)) + * \endcode + */ +#define linear_zalloc(ctx, type) ((type *) linear_zalloc_child(ctx, sizeof(type))) + +/** + * \def linear_alloc_array(ctx, type, count) + * Do a fast allocation of an array from the linear context. + * + * Similar to \c calloc, but does not initialize the memory to zero. + * + * More than a convenience function, this also checks for integer overflow when + * multiplying \c sizeof(type) and \p count. This is necessary for security. + * + * This is equivalent to: + * \code + * ((type *) linear_alloc_child_array(ctx, sizeof(type), count) + * \endcode + */ +#define linear_alloc_array(ctx, type, count) \ + ((type *) linear_alloc_child_array(ctx, sizeof(type), count)) + +/** + * \def linear_zalloc_array(ctx, type, count) + * Do a fast allocation of an array from the linear context and initialize it to zero + * + * Similar to \c calloc. + * + * More than a convenience function, this also checks for integer overflow when + * multiplying \c sizeof(type) and \p count. This is necessary for security. + * + * This is equivalent to: + * \code + * ((type *) linear_zalloc_child_array(ctx, sizeof(type), count) + * \endcode + */ +#define linear_zalloc_array(ctx, type, count) \ + ((type *) linear_zalloc_child_array(ctx, sizeof(type), count)) + +enum { + RALLOC_PRINT_INFO_SUMMARY_ONLY = 1 << 0, +}; + +void ralloc_print_info(FILE *f, const void *p, unsigned flags); #ifdef __cplusplus } /* end of extern "C" */ diff --git a/lib/mesa/src/util/sha1/sha1.c b/lib/mesa/src/util/sha1/sha1.c index 4fe2aa723..de7514c70 100644 --- a/lib/mesa/src/util/sha1/sha1.c +++ b/lib/mesa/src/util/sha1/sha1.c @@ -51,7 +51,7 @@ typedef union { /* * Hash a single 512-bit block. This is the core of the algorithm. */ -void +static void SHA1Transform(uint32_t state[5], const uint8_t buffer[SHA1_BLOCK_LENGTH]) { uint32_t a, b, c, d, e; @@ -144,7 +144,7 @@ SHA1Update(SHA1_CTX *context, const uint8_t *data, size_t len) /* * Add padding and return the message digest. */ -void +static void SHA1Pad(SHA1_CTX *context) { uint8_t finalcount[8]; diff --git a/lib/mesa/src/util/sha1/sha1.h b/lib/mesa/src/util/sha1/sha1.h index 029a0ae87..df534b508 100644 --- a/lib/mesa/src/util/sha1/sha1.h +++ b/lib/mesa/src/util/sha1/sha1.h @@ -27,8 +27,6 @@ typedef struct _SHA1_CTX { } SHA1_CTX; void SHA1Init(SHA1_CTX *); -void SHA1Pad(SHA1_CTX *); -void SHA1Transform(uint32_t [5], const uint8_t [SHA1_BLOCK_LENGTH]); void SHA1Update(SHA1_CTX *, const uint8_t *, size_t); void SHA1Final(uint8_t [SHA1_DIGEST_LENGTH], SHA1_CTX *); diff --git a/lib/mesa/src/util/u_cpu_detect.c b/lib/mesa/src/util/u_cpu_detect.c index 8baf2a7fa..3308968eb 100644 --- a/lib/mesa/src/util/u_cpu_detect.c +++ b/lib/mesa/src/util/u_cpu_detect.c @@ -33,11 +33,12 @@ */ #include "util/detect.h" -#include "pipe/p_compiler.h" +#include "util/compiler.h" #include "util/u_debug.h" #include "u_cpu_detect.h" #include "u_math.h" +#include "os_file.h" #include "c11/threads.h" #include <stdio.h> @@ -481,6 +482,40 @@ get_cpu_topology(void) memset(util_cpu_caps.cpu_to_L3, 0xff, sizeof(util_cpu_caps.cpu_to_L3)); +#if DETECT_OS_LINUX + uint64_t big_cap = 0; + unsigned num_big_cpus = 0; + uint64_t *caps = malloc(sizeof(uint64_t) * util_cpu_caps.max_cpus); + bool fail = false; + for (unsigned i = 0; caps && i < util_cpu_caps.max_cpus; i++) { + char name[PATH_MAX]; + snprintf(name, sizeof(name), "/sys/devices/system/cpu/cpu%u/cpu_capacity", i); + size_t size = 0; + char *cap = os_read_file(name, &size); + if (!cap) { + num_big_cpus = 0; + fail = true; + break; + } + errno = 0; + caps[i] = strtoull(cap, NULL, 10); + free(cap); + if (errno) { + fail = true; + break; + } + big_cap = MAX2(caps[i], big_cap); + } + if (!fail) { + for (unsigned i = 0; caps && i < util_cpu_caps.max_cpus; i++) { + if (caps[i] >= big_cap / 2) + num_big_cpus++; + } + } + free(caps); + util_cpu_caps.nr_big_cpus = num_big_cpus; +#endif + #if DETECT_ARCH_X86 || DETECT_ARCH_X86_64 /* AMD Zen */ if (util_cpu_caps.family >= CPU_AMD_ZEN1_ZEN2 && @@ -821,7 +856,6 @@ _util_cpu_detect_once(void) } /* general feature flags */ - util_cpu_caps.has_tsc = (regs2[3] >> 4) & 1; /* 0x0000010 */ util_cpu_caps.has_mmx = (regs2[3] >> 23) & 1; /* 0x0800000 */ util_cpu_caps.has_sse = (regs2[3] >> 25) & 1; /* 0x2000000 */ util_cpu_caps.has_sse2 = (regs2[3] >> 26) & 1; /* 0x4000000 */ @@ -847,27 +881,26 @@ _util_cpu_detect_once(void) if (cacheline > 0) util_cpu_caps.cacheline = cacheline; } - if (util_cpu_caps.has_avx && regs[0] >= 0x00000007) { + if (regs[0] >= 0x00000007) { uint32_t regs7[4]; cpuid_count(0x00000007, 0x00000000, regs7); - util_cpu_caps.has_avx2 = (regs7[1] >> 5) & 1; - } - - // check for avx512 - if (((regs2[2] >> 27) & 1) && // OSXSAVE - (xgetbv() & (0x7 << 5)) && // OPMASK: upper-256 enabled by OS - ((xgetbv() & 6) == 6)) { // XMM/YMM enabled by OS - uint32_t regs3[4]; - cpuid_count(0x00000007, 0x00000000, regs3); - util_cpu_caps.has_avx512f = (regs3[1] >> 16) & 1; - util_cpu_caps.has_avx512dq = (regs3[1] >> 17) & 1; - util_cpu_caps.has_avx512ifma = (regs3[1] >> 21) & 1; - util_cpu_caps.has_avx512pf = (regs3[1] >> 26) & 1; - util_cpu_caps.has_avx512er = (regs3[1] >> 27) & 1; - util_cpu_caps.has_avx512cd = (regs3[1] >> 28) & 1; - util_cpu_caps.has_avx512bw = (regs3[1] >> 30) & 1; - util_cpu_caps.has_avx512vl = (regs3[1] >> 31) & 1; - util_cpu_caps.has_avx512vbmi = (regs3[2] >> 1) & 1; + util_cpu_caps.has_clflushopt = (regs7[1] >> 23) & 1; + if (util_cpu_caps.has_avx) { + util_cpu_caps.has_avx2 = (regs7[1] >> 5) & 1; + + // check for avx512 + if (xgetbv() & (0x7 << 5)) { // OPMASK: upper-256 enabled by OS + util_cpu_caps.has_avx512f = (regs7[1] >> 16) & 1; + util_cpu_caps.has_avx512dq = (regs7[1] >> 17) & 1; + util_cpu_caps.has_avx512ifma = (regs7[1] >> 21) & 1; + util_cpu_caps.has_avx512pf = (regs7[1] >> 26) & 1; + util_cpu_caps.has_avx512er = (regs7[1] >> 27) & 1; + util_cpu_caps.has_avx512cd = (regs7[1] >> 28) & 1; + util_cpu_caps.has_avx512bw = (regs7[1] >> 30) & 1; + util_cpu_caps.has_avx512vl = (regs7[1] >> 31) & 1; + util_cpu_caps.has_avx512vbmi = (regs7[2] >> 1) & 1; + } + } } if (regs[1] == 0x756e6547 && regs[2] == 0x6c65746e && regs[3] == 0x49656e69) { @@ -930,7 +963,6 @@ _util_cpu_detect_once(void) printf("util_cpu_caps.x86_cpu_type = %u\n", util_cpu_caps.x86_cpu_type); printf("util_cpu_caps.cacheline = %u\n", util_cpu_caps.cacheline); - printf("util_cpu_caps.has_tsc = %u\n", util_cpu_caps.has_tsc); printf("util_cpu_caps.has_mmx = %u\n", util_cpu_caps.has_mmx); printf("util_cpu_caps.has_mmx2 = %u\n", util_cpu_caps.has_mmx2); printf("util_cpu_caps.has_sse = %u\n", util_cpu_caps.has_sse); @@ -960,6 +992,7 @@ _util_cpu_detect_once(void) printf("util_cpu_caps.has_avx512bw = %u\n", util_cpu_caps.has_avx512bw); printf("util_cpu_caps.has_avx512vl = %u\n", util_cpu_caps.has_avx512vl); printf("util_cpu_caps.has_avx512vbmi = %u\n", util_cpu_caps.has_avx512vbmi); + printf("util_cpu_caps.has_clflushopt = %u\n", util_cpu_caps.has_clflushopt); printf("util_cpu_caps.num_L3_caches = %u\n", util_cpu_caps.num_L3_caches); printf("util_cpu_caps.num_cpu_mask_bits = %u\n", util_cpu_caps.num_cpu_mask_bits); } diff --git a/lib/mesa/src/util/u_debug.h b/lib/mesa/src/util/u_debug.h index b3505caeb..d7e63381b 100644 --- a/lib/mesa/src/util/u_debug.h +++ b/lib/mesa/src/util/u_debug.h @@ -1,8 +1,8 @@ /************************************************************************** - * + * * 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 @@ -10,11 +10,11 @@ * 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. @@ -22,46 +22,90 @@ * 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 * Cross-platform debugging helpers. - * - * For now it just has assert and printf replacements, but it might be extended - * with stack trace reports and more advanced logging in the near future. - * + * + * For now it just has assert and printf replacements, but it might be extended + * with stack trace reports and more advanced logging in the near future. + * * @author Jose Fonseca <jfonseca@vmware.com> */ #ifndef U_DEBUG_H_ #define U_DEBUG_H_ +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#if !defined(_WIN32) +#include <sys/types.h> +#include <unistd.h> +#endif #include "util/os_misc.h" +#include "util/u_atomic.h" +#include "util/detect_os.h" +#include "util/macros.h" -#if defined(PIPE_OS_HAIKU) +#if DETECT_OS_HAIKU /* Haiku provides debug_printf in libroot with OS.h */ #include <OS.h> #endif -#include "pipe/p_defines.h" - - -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif +enum util_debug_type +{ + UTIL_DEBUG_TYPE_OUT_OF_MEMORY = 1, + UTIL_DEBUG_TYPE_ERROR, + UTIL_DEBUG_TYPE_SHADER_INFO, + UTIL_DEBUG_TYPE_PERF_INFO, + UTIL_DEBUG_TYPE_INFO, + UTIL_DEBUG_TYPE_FALLBACK, + UTIL_DEBUG_TYPE_CONFORMANCE, +}; -#if defined(__GNUC__) -#define _util_printf_format(fmt, list) __attribute__ ((format (printf, fmt, list))) -#else -#define _util_printf_format(fmt, list) -#endif +/** + * Structure that contains a callback for debug messages from the driver back + * to the gallium frontend. + */ +struct util_debug_callback +{ + /** + * When set to \c true, the callback may be called asynchronously from a + * driver-created thread. + */ + bool async; + + /** + * Callback for the driver to report debug/performance/etc information back + * to the gallium frontend. + * + * \param data user-supplied data pointer + * \param id message type identifier, if pointed value is 0, then a + * new id is assigned + * \param type UTIL_DEBUG_TYPE_* + * \param format printf-style format string + * \param args args for format string + */ + void (*debug_message)(void *data, + unsigned *id, + enum util_debug_type type, + const char *fmt, + va_list args); + void *data; +}; + +#define _util_printf_format(fmt, list) PRINTFLIKE(fmt, list) void _debug_vprintf(const char *format, va_list ap); - + static inline void _debug_printf(const char *format, ...) @@ -82,7 +126,7 @@ _debug_printf(const char *format, ...) * - avoid outputing large strings (512 bytes is the current maximum length * that is guaranteed to be printed in all platforms) */ -#if !defined(PIPE_OS_HAIKU) +#if !DETECT_OS_HAIKU static inline void debug_printf(const char *format, ...) _util_printf_format(1,2); @@ -109,9 +153,9 @@ debug_printf(const char *format, ...) */ #define debug_printf_once(args) \ do { \ - static boolean once = TRUE; \ + static bool once = true; \ if (once) { \ - once = FALSE; \ + once = false; \ debug_printf args; \ } \ } while (0) @@ -123,25 +167,15 @@ debug_printf(const char *format, ...) #define debug_vprintf(_format, _ap) ((void)0) #endif - -#ifdef DEBUG -/** - * Dump a blob in hex to the same place that debug_printf sends its - * messages. - */ -void debug_print_blob( const char *name, const void *blob, unsigned size ); -#else -#define debug_print_blob(_name, _blob, _size) ((void)0) -#endif - - +#ifdef _WIN32 /** - * Disable interactive error message boxes. + * Disable Win32 interactive error message boxes. * * Should be called as soon as possible for effectiveness. */ void -debug_disable_error_message_boxes(void); +debug_disable_win32_error_dialogs(void); +#endif /** @@ -154,43 +188,8 @@ debug_disable_error_message_boxes(void); #endif /* !DEBUG */ -long -debug_get_num_option(const char *name, long dfault); - -#ifdef _MSC_VER -__declspec(noreturn) -#endif -void _debug_assert_fail(const char *expr, - const char *file, - unsigned line, - const char *function) -#if defined(__GNUC__) && !defined(DEBUG) - __attribute__((noreturn)) -#endif -; - - -/** - * Assert macro - * - * Do not expect that the assert call terminates -- errors must be handled - * regardless of assert behavior. - * - * For non debug builds the assert macro will expand to a no-op, so do not - * call functions with side effects in the assert expression. - */ -#ifndef NDEBUG -#define debug_assert(expr) ((expr) ? (void)0 : _debug_assert_fail(#expr, __FILE__, __LINE__, __FUNCTION__)) -#else -#define debug_assert(expr) (void)(0 && (expr)) -#endif - - -/** Override standard assert macro */ -#ifdef assert -#undef assert -#endif -#define assert(expr) debug_assert(expr) +void +debug_get_version_option(const char *name, unsigned *major, unsigned *minor); /** @@ -198,10 +197,10 @@ void _debug_assert_fail(const char *expr, */ #ifdef DEBUG #define debug_checkpoint() \ - _debug_printf("%s\n", __FUNCTION__) + _debug_printf("%s\n", __func__) #else #define debug_checkpoint() \ - ((void)0) + ((void)0) #endif @@ -210,10 +209,10 @@ void _debug_assert_fail(const char *expr, */ #ifdef DEBUG #define debug_checkpoint_full() \ - _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __FUNCTION__) + _debug_printf("%s:%u:%s\n", __FILE__, __LINE__, __func__) #else #define debug_checkpoint_full() \ - ((void)0) + ((void)0) #endif @@ -222,10 +221,10 @@ void _debug_assert_fail(const char *expr, */ #ifdef DEBUG #define debug_warning(__msg) \ - _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg) + _debug_printf("%s:%u:%s: warning: %s\n", __FILE__, __LINE__, __func__, __msg) #else #define debug_warning(__msg) \ - ((void)0) + ((void)0) #endif @@ -235,16 +234,16 @@ void _debug_assert_fail(const char *expr, #ifdef DEBUG #define debug_warn_once(__msg) \ do { \ - static bool warned = FALSE; \ + static bool warned = false; \ if (!warned) { \ _debug_printf("%s:%u:%s: one time warning: %s\n", \ - __FILE__, __LINE__, __FUNCTION__, __msg); \ - warned = TRUE; \ + __FILE__, __LINE__, __func__, __msg); \ + warned = true; \ } \ } while (0) #else #define debug_warn_once(__msg) \ - ((void)0) + ((void)0) #endif @@ -253,7 +252,7 @@ void _debug_assert_fail(const char *expr, */ #ifdef DEBUG #define debug_error(__msg) \ - _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __FUNCTION__, __msg) + _debug_printf("%s:%u:%s: error: %s\n", __FILE__, __LINE__, __func__, __msg) #else #define debug_error(__msg) \ _debug_printf("error: %s\n", __msg) @@ -262,22 +261,18 @@ void _debug_assert_fail(const char *expr, /** * Output a debug log message to the debug info callback. */ -#define pipe_debug_message(cb, type, fmt, ...) do { \ +#define util_debug_message(cb, type, fmt, ...) do { \ static unsigned id = 0; \ - if ((cb) && (cb)->debug_message) { \ - _pipe_debug_message(cb, &id, \ - PIPE_DEBUG_TYPE_ ## type, \ - fmt, ##__VA_ARGS__); \ - } \ + _util_debug_message(cb, &id, \ + UTIL_DEBUG_TYPE_ ## type, \ + fmt, ##__VA_ARGS__); \ } while (0) -struct pipe_debug_callback; - void -_pipe_debug_message( - struct pipe_debug_callback *cb, +_util_debug_message( + struct util_debug_callback *cb, unsigned *id, - enum pipe_debug_type type, + enum util_debug_type type, const char *fmt, ...) _util_printf_format(4, 5); @@ -294,7 +289,7 @@ struct debug_named_value /** * Some C pre-processor magic to simplify creating named values. - * + * * Example: * @code * static const debug_named_value my_names[] = { @@ -303,16 +298,16 @@ struct debug_named_value * DEBUG_NAMED_VALUE(MY_ENUM_VALUE_Z), * DEBUG_NAMED_VALUE_END * }; - * + * * ... - * debug_printf("%s = %s\n", + * debug_printf("%s = %s\n", * name, * debug_dump_enum(my_names, my_value)); * ... * @endcode */ -#define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (unsigned long)__symbol, NULL} -#define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (unsigned long)__symbol, __desc} +#define DEBUG_NAMED_VALUE(__symbol) {#__symbol, (uint64_t)__symbol, NULL} +#define DEBUG_NAMED_VALUE_WITH_DESCRIPTION(__symbol, __desc) {#__symbol, (uint64_t)__symbol, __desc} #define DEBUG_NAMED_VALUE_END {NULL, 0, NULL} @@ -320,83 +315,68 @@ struct debug_named_value * Convert a enum value to a string. */ const char * -debug_dump_enum(const struct debug_named_value *names, - unsigned long value); - -const char * -debug_dump_enum_noprefix(const struct debug_named_value *names, - const char *prefix, - unsigned long value); - +debug_dump_enum(const struct debug_named_value *names, + uint64_t value); /** * Convert binary flags value to a string. */ const char * -debug_dump_flags(const struct debug_named_value *names, - unsigned long value); +debug_dump_flags(const struct debug_named_value *names, + uint64_t value); -/** - * Function enter exit loggers - */ -#ifdef DEBUG -int debug_funclog_enter(const char* f, const int line, const char* file); -void debug_funclog_exit(const char* f, const int line, const char* file); -void debug_funclog_enter_exit(const char* f, const int line, const char* file); - -#define DEBUG_FUNCLOG_ENTER() \ - int __debug_decleration_work_around = \ - debug_funclog_enter(__FUNCTION__, __LINE__, __FILE__) -#define DEBUG_FUNCLOG_EXIT() \ - do { \ - (void)__debug_decleration_work_around; \ - debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \ - return; \ - } while(0) -#define DEBUG_FUNCLOG_EXIT_RET(ret) \ - do { \ - (void)__debug_decleration_work_around; \ - debug_funclog_exit(__FUNCTION__, __LINE__, __FILE__); \ - return ret; \ - } while(0) -#define DEBUG_FUNCLOG_ENTER_EXIT() \ - debug_funclog_enter_exit(__FUNCTION__, __LINE__, __FILE__) +struct debug_control { + const char * string; + uint64_t flag; +}; -#else -#define DEBUG_FUNCLOG_ENTER() \ - int __debug_decleration_work_around -#define DEBUG_FUNCLOG_EXIT() \ - do { (void)__debug_decleration_work_around; return; } while(0) -#define DEBUG_FUNCLOG_EXIT_RET(ret) \ - do { (void)__debug_decleration_work_around; return ret; } while(0) -#define DEBUG_FUNCLOG_ENTER_EXIT() -#endif +uint64_t +parse_debug_string(const char *debug, + const struct debug_control *control); +uint64_t +parse_enable_string(const char *debug, + uint64_t default_value, + const struct debug_control *control); + + +bool +comma_separated_list_contains(const char *list, const char *s); + /** * Get option. - * - * It is an alias for getenv on Linux. - * - * On Windows it reads C:\gallium.cfg, which is a text file with CR+LF line - * endings with one option per line as - * - * NAME=value - * - * This file must be terminated with an extra empty line. + * + * It is an alias for getenv on Unix and Windows. + * */ const char * debug_get_option(const char *name, const char *dfault); -boolean -debug_get_bool_option(const char *name, boolean dfault); +const char * +debug_get_option_cached(const char *name, const char *dfault); + +bool +debug_parse_bool_option(const char *str, bool dfault); + +bool +debug_get_bool_option(const char *name, bool dfault); + +int64_t +debug_parse_num_option(const char *str, int64_t dfault); -long -debug_get_num_option(const char *name, long dfault); +int64_t +debug_get_num_option(const char *name, int64_t dfault); + +uint64_t +debug_parse_flags_option(const char *name, + const char *str, + const struct debug_named_value *flags, + uint64_t dfault); uint64_t -debug_get_flags_option(const char *name, +debug_get_flags_option(const char *name, const struct debug_named_value *flags, uint64_t dfault); @@ -404,56 +384,82 @@ debug_get_flags_option(const char *name, static const char * \ debug_get_option_ ## suffix (void) \ { \ - static boolean first = TRUE; \ + static bool initialized = false; \ static const char * value; \ - if (first) { \ - first = FALSE; \ - value = debug_get_option(name, dfault); \ + if (unlikely(!p_atomic_read_relaxed(&initialized))) { \ + const char *str = debug_get_option_cached(name, dfault); \ + p_atomic_set(&value, str); \ + p_atomic_set(&initialized, true); \ } \ return value; \ } +static inline bool +__normal_user(void) +{ +#if defined(_WIN32) + return true; +#else + return issetugid() == 0 && geteuid() == getuid() && getegid() == getgid(); +#endif +} + +#ifndef HAVE_SECURE_GETENV +static inline char *secure_getenv(const char *name) +{ + if (issetugid()) + return NULL; + return getenv(name); +} +#endif + #define DEBUG_GET_ONCE_BOOL_OPTION(sufix, name, dfault) \ -static boolean \ +static bool \ debug_get_option_ ## sufix (void) \ { \ - static boolean first = TRUE; \ - static boolean value; \ - if (first) { \ - first = FALSE; \ - value = debug_get_bool_option(name, dfault); \ + static bool initialized = false; \ + static bool value; \ + if (unlikely(!p_atomic_read_relaxed(&initialized))) { \ + const char *str = debug_get_option_cached(name, NULL); \ + bool parsed_value = debug_parse_bool_option(str, dfault); \ + p_atomic_set(&value, parsed_value); \ + p_atomic_set(&initialized, true); \ } \ return value; \ } #define DEBUG_GET_ONCE_NUM_OPTION(sufix, name, dfault) \ -static long \ +static int64_t \ debug_get_option_ ## sufix (void) \ { \ - static boolean first = TRUE; \ - static long value; \ - if (first) { \ - first = FALSE; \ - value = debug_get_num_option(name, dfault); \ + static bool initialized = false; \ + static int64_t value; \ + if (unlikely(!p_atomic_read_relaxed(&initialized))) { \ + const char *str = debug_get_option_cached(name, NULL); \ + int64_t parsed_value = debug_parse_num_option(str, dfault); \ + p_atomic_set(&value, parsed_value); \ + p_atomic_set(&initialized, true); \ } \ return value; \ } #define DEBUG_GET_ONCE_FLAGS_OPTION(sufix, name, flags, dfault) \ -static unsigned long \ +static uint64_t \ debug_get_option_ ## sufix (void) \ { \ - static boolean first = TRUE; \ - static unsigned long value; \ - if (first) { \ - first = FALSE; \ - value = debug_get_flags_option(name, flags, dfault); \ + static bool initialized = false; \ + static uint64_t value; \ + if (unlikely(!p_atomic_read_relaxed(&initialized))) { \ + const char *str = debug_get_option_cached(name, NULL); \ + uint64_t parsed_value = debug_parse_flags_option(name, str, flags, dfault); \ + p_atomic_set(&value, parsed_value); \ + p_atomic_set(&initialized, true); \ } \ return value; \ } -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/lib/mesa/src/util/u_debug_describe.c b/lib/mesa/src/util/u_debug_describe.c deleted file mode 100644 index 8bfd970a5..000000000 --- a/lib/mesa/src/util/u_debug_describe.c +++ /dev/null @@ -1,109 +0,0 @@ -/************************************************************************** - * - * Copyright 2010 Luca Barbieri - * - * 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 COPYRIGHT OWNER(S) 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 "pipe/p_state.h" -#include "util/format/u_format.h" -#include "util/u_debug_describe.h" -#include "util/u_string.h" - -void -debug_describe_reference(char* buf, UNUSED const struct pipe_reference*ptr) -{ - strcpy(buf, "pipe_object"); -} - -void -debug_describe_resource(char* buf, const struct pipe_resource *ptr) -{ - switch(ptr->target) - { - case PIPE_BUFFER: - sprintf(buf, "pipe_buffer<%u>", (unsigned)util_format_get_stride(ptr->format, ptr->width0)); - break; - case PIPE_TEXTURE_1D: - sprintf(buf, "pipe_texture1d<%u,%s,%u>", ptr->width0, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_2D: - sprintf(buf, "pipe_texture2d<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_RECT: - sprintf(buf, "pipe_texture_rect<%u,%u,%s>", ptr->width0, ptr->height0, util_format_short_name(ptr->format)); - break; - case PIPE_TEXTURE_CUBE: - sprintf(buf, "pipe_texture_cube<%u,%u,%s,%u>", ptr->width0, ptr->height0, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_3D: - sprintf(buf, "pipe_texture3d<%u,%u,%u,%s,%u>", ptr->width0, ptr->height0, ptr->depth0, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_1D_ARRAY: - sprintf(buf, "pipe_texture_1darray<%u,%u,%s,%u>", ptr->width0, ptr->array_size, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_2D_ARRAY: - sprintf(buf, "pipe_texture_2darray<%u,%u,%u,%s,%u>", ptr->width0, ptr->height0, ptr->array_size, util_format_short_name(ptr->format), ptr->last_level); - break; - case PIPE_TEXTURE_CUBE_ARRAY: - sprintf(buf, "pipe_texture_cubearray<%u,%u,%u,%s,%u>", ptr->width0, ptr->height0, ptr->array_size, util_format_short_name(ptr->format), ptr->last_level); - break; - default: - sprintf(buf, "pipe_martian_resource<%u>", ptr->target); - break; - } -} - -void -debug_describe_surface(char* buf, const struct pipe_surface *ptr) -{ - char res[128]; - debug_describe_resource(res, ptr->texture); - sprintf(buf, "pipe_surface<%s,%u,%u,%u>", res, ptr->u.tex.level, ptr->u.tex.first_layer, ptr->u.tex.last_layer); -} - -void -debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr) -{ - char res[128]; - debug_describe_resource(res, ptr->texture); - sprintf(buf, "pipe_sampler_view<%s,%s>", res, util_format_short_name(ptr->format)); -} - -void -debug_describe_image_view(char* buf, const struct pipe_image_view *ptr) -{ - char res[128]; - debug_describe_resource(res, ptr->resource); - sprintf(buf, "pipe_image_view<%s,%s>", res, - util_format_short_name(ptr->format)); -} - -void -debug_describe_so_target(char* buf, - const struct pipe_stream_output_target *ptr) -{ - char res[128]; - debug_describe_resource(res, ptr->buffer); - sprintf(buf, "pipe_stream_output_target<%s,%u,%u>", res, - ptr->buffer_offset, ptr->buffer_size); -} diff --git a/lib/mesa/src/util/u_debug_describe.h b/lib/mesa/src/util/u_debug_describe.h deleted file mode 100644 index 2172ecb43..000000000 --- a/lib/mesa/src/util/u_debug_describe.h +++ /dev/null @@ -1,53 +0,0 @@ -/************************************************************************** - * - * Copyright 2010 Luca Barbieri - * - * 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 COPYRIGHT OWNER(S) 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_DEBUG_DESCRIBE_H_ -#define U_DEBUG_DESCRIBE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -struct pipe_reference; -struct pipe_resource; -struct pipe_surface; -struct pipe_sampler_view; -struct pipe_image_view; - -/* a 256-byte buffer is necessary and sufficient */ -void debug_describe_reference(char* buf, const struct pipe_reference*ptr); -void debug_describe_resource(char* buf, const struct pipe_resource *ptr); -void debug_describe_surface(char* buf, const struct pipe_surface *ptr); -void debug_describe_sampler_view(char* buf, const struct pipe_sampler_view *ptr); -void debug_describe_image_view(char* buf, const struct pipe_image_view *ptr); -void debug_describe_so_target(char* buf, - const struct pipe_stream_output_target *ptr); - -#ifdef __cplusplus -} -#endif - -#endif /* U_DEBUG_DESCRIBE_H_ */ diff --git a/lib/mesa/src/util/u_debug_refcnt.c b/lib/mesa/src/util/u_debug_refcnt.c deleted file mode 100644 index 06498eb67..000000000 --- a/lib/mesa/src/util/u_debug_refcnt.c +++ /dev/null @@ -1,200 +0,0 @@ -/************************************************************************** - * - * Copyright 2010 Luca Barbieri - * - * 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 COPYRIGHT OWNER(S) 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. - * - **************************************************************************/ - -#if defined(DEBUG) - -/** - * If the GALLIUM_REFCNT_LOG env var is defined as a filename, gallium - * reference counting will be logged to the file. - * - * See http://www-archive.mozilla.org/performance/refcnt-balancer.html - * for what to do with the output on Linux, use tools/addr2line.sh to - * postprocess it before anything else. - */ - -#include <stdio.h> - -#include "util/u_debug.h" -#include "util/u_debug_refcnt.h" -#include "util/u_debug_stack.h" -#include "util/u_debug_symbol.h" -#include "util/u_string.h" -#include "util/u_hash_table.h" -#include "util/u_thread.h" - -int debug_refcnt_state; - -static FILE *stream; - -/* TODO: maybe move this serial machinery to a stand-alone module and - * expose it? - */ -#ifdef PIPE_OS_WINDOWS -static mtx_t serials_mutex; -#else -static mtx_t serials_mutex = _MTX_INITIALIZER_NP; -#endif - -static struct hash_table *serials_hash; -static unsigned serials_last; - - -/** - * Return a small integer serial number for the given pointer. - */ -static boolean -debug_serial(void *p, unsigned *pserial) -{ - unsigned serial; - boolean found = TRUE; -#ifdef PIPE_OS_WINDOWS - static boolean first = TRUE; - - if (first) { - (void) mtx_init(&serials_mutex, mtx_plain); - first = FALSE; - } -#endif - - mtx_lock(&serials_mutex); - if (!serials_hash) - serials_hash = util_hash_table_create_ptr_keys(); - - serial = (unsigned) (uintptr_t) util_hash_table_get(serials_hash, p); - if (!serial) { - /* time to stop logging... (you'll have a 100 GB logfile at least at - * this point) TODO: avoid this - */ - serial = ++serials_last; - if (!serial) { - debug_error("More than 2^32 objects detected, aborting.\n"); - os_abort(); - } - - _mesa_hash_table_insert(serials_hash, p, (void *) (uintptr_t) serial); - found = FALSE; - } - mtx_unlock(&serials_mutex); - - *pserial = serial; - - return found; -} - - -/** - * Free the serial number for the given pointer. - */ -static void -debug_serial_delete(void *p) -{ - mtx_lock(&serials_mutex); - _mesa_hash_table_remove_key(serials_hash, p); - mtx_unlock(&serials_mutex); -} - - -#if defined(PIPE_OS_WINDOWS) -#define STACK_LEN 60 -#else -#define STACK_LEN 64 -#endif - -/** - * Log a reference count change to the log file (if enabled). - * This is called via the pipe_reference() and debug_reference() functions, - * basically whenever a reference count is initialized or changed. - * - * \param p the refcount being changed (the value is not changed here) - * \param get_desc a function which will be called to print an object's - * name/pointer into a string buffer during logging - * \param change the reference count change which must be +/-1 or 0 when - * creating the object and initializing the refcount. - */ -void -debug_reference_slowpath(const struct pipe_reference *p, - debug_reference_descriptor get_desc, int change) -{ - assert(change >= -1); - assert(change <= 1); - - if (debug_refcnt_state < 0) - return; - - if (!debug_refcnt_state) { - const char *filename = debug_get_option("GALLIUM_REFCNT_LOG", NULL); - if (filename && filename[0]) - stream = fopen(filename, "wt"); - - if (stream) - debug_refcnt_state = 1; - else - debug_refcnt_state = -1; - } - - if (debug_refcnt_state > 0) { - struct debug_stack_frame frames[STACK_LEN]; - char buf[1024]; - unsigned i; - unsigned refcnt = p->count; - unsigned serial; - boolean existing = debug_serial((void *) p, &serial); - - debug_backtrace_capture(frames, 1, STACK_LEN); - - get_desc(buf, p); - - if (!existing) { - fprintf(stream, "<%s> %p %u Create\n", buf, (void *) p, serial); - debug_backtrace_print(stream, frames, STACK_LEN); - - /* this is here to provide a gradual change even if we don't see - * the initialization - */ - for (i = 1; i <= refcnt - change; ++i) { - fprintf(stream, "<%s> %p %u AddRef %u\n", buf, (void *) p, - serial, i); - debug_backtrace_print(stream, frames, STACK_LEN); - } - } - - if (change) { - fprintf(stream, "<%s> %p %u %s %u\n", buf, (void *) p, serial, - change > 0 ? "AddRef" : "Release", refcnt); - debug_backtrace_print(stream, frames, STACK_LEN); - } - - if (!refcnt) { - debug_serial_delete((void *) p); - fprintf(stream, "<%s> %p %u Destroy\n", buf, (void *) p, serial); - debug_backtrace_print(stream, frames, STACK_LEN); - } - - fflush(stream); - } -} - -#endif /* DEBUG */ diff --git a/lib/mesa/src/util/u_debug_refcnt.h b/lib/mesa/src/util/u_debug_refcnt.h deleted file mode 100644 index 78f690b02..000000000 --- a/lib/mesa/src/util/u_debug_refcnt.h +++ /dev/null @@ -1,69 +0,0 @@ -/************************************************************************** - * - * Copyright 2010 Luca Barbieri - * - * 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 COPYRIGHT OWNER(S) 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_DEBUG_REFCNT_H_ -#define U_DEBUG_REFCNT_H_ - -#include "pipe/p_config.h" -#include "pipe/p_state.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*debug_reference_descriptor)(char*, const struct pipe_reference*); - -#if defined(DEBUG) - -extern int debug_refcnt_state; - -void -debug_reference_slowpath(const struct pipe_reference* p, - debug_reference_descriptor get_desc, int change); - -static inline void -debug_reference(const struct pipe_reference* p, - debug_reference_descriptor get_desc, int change) -{ - if (debug_refcnt_state >= 0) - debug_reference_slowpath(p, get_desc, change); -} - -#else - -static inline void -debug_reference(UNUSED const struct pipe_reference* p, - UNUSED debug_reference_descriptor get_desc, UNUSED int change) -{ -} - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* U_DEBUG_REFCNT_H_ */ diff --git a/lib/mesa/src/util/u_dynarray.h b/lib/mesa/src/util/u_dynarray.h index 769669e1e..b8fff5b8a 100644 --- a/lib/mesa/src/util/u_dynarray.h +++ b/lib/mesa/src/util/u_dynarray.h @@ -36,7 +36,7 @@ extern "C" { #endif -static unsigned util_dynarray_is_data_stack_allocated; +extern unsigned util_dynarray_is_data_stack_allocated; /* A zero-initialized version of this is guaranteed to represent an * empty array. diff --git a/lib/mesa/src/util/u_queue.c b/lib/mesa/src/util/u_queue.c index ed1e96b10..750dd2015 100644 --- a/lib/mesa/src/util/u_queue.c +++ b/lib/mesa/src/util/u_queue.c @@ -442,9 +442,10 @@ util_queue_init(struct util_queue *queue, snprintf(queue->name, sizeof(queue->name), "%s", name); } + queue->create_threads_on_demand = true; queue->flags = flags; queue->max_threads = num_threads; - queue->num_threads = (flags & UTIL_QUEUE_INIT_SCALE_THREADS) ? 1 : num_threads; + queue->num_threads = 1; queue->max_jobs = max_jobs; queue->global_data = global_data; @@ -582,7 +583,7 @@ util_queue_add_job_locked(struct util_queue *queue, /* Scale the number of threads up if there's already one job waiting. */ if (queue->num_queued > 0 && - queue->flags & UTIL_QUEUE_INIT_SCALE_THREADS && + queue->create_threads_on_demand && execute != util_queue_finish_execute && queue->num_threads < queue->max_threads) { util_queue_adjust_num_threads(queue, queue->num_threads + 1, true); @@ -719,8 +720,7 @@ util_queue_finish(struct util_queue *queue) * Also note that util_queue_add_job can unlock the mutex if there is not * enough space in the queue and wait for space. */ - unsigned saved_flags = queue->flags; - queue->flags &= ~UTIL_QUEUE_INIT_SCALE_THREADS; + queue->create_threads_on_demand = false; fences = malloc(queue->num_threads * sizeof(*fences)); util_barrier_init(&barrier, queue->num_threads); @@ -730,7 +730,7 @@ util_queue_finish(struct util_queue *queue) util_queue_add_job_locked(queue, &barrier, &fences[i], util_queue_finish_execute, NULL, 0, true); } - queue->flags = saved_flags; + queue->create_threads_on_demand = true; mtx_unlock(&queue->lock); for (unsigned i = 0; i < queue->num_threads; ++i) { diff --git a/lib/mesa/src/util/u_queue.h b/lib/mesa/src/util/u_queue.h index 25f2c1589..ae7516c03 100644 --- a/lib/mesa/src/util/u_queue.h +++ b/lib/mesa/src/util/u_queue.h @@ -50,7 +50,6 @@ extern "C" { #define UTIL_QUEUE_INIT_USE_MINIMUM_PRIORITY (1 << 0) #define UTIL_QUEUE_INIT_RESIZE_IF_FULL (1 << 1) #define UTIL_QUEUE_INIT_SET_FULL_THREAD_AFFINITY (1 << 2) -#define UTIL_QUEUE_INIT_SCALE_THREADS (1 << 3) #if UTIL_FUTEX_SUPPORTED #define UTIL_QUEUE_FENCE_FUTEX @@ -206,6 +205,7 @@ struct util_queue_job { struct util_queue { char name[14]; /* 13 characters = the thread name without the index */ mtx_t lock; + bool create_threads_on_demand; cnd_t has_queued_cond; cnd_t has_space_cond; thrd_t *threads; diff --git a/lib/mesa/src/util/u_string.h b/lib/mesa/src/util/u_string.h index 8fead06b6..b9142d761 100644 --- a/lib/mesa/src/util/u_string.h +++ b/lib/mesa/src/util/u_string.h @@ -35,12 +35,10 @@ #ifndef U_STRING_H_ #define U_STRING_H_ -#if !defined(XF86_LIBC_H) -#include <stdio.h> -#endif #include <stdlib.h> #include <stddef.h> #include <stdarg.h> +#include <stdio.h> #include <string.h> #include <limits.h> @@ -102,6 +100,7 @@ util_vasprintf(char **ret, const char *format, va_list ap) #define asprintf util_asprintf static inline int + PRINTFLIKE(2, 3) util_asprintf(char **str, const char *fmt, ...) { int ret; @@ -118,11 +117,11 @@ util_asprintf(char **str, const char *fmt, ...) #define strdup _strdup -#if defined(_WIN32) && !defined(HAVE_STRTOK_R) +#if !defined(HAVE_STRTOK_R) #define strtok_r strtok_s #endif -#endif +#endif /* _WIN32 */ #ifdef __cplusplus diff --git a/lib/mesa/src/util/u_vector.c b/lib/mesa/src/util/u_vector.c index 3c5593da7..cd23b963e 100644 --- a/lib/mesa/src/util/u_vector.c +++ b/lib/mesa/src/util/u_vector.c @@ -78,7 +78,7 @@ u_vector_add(struct u_vector *vector) * 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); + split = align(vector->tail, vector->size); assert(vector->tail <= split && split < vector->head); memcpy((char *)data + dst_tail, (char *)vector->data + src_tail, split - vector->tail); diff --git a/lib/mesa/src/util/u_vector.h b/lib/mesa/src/util/u_vector.h index 5a1a08934..50e706e32 100644 --- a/lib/mesa/src/util/u_vector.h +++ b/lib/mesa/src/util/u_vector.h @@ -38,14 +38,6 @@ extern "C" { #endif -/* 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 & -((int32_t) a))); - return (v + a - 1) & ~(a - 1); -} - struct u_vector { uint32_t head; uint32_t tail; diff --git a/lib/mesa/src/util/xmlconfig.c b/lib/mesa/src/util/xmlconfig.c index 62b163be2..7a753e37e 100644 --- a/lib/mesa/src/util/xmlconfig.c +++ b/lib/mesa/src/util/xmlconfig.c @@ -1173,16 +1173,9 @@ initOptionCache(driOptionCache *cache, const driOptionCache *info) #define DATADIR "/usr/share" #endif -static const char *datadir = DATADIR "/drirc.d"; static const char *execname; void -driInjectDataDir(const char *dir) -{ - datadir = dir; -} - -void driInjectExecName(const char *exec) { execname = exec; @@ -1216,10 +1209,15 @@ driParseConfigFiles(driOptionCache *cache, const driOptionCache *info, userData.execName = execname; #if WITH_XMLCONFIG - char *home; - - parseConfigDir(&userData, datadir); - parseOneConfigFile(&userData, SYSCONFDIR "/drirc"); + char *home, *configdir; + + /* parse from either $DRIRC_CONFIGDIR or $datadir/drirc.d */ + if ((configdir = getenv("DRIRC_CONFIGDIR"))) + parseConfigDir(&userData, configdir); + else { + parseConfigDir(&userData, DATADIR "/drirc.d"); + parseOneConfigFile(&userData, SYSCONFDIR "/drirc"); + } if ((home = getenv("HOME"))) { char filename[PATH_MAX]; diff --git a/lib/mesa/src/util/xmlconfig.h b/lib/mesa/src/util/xmlconfig.h index 7405f0cb9..8d063974c 100644 --- a/lib/mesa/src/util/xmlconfig.h +++ b/lib/mesa/src/util/xmlconfig.h @@ -159,7 +159,6 @@ float driQueryOptionf(const driOptionCache *cache, const char *name); char *driQueryOptionstr(const driOptionCache *cache, const char *name); /* Overrides for the unit tests to control drirc parsing. */ -void driInjectDataDir(const char *dir); void driInjectExecName(const char *exec); /** |