17117f1b4Smrg/** 27117f1b4Smrg * \file hash.h 37ec681f3Smrg * Generic hash table. 47117f1b4Smrg */ 57117f1b4Smrg 67117f1b4Smrg/* 77117f1b4Smrg * Mesa 3-D graphics library 87117f1b4Smrg * 97117f1b4Smrg * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 107117f1b4Smrg * 117117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a 127117f1b4Smrg * copy of this software and associated documentation files (the "Software"), 137117f1b4Smrg * to deal in the Software without restriction, including without limitation 147117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 157117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the 167117f1b4Smrg * Software is furnished to do so, subject to the following conditions: 177117f1b4Smrg * 187117f1b4Smrg * The above copyright notice and this permission notice shall be included 197117f1b4Smrg * in all copies or substantial portions of the Software. 207117f1b4Smrg * 217117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 227117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 237117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE. 287117f1b4Smrg */ 297117f1b4Smrg 307117f1b4Smrg 317117f1b4Smrg#ifndef HASH_H 327117f1b4Smrg#define HASH_H 337117f1b4Smrg 347117f1b4Smrg 357ec681f3Smrg#include <stdbool.h> 367ec681f3Smrg#include <stdint.h> 377117f1b4Smrg#include "glheader.h" 387ec681f3Smrg 3901e04c3fSmrg#include "c11/threads.h" 407ec681f3Smrg#include "util/simple_mtx.h" 417ec681f3Smrg 427ec681f3Smrgstruct util_idalloc; 437117f1b4Smrg 4401e04c3fSmrg/** 4501e04c3fSmrg * Magic GLuint object name that gets stored outside of the struct hash_table. 4601e04c3fSmrg * 4701e04c3fSmrg * The hash table needs a particular pointer to be the marker for a key that 4801e04c3fSmrg * was deleted from the table, along with NULL for the "never allocated in the 4901e04c3fSmrg * table" marker. Legacy GL allows any GLuint to be used as a GL object name, 5001e04c3fSmrg * and we use a 1:1 mapping from GLuints to key pointers, so we need to be 5101e04c3fSmrg * able to track a GLuint that happens to match the deleted key outside of 5201e04c3fSmrg * struct hash_table. We tell the hash table to use "1" as the deleted key 5301e04c3fSmrg * value, so that we test the deleted-key-in-the-table path as best we can. 5401e04c3fSmrg */ 5501e04c3fSmrg#define DELETED_KEY_VALUE 1 5601e04c3fSmrg 5701e04c3fSmrg/** @{ 5801e04c3fSmrg * Mapping from our use of GLuint as both the key and the hash value to the 5901e04c3fSmrg * hash_table.h API 6001e04c3fSmrg * 6101e04c3fSmrg * There exist many integer hash functions, designed to avoid collisions when 6201e04c3fSmrg * the integers are spread across key space with some patterns. In GL, the 6301e04c3fSmrg * pattern (in the case of glGen*()ed object IDs) is that the keys are unique 6401e04c3fSmrg * contiguous integers starting from 1. Because of that, we just use the key 6501e04c3fSmrg * as the hash value, to minimize the cost of the hash function. If objects 6601e04c3fSmrg * are never deleted, we will never see a collision in the table, because the 6701e04c3fSmrg * table resizes itself when it approaches full, and thus key % table_size == 6801e04c3fSmrg * key. 6901e04c3fSmrg * 7001e04c3fSmrg * The case where we could have collisions for genned objects would be 7101e04c3fSmrg * something like: glGenBuffers(&a, 100); glDeleteBuffers(&a + 50, 50); 7201e04c3fSmrg * glGenBuffers(&b, 100), because objects 1-50 and 101-200 are allocated at 7301e04c3fSmrg * the end of that sequence, instead of 1-150. So far it doesn't appear to be 7401e04c3fSmrg * a problem. 7501e04c3fSmrg */ 7601e04c3fSmrgstatic inline bool 7701e04c3fSmrguint_key_compare(const void *a, const void *b) 7801e04c3fSmrg{ 7901e04c3fSmrg return a == b; 8001e04c3fSmrg} 8101e04c3fSmrg 8201e04c3fSmrgstatic inline uint32_t 8301e04c3fSmrguint_hash(GLuint id) 8401e04c3fSmrg{ 8501e04c3fSmrg return id; 8601e04c3fSmrg} 8701e04c3fSmrg 8801e04c3fSmrgstatic inline uint32_t 8901e04c3fSmrguint_key_hash(const void *key) 9001e04c3fSmrg{ 9101e04c3fSmrg return uint_hash((uintptr_t)key); 9201e04c3fSmrg} 9301e04c3fSmrg 9401e04c3fSmrgstatic inline void * 9501e04c3fSmrguint_key(GLuint id) 9601e04c3fSmrg{ 9701e04c3fSmrg return (void *)(uintptr_t) id; 9801e04c3fSmrg} 9901e04c3fSmrg/** @} */ 10001e04c3fSmrg 10101e04c3fSmrg/** 10201e04c3fSmrg * The hash table data structure. 10301e04c3fSmrg */ 10401e04c3fSmrgstruct _mesa_HashTable { 10501e04c3fSmrg struct hash_table *ht; 10601e04c3fSmrg GLuint MaxKey; /**< highest key inserted so far */ 1077ec681f3Smrg simple_mtx_t Mutex; /**< mutual exclusion lock */ 1087ec681f3Smrg /* Used when name reuse is enabled */ 1097ec681f3Smrg struct util_idalloc* id_alloc; 1107ec681f3Smrg 11101e04c3fSmrg /** Value that would be in the table for DELETED_KEY_VALUE. */ 11201e04c3fSmrg void *deleted_key_data; 1137ec681f3Smrg #ifndef NDEBUG 1147ec681f3Smrg GLboolean InDeleteAll; /**< Debug check */ 1157ec681f3Smrg #endif 11601e04c3fSmrg}; 1177117f1b4Smrg 1187117f1b4Smrgextern struct _mesa_HashTable *_mesa_NewHashTable(void); 1197117f1b4Smrg 1207117f1b4Smrgextern void _mesa_DeleteHashTable(struct _mesa_HashTable *table); 1217117f1b4Smrg 1224a49301eSmrgextern void *_mesa_HashLookup(struct _mesa_HashTable *table, GLuint key); 1237117f1b4Smrg 1247ec681f3Smrgextern void _mesa_HashInsert(struct _mesa_HashTable *table, GLuint key, void *data, 1257ec681f3Smrg GLboolean isGenName); 1267117f1b4Smrg 1277117f1b4Smrgextern void _mesa_HashRemove(struct _mesa_HashTable *table, GLuint key); 1287117f1b4Smrg 12901e04c3fSmrg/** 13001e04c3fSmrg * Lock the hash table mutex. 13101e04c3fSmrg * 13201e04c3fSmrg * This function should be used when multiple objects need 13301e04c3fSmrg * to be looked up in the hash table, to avoid having to lock 13401e04c3fSmrg * and unlock the mutex each time. 13501e04c3fSmrg * 13601e04c3fSmrg * \param table the hash table. 13701e04c3fSmrg */ 13801e04c3fSmrgstatic inline void 13901e04c3fSmrg_mesa_HashLockMutex(struct _mesa_HashTable *table) 14001e04c3fSmrg{ 14101e04c3fSmrg assert(table); 1427ec681f3Smrg simple_mtx_lock(&table->Mutex); 14301e04c3fSmrg} 14401e04c3fSmrg 145af69d88dSmrg 14601e04c3fSmrg/** 14701e04c3fSmrg * Unlock the hash table mutex. 14801e04c3fSmrg * 14901e04c3fSmrg * \param table the hash table. 15001e04c3fSmrg */ 15101e04c3fSmrgstatic inline void 15201e04c3fSmrg_mesa_HashUnlockMutex(struct _mesa_HashTable *table) 15301e04c3fSmrg{ 15401e04c3fSmrg assert(table); 1557ec681f3Smrg simple_mtx_unlock(&table->Mutex); 15601e04c3fSmrg} 157af69d88dSmrg 158af69d88dSmrgextern void *_mesa_HashLookupLocked(struct _mesa_HashTable *table, GLuint key); 159af69d88dSmrg 160af69d88dSmrgextern void _mesa_HashInsertLocked(struct _mesa_HashTable *table, 1617ec681f3Smrg GLuint key, void *data, GLboolean isGenName); 162af69d88dSmrg 16301e04c3fSmrgextern void _mesa_HashRemoveLocked(struct _mesa_HashTable *table, GLuint key); 16401e04c3fSmrg 1657117f1b4Smrgextern void 1667117f1b4Smrg_mesa_HashDeleteAll(struct _mesa_HashTable *table, 1677ec681f3Smrg void (*callback)(void *data, void *userData), 1687117f1b4Smrg void *userData); 1697117f1b4Smrg 1707117f1b4Smrgextern void 1717117f1b4Smrg_mesa_HashWalk(const struct _mesa_HashTable *table, 1727ec681f3Smrg void (*callback)(void *data, void *userData), 1737117f1b4Smrg void *userData); 1747117f1b4Smrg 17501e04c3fSmrgextern void 17601e04c3fSmrg_mesa_HashWalkLocked(const struct _mesa_HashTable *table, 1777ec681f3Smrg void (*callback)(void *data, void *userData), 17801e04c3fSmrg void *userData); 17901e04c3fSmrg 1807117f1b4Smrgextern void _mesa_HashPrint(const struct _mesa_HashTable *table); 1817117f1b4Smrg 1827117f1b4Smrgextern GLuint _mesa_HashFindFreeKeyBlock(struct _mesa_HashTable *table, GLuint numKeys); 1837117f1b4Smrg 1847ec681f3Smrgextern bool 1857ec681f3Smrg_mesa_HashFindFreeKeys(struct _mesa_HashTable *table, GLuint* keys, GLuint numKeys); 1867ec681f3Smrg 187af69d88dSmrgextern GLuint 188af69d88dSmrg_mesa_HashNumEntries(const struct _mesa_HashTable *table); 189af69d88dSmrg 1907117f1b4Smrgextern void _mesa_test_hash_functions(void); 1917117f1b4Smrg 1927ec681f3Smrgextern void _mesa_HashEnableNameReuse(struct _mesa_HashTable *table); 1937ec681f3Smrg 1947ec681f3Smrgstatic inline void 1957ec681f3Smrg_mesa_HashWalkMaybeLocked(const struct _mesa_HashTable *table, 1967ec681f3Smrg void (*callback)(void *data, void *userData), 1977ec681f3Smrg void *userData, bool locked) 1987ec681f3Smrg{ 1997ec681f3Smrg if (locked) 2007ec681f3Smrg _mesa_HashWalkLocked(table, callback, userData); 2017ec681f3Smrg else 2027ec681f3Smrg _mesa_HashWalk(table, callback, userData); 2037ec681f3Smrg} 2047ec681f3Smrg 2057ec681f3Smrgstatic inline struct gl_buffer_object * 2067ec681f3Smrg_mesa_HashLookupMaybeLocked(struct _mesa_HashTable *table, GLuint key, 2077ec681f3Smrg bool locked) 2087ec681f3Smrg{ 2097ec681f3Smrg if (locked) 2107ec681f3Smrg return _mesa_HashLookupLocked(table, key); 2117ec681f3Smrg else 2127ec681f3Smrg return _mesa_HashLookup(table, key); 2137ec681f3Smrg} 2147ec681f3Smrg 2157ec681f3Smrgstatic inline void 2167ec681f3Smrg_mesa_HashInsertMaybeLocked(struct _mesa_HashTable *table, 2177ec681f3Smrg GLuint key, void *data, GLboolean isGenName, 2187ec681f3Smrg bool locked) 2197ec681f3Smrg{ 2207ec681f3Smrg if (locked) 2217ec681f3Smrg _mesa_HashInsertLocked(table, key, data, isGenName); 2227ec681f3Smrg else 2237ec681f3Smrg _mesa_HashInsert(table, key, data, isGenName); 2247ec681f3Smrg} 2257ec681f3Smrg 2267ec681f3Smrgstatic inline void 2277ec681f3Smrg_mesa_HashLockMaybeLocked(struct _mesa_HashTable *table, bool locked) 2287ec681f3Smrg{ 2297ec681f3Smrg if (!locked) 2307ec681f3Smrg _mesa_HashLockMutex(table); 2317ec681f3Smrg} 2327ec681f3Smrg 2337ec681f3Smrgstatic inline void 2347ec681f3Smrg_mesa_HashUnlockMaybeLocked(struct _mesa_HashTable *table, bool locked) 2357ec681f3Smrg{ 2367ec681f3Smrg if (!locked) 2377ec681f3Smrg _mesa_HashUnlockMutex(table); 2387ec681f3Smrg} 2397117f1b4Smrg 2407117f1b4Smrg#endif 241