VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/util/hash.c@ 58312

Last change on this file since 58312 was 56566, checked in by vboxsync, 10 years ago

Host 3D: Expando SPU, DLM module.

  • DLM module reworked. Now it uses hardware way in order to execute Display List (software approach dropped);
  • Chromium/utils slightly extended with more helper functions needed for Expando/DLM;
  • More testing needed especially for glCallLists() and glListBase();
  • Expando/DLM code now enabed for Mac hosts.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_threads.h"
8#include "cr_hash.h"
9#include "cr_mem.h"
10#include "cr_error.h"
11
12#include <iprt/list.h>
13
14#define CR_MAXUINT ((GLuint) 0xFFFFFFFF)
15#define CR_HASH_ID_MIN ((GLuint)1)
16#define CR_HASH_ID_MAX CR_MAXUINT
17
18#define CR_NUM_BUCKETS 1047
19
20typedef struct FreeElemRec {
21 RTLISTNODE Node;
22 GLuint min;
23 GLuint max;
24} FreeElem;
25
26struct CRHashIdPool {
27 RTLISTNODE freeList;
28 GLuint min;
29 GLuint max;
30};
31
32typedef struct CRHashNode {
33 unsigned long key;
34 void *data;
35 struct CRHashNode *next;
36} CRHashNode;
37
38struct CRHashTable {
39 unsigned int num_elements;
40 CRHashNode *buckets[CR_NUM_BUCKETS];
41 CRHashIdPool *idPool;
42#ifdef CHROMIUM_THREADSAFE
43 CRmutex mutex;
44#endif
45};
46
47
48CRHashIdPool *crAllocHashIdPoolEx( GLuint min, GLuint max )
49{
50 CRHashIdPool *pool;
51 FreeElem *elem;
52 if (min < CR_HASH_ID_MIN || max > CR_HASH_ID_MAX || min >= max)
53 {
54 crWarning("invalid min man vals");
55 return NULL;
56 }
57 pool = (CRHashIdPool *) crCalloc(sizeof(CRHashIdPool));
58 elem = (FreeElem *) crCalloc(sizeof(FreeElem));
59 RTListInit(&pool->freeList);
60 elem->min = min;
61 elem->max = max;
62 RTListAppend(&pool->freeList, &elem->Node);
63 pool->min = min;
64 pool->max = max;
65 return pool;
66}
67
68CRHashIdPool *crAllocHashIdPool( void )
69{
70 return crAllocHashIdPoolEx( CR_HASH_ID_MIN, CR_HASH_ID_MAX );
71}
72
73void crFreeHashIdPool( CRHashIdPool *pool )
74{
75 FreeElem *i, *next;
76 RTListForEachSafe(&pool->freeList, i, next, FreeElem, Node)
77 {
78 crFree(i);
79 }
80
81 crFree(pool);
82}
83
84#ifdef DEBUG_misha
85static void crHashIdPoolDbgCheckConsistency(CRHashIdPool *pool)
86{
87 FreeElem *i;
88 GLuint min = 0;
89
90 /* null is a special case, it is always treated as allocated */
91 Assert(!crHashIdPoolIsIdFree(pool, 0));
92
93 /* first ensure entries have correct values */
94 RTListForEach(&pool->freeList, i, FreeElem, Node)
95 {
96 Assert(i->min >= pool->min);
97 Assert(i->max <= pool->max);
98 Assert(i->min < i->max);
99 }
100
101 /* now ensure entries do not intersect */
102 /* and that they are sorted */
103 RTListForEach(&pool->freeList, i, FreeElem, Node)
104 {
105 Assert(min < i->min);
106 min = i->max;
107 }
108}
109
110static void crHashIdPoolDbgCheckUsed( const CRHashIdPool *pool, GLuint start, GLuint count, GLboolean fUsed )
111{
112 GLuint i;
113 CRASSERT(count);
114 CRASSERT(start >= pool->min);
115 CRASSERT(start + count <= pool->max);
116 CRASSERT(start + count > start);
117 for (i = 0; i < count; ++i)
118 {
119 Assert(!fUsed == !!crHashIdPoolIsIdFree( pool, start + i ));
120 }
121}
122
123# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { \
124 crHashIdPoolDbgCheckConsistency((_p)); \
125 crHashIdPoolDbgCheckUsed( (_p), (_start), (_count), (_used) ); \
126 } while (0)
127
128# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { crHashIdPoolDbgCheckConsistency((_p)); } while (0)
129#else
130# define CR_HASH_IDPOOL_DBG_CHECK_USED(_p, _start, _count, _used) do { } while (0)
131# define CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(_p) do { } while (0)
132#endif
133
134/*
135 * Allocate a block of <count> IDs. Return index of first one.
136 * Return 0 if we fail.
137 */
138GLuint crHashIdPoolAllocBlock( CRHashIdPool *pool, GLuint count )
139{
140 FreeElem *f, *next;
141 GLuint ret;
142
143 CRASSERT(count > 0);
144 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
145 {
146 Assert(f->max > f->min);
147 if (f->max - f->min >= (GLuint) count)
148 {
149 /* found a sufficiently large enough block */
150 ret = f->min;
151 f->min += count;
152 if (f->min == f->max)
153 {
154 RTListNodeRemove(&f->Node);
155 crFree(f);
156 }
157
158 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, ret, count, GL_TRUE);
159 return ret;
160 }
161 }
162
163 /* failed to find free block */
164 crWarning("crHashIdPoolAllocBlock failed");
165 CR_HASH_IDPOOL_DBG_CHECK_CONSISTENCY(pool);
166 return 0;
167}
168
169
170/*
171 * Free a block of <count> IDs starting at <first>.
172 */
173void crHashIdPoolFreeBlock( CRHashIdPool *pool, GLuint first, GLuint count )
174{
175 FreeElem *f;
176 GLuint last;
177 GLuint newMax;
178 FreeElem *cur, *curNext;
179
180 /* null is a special case, it is always treated as allocated */
181 if (!first)
182 {
183 Assert(!crHashIdPoolIsIdFree(pool, 0));
184 ++first;
185 --count;
186 if (!count)
187 return;
188 }
189
190 last = first + count;
191 CRASSERT(count > 0);
192 CRASSERT(last > first);
193 CRASSERT(first >= pool->min);
194 CRASSERT(last <= pool->max);
195
196 /* the id list is sorted, first find a place to insert */
197 RTListForEach(&pool->freeList, f, FreeElem, Node)
198 {
199 Assert(f->max > f->min);
200
201 if (f->max < first)
202 continue;
203
204 if (f->min > last)
205 {
206 /* we are here because first is > than prevEntry->max
207 * otherwise the previous loop iterations should handle that */
208 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
209 elem->min = first;
210 elem->max = last;
211 RTListNodeInsertBefore(&f->Node, &elem->Node);
212 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
213 return;
214 }
215
216 /* now we have f->min <= last and f->max >= first,
217 * so we have either intersection */
218
219 if (f->min > first)
220 f->min = first; /* first is guaranteed not to touch any prev regions */
221
222 newMax = last;
223
224 if (f->max >= last)
225 {
226 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
227 return;
228 }
229
230 for (cur = RTListNodeGetNext(&f->Node, FreeElem, Node),
231 curNext = RT_FROM_MEMBER(cur->Node.pNext, FreeElem, Node);
232 !RTListNodeIsDummy(&pool->freeList, cur, FreeElem, Node);
233 cur = curNext,
234 curNext = RT_FROM_MEMBER((cur)->Node.pNext, FreeElem, Node) )
235 {
236 if (cur->min > last)
237 break;
238
239 newMax = cur->max;
240 RTListNodeRemove(&cur->Node);
241 crFree(cur);
242
243 if (newMax >= last)
244 break;
245 }
246
247 f->max = newMax;
248 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
249 return;
250 }
251
252 /* we are here because either the list is empty or because all list rande elements have smaller values */
253 f = (FreeElem *) crCalloc(sizeof(FreeElem));
254 f->min = first;
255 f->max = last;
256 RTListAppend(&pool->freeList, &f->Node);
257 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, first, count, GL_FALSE);
258}
259
260
261
262/*
263 * Mark the given Id as being allocated.
264 */
265GLboolean crHashIdPoolAllocId( CRHashIdPool *pool, GLuint id )
266{
267 FreeElem *f, *next;
268
269 if (!id)
270 {
271 /* null is a special case, it is always treated as allocated */
272 Assert(!crHashIdPoolIsIdFree(pool, 0));
273 return GL_FALSE;
274 }
275
276// Assert(id != 2);
277
278 RTListForEachSafe(&pool->freeList, f, next, FreeElem, Node)
279 {
280 if (f->max <= id)
281 continue;
282 if (f->min > id)
283 {
284 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
285 return GL_FALSE;
286 }
287
288 /* f->min <= id && f->max > id */
289 if (id > f->min)
290 {
291 if (id + 1 < f->max)
292 {
293 FreeElem *elem = (FreeElem *) crCalloc(sizeof(FreeElem));
294 elem->min = id + 1;
295 elem->max = f->max;
296 RTListNodeInsertAfter(&f->Node, &elem->Node);
297 }
298 f->max = id;
299
300 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
301 }
302 else
303 {
304 Assert(id == f->min);
305 if (id + 1 < f->max)
306 {
307 f->min = id + 1;
308 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
309 }
310 else
311 {
312 RTListNodeRemove(&f->Node);
313 crFree(f);
314 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
315 }
316 }
317
318 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
319 return GL_TRUE;
320 }
321
322 /* if we get here, the ID was already allocated - that's OK */
323 CR_HASH_IDPOOL_DBG_CHECK_USED(pool, id, 1, GL_TRUE);
324 return GL_FALSE;
325}
326
327
328/*
329 * Determine if the given id is free. Return GL_TRUE if so.
330 */
331GLboolean crHashIdPoolIsIdFree( const CRHashIdPool *pool, GLuint id )
332{
333 FreeElem *f;
334 CRASSERT(id <= pool->max);
335
336 RTListForEach(&pool->freeList, f, FreeElem, Node)
337 {
338 if (f->max <= id)
339 continue;
340 if (f->min > id)
341 return GL_FALSE;
342 return GL_TRUE;
343 }
344 return GL_FALSE;
345}
346
347void crHashIdWalkKeys( CRHashIdPool *pool, CRHashIdWalkKeys walkFunc , void *data)
348{
349 FreeElem *prev = NULL, *f;
350
351 RTListForEach(&pool->freeList, f, FreeElem, Node)
352 {
353 if (prev)
354 {
355 Assert(prev->max < f->min);
356 walkFunc(prev->max+1, f->min - prev->max, data);
357 }
358 else if (f->min > pool->min)
359 {
360 walkFunc(pool->min, f->min - pool->min, data);
361 }
362
363 prev = f;
364 }
365
366 Assert(prev->max <= pool->max);
367
368 if (prev->max < pool->max)
369 {
370 walkFunc(prev->max+1, pool->max - prev->max, data);
371 }
372}
373
374CRHashTable *crAllocHashtableEx( GLuint min, GLuint max )
375{
376 int i;
377 CRHashTable *hash = (CRHashTable *) crCalloc( sizeof( CRHashTable )) ;
378 hash->num_elements = 0;
379 for (i = 0 ; i < CR_NUM_BUCKETS ; i++)
380 {
381 hash->buckets[i] = NULL;
382 }
383 hash->idPool = crAllocHashIdPoolEx( min, max );
384#ifdef CHROMIUM_THREADSAFE
385 crInitMutex(&hash->mutex);
386#endif
387 return hash;
388}
389
390CRHashTable *crAllocHashtable( void )
391{
392 return crAllocHashtableEx(CR_HASH_ID_MIN, CR_HASH_ID_MAX);
393}
394
395void crFreeHashtable( CRHashTable *hash, CRHashtableCallback deleteFunc )
396{
397 int i;
398 CRHashNode *entry, *next;
399
400 if ( !hash) return;
401
402#ifdef CHROMIUM_THREADSAFE
403 crLockMutex(&hash->mutex);
404#endif
405
406 for ( i = 0; i < CR_NUM_BUCKETS; i++ )
407 {
408 entry = hash->buckets[i];
409 while (entry)
410 {
411 next = entry->next;
412 /* Clear the key in case crHashtableDelete() is called
413 * from this callback.
414 */
415 entry->key = 0;
416 if (deleteFunc && entry->data)
417 {
418 (*deleteFunc)(entry->data);
419 }
420 crFree(entry);
421 entry = next;
422
423 }
424 }
425 crFreeHashIdPool( hash->idPool );
426
427#ifdef CHROMIUM_THREADSAFE
428 crUnlockMutex(&hash->mutex);
429 crFreeMutex(&hash->mutex);
430#endif
431
432 crFree( hash );
433}
434
435void crFreeHashtableEx(CRHashTable *hash, CRHashtableCallbackEx deleteFunc, void *pData)
436{
437 int i;
438 CRHashNode *entry, *next;
439
440 if (!hash) return;
441
442#ifdef CHROMIUM_THREADSAFE
443 crLockMutex(&hash->mutex);
444#endif
445
446 for (i = 0; i < CR_NUM_BUCKETS; i++)
447 {
448 entry = hash->buckets[i];
449 while (entry)
450 {
451 next = entry->next;
452 /* Clear the key in case crHashtableDelete() is called
453 * from this callback.
454 */
455 entry->key = 0;
456 if (deleteFunc && entry->data)
457 {
458 (*deleteFunc)(entry->data, pData);
459 }
460 crFree(entry);
461 entry = next;
462
463 }
464 }
465 crFreeHashIdPool(hash->idPool);
466
467#ifdef CHROMIUM_THREADSAFE
468 crUnlockMutex(&hash->mutex);
469 crFreeMutex(&hash->mutex);
470#endif
471
472 crFree(hash);
473}
474
475
476void crHashtableLock(CRHashTable *h)
477{
478#ifdef CHROMIUM_THREADSAFE
479 crLockMutex(&h->mutex);
480#endif
481}
482
483void crHashtableUnlock(CRHashTable *h)
484{
485#ifdef CHROMIUM_THREADSAFE
486 crUnlockMutex(&h->mutex);
487#endif
488}
489
490void crHashtableWalkUnlocked( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
491{
492 int i;
493 CRHashNode *entry, *next;
494
495 for (i = 0; i < CR_NUM_BUCKETS; i++)
496 {
497 entry = hash->buckets[i];
498 while (entry)
499 {
500 /* save next ptr here, in case walkFunc deletes this entry */
501 next = entry->next;
502 if (entry->data && walkFunc) {
503 (*walkFunc)( entry->key, entry->data, dataPtr2 );
504 }
505 entry = next;
506 }
507 }
508}
509
510void crHashtableWalk( CRHashTable *hash, CRHashtableWalkCallback walkFunc , void *dataPtr2)
511{
512 if (!hash)
513 return;
514
515#ifdef CHROMIUM_THREADSAFE
516 crLockMutex(&hash->mutex);
517#endif
518 crHashtableWalkUnlocked(hash, walkFunc , dataPtr2);
519#ifdef CHROMIUM_THREADSAFE
520 crUnlockMutex(&hash->mutex);
521#endif
522}
523
524static unsigned int crHash( unsigned long key )
525{
526 return key % CR_NUM_BUCKETS;
527}
528
529void crHashtableAdd( CRHashTable *h, unsigned long key, void *data )
530{
531 unsigned int index = crHash(key);
532 CRHashNode *node = (CRHashNode *) crCalloc( sizeof( CRHashNode ) );
533#ifdef CHROMIUM_THREADSAFE
534 crLockMutex(&h->mutex);
535#endif
536 node->key = key;
537 node->data = data;
538 node->next = h->buckets[index];
539 h->buckets[index] = node;
540 h->num_elements++;
541 crHashIdPoolAllocId (h->idPool, key);
542#ifdef CHROMIUM_THREADSAFE
543 crUnlockMutex(&h->mutex);
544#endif
545}
546
547GLboolean crHashtableAllocRegisterKey( CRHashTable *h, GLuint key)
548{
549 GLboolean fAllocated;
550#ifdef CHROMIUM_THREADSAFE
551 crLockMutex(&h->mutex);
552#endif
553 fAllocated = crHashIdPoolAllocId (h->idPool, key);
554#ifdef CHROMIUM_THREADSAFE
555 crUnlockMutex(&h->mutex);
556#endif
557 return fAllocated;
558}
559
560void crHashtableWalkKeys( CRHashTable *h, CRHashIdWalkKeys walkFunc , void *data)
561{
562#ifdef CHROMIUM_THREADSAFE
563 crLockMutex(&h->mutex);
564#endif
565 crHashIdWalkKeys(h->idPool, walkFunc , data);
566#ifdef CHROMIUM_THREADSAFE
567 crUnlockMutex(&h->mutex);
568#endif
569}
570
571GLuint crHashtableAllocKeys( CRHashTable *h, GLsizei range)
572{
573 GLuint res;
574 int i;
575
576#ifdef CHROMIUM_THREADSAFE
577 crLockMutex(&h->mutex);
578#endif
579 res = crHashIdPoolAllocBlock (h->idPool, range);
580#ifdef DEBUG_misha
581 Assert(res);
582 for (i = 0; i < range; ++i)
583 {
584 void *search = crHashtableSearch( h, res+i );
585 Assert(!search);
586 }
587#endif
588#ifdef CHROMIUM_THREADSAFE
589 crUnlockMutex(&h->mutex);
590#endif
591 return res;
592}
593
594void crHashtableDelete( CRHashTable *h, unsigned long key, CRHashtableCallback deleteFunc )
595{
596 unsigned int index = crHash( key );
597 CRHashNode *temp, *beftemp = NULL;
598
599#ifdef CHROMIUM_THREADSAFE
600 crLockMutex(&h->mutex);
601#endif
602 for ( temp = h->buckets[index]; temp; temp = temp->next )
603 {
604 if ( temp->key == key )
605 break;
606 beftemp = temp;
607 }
608 if ( temp )
609 {
610 if ( beftemp )
611 beftemp->next = temp->next;
612 else
613 h->buckets[index] = temp->next;
614 h->num_elements--;
615 if (temp->data && deleteFunc) {
616 (*deleteFunc)( temp->data );
617 }
618
619 crFree( temp );
620 }
621
622 crHashIdPoolFreeBlock( h->idPool, key, 1 );
623#ifdef CHROMIUM_THREADSAFE
624 crUnlockMutex(&h->mutex);
625#endif
626}
627
628void crHashtableDeleteEx(CRHashTable *h, unsigned long key, CRHashtableCallbackEx deleteFunc, void *pData)
629{
630 unsigned int index = crHash( key );
631 CRHashNode *temp, *beftemp = NULL;
632
633#ifdef CHROMIUM_THREADSAFE
634 crLockMutex(&h->mutex);
635#endif
636 for (temp = h->buckets[index]; temp; temp = temp->next)
637 {
638 if (temp->key == key)
639 break;
640 beftemp = temp;
641 }
642 if (temp)
643 {
644 if (beftemp)
645 beftemp->next = temp->next;
646 else
647 h->buckets[index] = temp->next;
648 h->num_elements--;
649 if (temp->data && deleteFunc) {
650 (*deleteFunc)(temp->data, pData);
651 }
652
653 crFree(temp);
654 }
655
656 crHashIdPoolFreeBlock(h->idPool, key, 1);
657#ifdef CHROMIUM_THREADSAFE
658 crUnlockMutex(&h->mutex);
659#endif
660}
661
662
663void crHashtableDeleteBlock( CRHashTable *h, unsigned long key, GLsizei range, CRHashtableCallback deleteFunc )
664{
665 /* XXX optimize someday */
666 GLuint i;
667 for (i = 0; i < (GLuint)range; i++) {
668 crHashtableDelete( h, key, deleteFunc );
669 }
670}
671
672void *crHashtableSearch( const CRHashTable *h, unsigned long key )
673{
674 unsigned int index = crHash( key );
675 CRHashNode *temp;
676#ifdef CHROMIUM_THREADSAFE
677 crLockMutex((CRmutex *)&h->mutex);
678#endif
679 for ( temp = h->buckets[index]; temp; temp = temp->next )
680 {
681 if ( temp->key == key )
682 break;
683 }
684#ifdef CHROMIUM_THREADSAFE
685 crUnlockMutex((CRmutex *)&h->mutex);
686#endif
687 if ( !temp )
688 {
689 return NULL;
690 }
691 return temp->data;
692}
693
694void crHashtableReplace( CRHashTable *h, unsigned long key, void *data,
695 CRHashtableCallback deleteFunc)
696{
697 unsigned int index = crHash( key );
698 CRHashNode *temp;
699#ifdef CHROMIUM_THREADSAFE
700 crLockMutex(&h->mutex);
701#endif
702 for ( temp = h->buckets[index]; temp; temp = temp->next )
703 {
704 if ( temp->key == key )
705 break;
706 }
707#ifdef CHROMIUM_THREADSAFE
708 crUnlockMutex(&h->mutex);
709#endif
710 if ( !temp )
711 {
712 crHashtableAdd( h, key, data );
713 return;
714 }
715#ifdef CHROMIUM_THREADSAFE
716 crLockMutex(&h->mutex);
717#endif
718 if ( temp->data && deleteFunc )
719 {
720 (*deleteFunc)( temp->data );
721 }
722 temp->data = data;
723#ifdef CHROMIUM_THREADSAFE
724 crUnlockMutex(&h->mutex);
725#endif
726}
727
728unsigned int crHashtableNumElements( const CRHashTable *h)
729{
730 if (h)
731 return h->num_elements;
732 else
733 return 0;
734}
735
736/*
737 * Determine if the given key is used. Return GL_TRUE if so.
738 */
739GLboolean crHashtableIsKeyUsed( const CRHashTable *h, GLuint id )
740{
741 return (GLboolean) !crHashIdPoolIsIdFree( h->idPool, id);
742}
743
744GLboolean crHashtableGetDataKey(CRHashTable *pHash, void *pData, unsigned long *pKey)
745{
746 int i;
747 CRHashNode *entry;
748 GLboolean rc = GL_FALSE;
749
750 if (!pHash)
751 return rc;
752
753#ifdef CHROMIUM_THREADSAFE
754 crLockMutex(&pHash->mutex);
755#endif
756 for (i = 0; i<CR_NUM_BUCKETS && !rc; i++)
757 {
758 entry = pHash->buckets[i];
759 while (entry)
760 {
761 if (entry->data == pData) {
762 if (pKey)
763 *pKey = entry->key;
764 rc = GL_TRUE;
765 break;
766 }
767 entry = entry->next;
768 }
769 }
770#ifdef CHROMIUM_THREADSAFE
771 crUnlockMutex(&pHash->mutex);
772#endif
773
774 return rc;
775}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette