Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

pb_bufmgr_mm.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. /**************************************************************************
  2. *
  3. * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
  4. * Copyright 1999 Wittawat Yamwong
  5. * All Rights Reserved.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the
  9. * "Software"), to deal in the Software without restriction, including
  10. * without limitation the rights to use, copy, modify, merge, publish,
  11. * distribute, sub license, and/or sell copies of the Software, and to
  12. * permit persons to whom the Software is furnished to do so, subject to
  13. * the following conditions:
  14. *
  15. * The above copyright notice and this permission notice (including the
  16. * next paragraph) shall be included in all copies or substantial portions
  17. * of the Software.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  20. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  22. * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
  23. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  24. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  25. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  26. *
  27. **************************************************************************/
  28. /**
  29. * \file
  30. * Buffer manager using the old texture memory manager.
  31. *
  32. * \author José Fonseca <jrfonseca@tungstengraphics.com>
  33. */
  34. #include "linked_list.h"
  35. #include "p_defines.h"
  36. #include "p_debug.h"
  37. #include "p_thread.h"
  38. #include "p_util.h"
  39. #include "pb_buffer.h"
  40. #include "pb_bufmgr.h"
  41. /**
  42. * Convenience macro (type safe).
  43. */
  44. #define SUPER(__derived) (&(__derived)->base)
  45. struct mem_block
  46. {
  47. struct mem_block *next, *prev;
  48. struct mem_block *next_free, *prev_free;
  49. struct mem_block *heap;
  50. int ofs, size;
  51. unsigned int free:1;
  52. unsigned int reserved:1;
  53. };
  54. #ifdef DEBUG
  55. /**
  56. * For debugging purposes.
  57. */
  58. static void
  59. mmDumpMemInfo(const struct mem_block *heap)
  60. {
  61. debug_printf("Memory heap %p:\n", (void *)heap);
  62. if (heap == 0) {
  63. debug_printf(" heap == 0\n");
  64. } else {
  65. const struct mem_block *p;
  66. for(p = heap->next; p != heap; p = p->next) {
  67. debug_printf(" Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
  68. p->free ? 'F':'.',
  69. p->reserved ? 'R':'.');
  70. }
  71. debug_printf("\nFree list:\n");
  72. for(p = heap->next_free; p != heap; p = p->next_free) {
  73. debug_printf(" FREE Offset:%08x, Size:%08x, %c%c\n",p->ofs,p->size,
  74. p->free ? 'F':'.',
  75. p->reserved ? 'R':'.');
  76. }
  77. }
  78. debug_printf("End of memory blocks\n");
  79. }
  80. #endif
  81. /**
  82. * input: total size in bytes
  83. * return: a heap pointer if OK, NULL if error
  84. */
  85. static struct mem_block *
  86. mmInit(int ofs, int size)
  87. {
  88. struct mem_block *heap, *block;
  89. if (size <= 0)
  90. return NULL;
  91. heap = CALLOC_STRUCT(mem_block);
  92. if (!heap)
  93. return NULL;
  94. block = CALLOC_STRUCT(mem_block);
  95. if (!block) {
  96. FREE(heap);
  97. return NULL;
  98. }
  99. heap->next = block;
  100. heap->prev = block;
  101. heap->next_free = block;
  102. heap->prev_free = block;
  103. block->heap = heap;
  104. block->next = heap;
  105. block->prev = heap;
  106. block->next_free = heap;
  107. block->prev_free = heap;
  108. block->ofs = ofs;
  109. block->size = size;
  110. block->free = 1;
  111. return heap;
  112. }
  113. static struct mem_block *
  114. SliceBlock(struct mem_block *p,
  115. int startofs, int size,
  116. int reserved, int alignment)
  117. {
  118. struct mem_block *newblock;
  119. /* break left [p, newblock, p->next], then p = newblock */
  120. if (startofs > p->ofs) {
  121. newblock = CALLOC_STRUCT(mem_block);
  122. if (!newblock)
  123. return NULL;
  124. newblock->ofs = startofs;
  125. newblock->size = p->size - (startofs - p->ofs);
  126. newblock->free = 1;
  127. newblock->heap = p->heap;
  128. newblock->next = p->next;
  129. newblock->prev = p;
  130. p->next->prev = newblock;
  131. p->next = newblock;
  132. newblock->next_free = p->next_free;
  133. newblock->prev_free = p;
  134. p->next_free->prev_free = newblock;
  135. p->next_free = newblock;
  136. p->size -= newblock->size;
  137. p = newblock;
  138. }
  139. /* break right, also [p, newblock, p->next] */
  140. if (size < p->size) {
  141. newblock = CALLOC_STRUCT(mem_block);
  142. if (!newblock)
  143. return NULL;
  144. newblock->ofs = startofs + size;
  145. newblock->size = p->size - size;
  146. newblock->free = 1;
  147. newblock->heap = p->heap;
  148. newblock->next = p->next;
  149. newblock->prev = p;
  150. p->next->prev = newblock;
  151. p->next = newblock;
  152. newblock->next_free = p->next_free;
  153. newblock->prev_free = p;
  154. p->next_free->prev_free = newblock;
  155. p->next_free = newblock;
  156. p->size = size;
  157. }
  158. /* p = middle block */
  159. p->free = 0;
  160. /* Remove p from the free list:
  161. */
  162. p->next_free->prev_free = p->prev_free;
  163. p->prev_free->next_free = p->next_free;
  164. p->next_free = 0;
  165. p->prev_free = 0;
  166. p->reserved = reserved;
  167. return p;
  168. }
  169. /**
  170. * Allocate 'size' bytes with 2^align2 bytes alignment,
  171. * restrict the search to free memory after 'startSearch'
  172. * depth and back buffers should be in different 4mb banks
  173. * to get better page hits if possible
  174. * input: size = size of block
  175. * align2 = 2^align2 bytes alignment
  176. * startSearch = linear offset from start of heap to begin search
  177. * return: pointer to the allocated block, 0 if error
  178. */
  179. static struct mem_block *
  180. mmAllocMem(struct mem_block *heap, int size, int align2, int startSearch)
  181. {
  182. struct mem_block *p;
  183. const int mask = (1 << align2)-1;
  184. int startofs = 0;
  185. int endofs;
  186. if (!heap || align2 < 0 || size <= 0)
  187. return NULL;
  188. for (p = heap->next_free; p != heap; p = p->next_free) {
  189. assert(p->free);
  190. startofs = (p->ofs + mask) & ~mask;
  191. if ( startofs < startSearch ) {
  192. startofs = startSearch;
  193. }
  194. endofs = startofs+size;
  195. if (endofs <= (p->ofs+p->size))
  196. break;
  197. }
  198. if (p == heap)
  199. return NULL;
  200. assert(p->free);
  201. p = SliceBlock(p,startofs,size,0,mask+1);
  202. return p;
  203. }
  204. #if 0
  205. /**
  206. * Free block starts at offset
  207. * input: pointer to a heap, start offset
  208. * return: pointer to a block
  209. */
  210. static struct mem_block *
  211. mmFindBlock(struct mem_block *heap, int start)
  212. {
  213. struct mem_block *p;
  214. for (p = heap->next; p != heap; p = p->next) {
  215. if (p->ofs == start)
  216. return p;
  217. }
  218. return NULL;
  219. }
  220. #endif
  221. static INLINE int
  222. Join2Blocks(struct mem_block *p)
  223. {
  224. /* XXX there should be some assertions here */
  225. /* NOTE: heap->free == 0 */
  226. if (p->free && p->next->free) {
  227. struct mem_block *q = p->next;
  228. assert(p->ofs + p->size == q->ofs);
  229. p->size += q->size;
  230. p->next = q->next;
  231. q->next->prev = p;
  232. q->next_free->prev_free = q->prev_free;
  233. q->prev_free->next_free = q->next_free;
  234. FREE(q);
  235. return 1;
  236. }
  237. return 0;
  238. }
  239. /**
  240. * Free block starts at offset
  241. * input: pointer to a block
  242. * return: 0 if OK, -1 if error
  243. */
  244. static int
  245. mmFreeMem(struct mem_block *b)
  246. {
  247. if (!b)
  248. return 0;
  249. if (b->free) {
  250. debug_printf("block already free\n");
  251. return -1;
  252. }
  253. if (b->reserved) {
  254. debug_printf("block is reserved\n");
  255. return -1;
  256. }
  257. b->free = 1;
  258. b->next_free = b->heap->next_free;
  259. b->prev_free = b->heap;
  260. b->next_free->prev_free = b;
  261. b->prev_free->next_free = b;
  262. Join2Blocks(b);
  263. if (b->prev != b->heap)
  264. Join2Blocks(b->prev);
  265. return 0;
  266. }
  267. /**
  268. * destroy MM
  269. */
  270. static void
  271. mmDestroy(struct mem_block *heap)
  272. {
  273. struct mem_block *p;
  274. if (!heap)
  275. return;
  276. for (p = heap->next; p != heap; ) {
  277. struct mem_block *next = p->next;
  278. FREE(p);
  279. p = next;
  280. }
  281. FREE(heap);
  282. }
  283. struct mm_pb_manager
  284. {
  285. struct pb_manager base;
  286. _glthread_Mutex mutex;
  287. size_t size;
  288. struct mem_block *heap;
  289. size_t align2;
  290. struct pb_buffer *buffer;
  291. void *map;
  292. };
  293. static INLINE struct mm_pb_manager *
  294. mm_pb_manager(struct pb_manager *mgr)
  295. {
  296. assert(mgr);
  297. return (struct mm_pb_manager *)mgr;
  298. }
  299. struct mm_buffer
  300. {
  301. struct pb_buffer base;
  302. struct mm_pb_manager *mgr;
  303. struct mem_block *block;
  304. };
  305. static INLINE struct mm_buffer *
  306. mm_buffer(struct pb_buffer *buf)
  307. {
  308. assert(buf);
  309. return (struct mm_buffer *)buf;
  310. }
  311. static void
  312. mm_buffer_destroy(struct pb_buffer *buf)
  313. {
  314. struct mm_buffer *mm_buf = mm_buffer(buf);
  315. struct mm_pb_manager *mm = mm_buf->mgr;
  316. assert(buf->base.refcount == 0);
  317. _glthread_LOCK_MUTEX(mm->mutex);
  318. mmFreeMem(mm_buf->block);
  319. FREE(buf);
  320. _glthread_UNLOCK_MUTEX(mm->mutex);
  321. }
  322. static void *
  323. mm_buffer_map(struct pb_buffer *buf,
  324. unsigned flags)
  325. {
  326. struct mm_buffer *mm_buf = mm_buffer(buf);
  327. struct mm_pb_manager *mm = mm_buf->mgr;
  328. return (unsigned char *) mm->map + mm_buf->block->ofs;
  329. }
  330. static void
  331. mm_buffer_unmap(struct pb_buffer *buf)
  332. {
  333. /* No-op */
  334. }
  335. static void
  336. mm_buffer_get_base_buffer(struct pb_buffer *buf,
  337. struct pb_buffer **base_buf,
  338. unsigned *offset)
  339. {
  340. struct mm_buffer *mm_buf = mm_buffer(buf);
  341. struct mm_pb_manager *mm = mm_buf->mgr;
  342. pb_get_base_buffer(mm->buffer, base_buf, offset);
  343. *offset += mm_buf->block->ofs;
  344. }
  345. static const struct pb_vtbl
  346. mm_buffer_vtbl = {
  347. mm_buffer_destroy,
  348. mm_buffer_map,
  349. mm_buffer_unmap,
  350. mm_buffer_get_base_buffer
  351. };
  352. static struct pb_buffer *
  353. mm_bufmgr_create_buffer(struct pb_manager *mgr,
  354. size_t size,
  355. const struct pb_desc *desc)
  356. {
  357. struct mm_pb_manager *mm = mm_pb_manager(mgr);
  358. struct mm_buffer *mm_buf;
  359. /* We don't handle alignments larger then the one initially setup */
  360. assert(desc->alignment % (1 << mm->align2) == 0);
  361. if(desc->alignment % (1 << mm->align2))
  362. return NULL;
  363. _glthread_LOCK_MUTEX(mm->mutex);
  364. mm_buf = CALLOC_STRUCT(mm_buffer);
  365. if (!mm_buf) {
  366. _glthread_UNLOCK_MUTEX(mm->mutex);
  367. return NULL;
  368. }
  369. mm_buf->base.base.refcount = 1;
  370. mm_buf->base.base.alignment = desc->alignment;
  371. mm_buf->base.base.usage = desc->usage;
  372. mm_buf->base.base.size = size;
  373. mm_buf->base.vtbl = &mm_buffer_vtbl;
  374. mm_buf->mgr = mm;
  375. mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
  376. if(!mm_buf->block) {
  377. debug_printf("warning: heap full\n");
  378. #if 0
  379. mmDumpMemInfo(mm->heap);
  380. #endif
  381. mm_buf->block = mmAllocMem(mm->heap, size, mm->align2, 0);
  382. if(!mm_buf->block) {
  383. assert(0);
  384. FREE(mm_buf);
  385. _glthread_UNLOCK_MUTEX(mm->mutex);
  386. return NULL;
  387. }
  388. }
  389. /* Some sanity checks */
  390. assert(0 <= mm_buf->block->ofs && mm_buf->block->ofs < mm->size);
  391. assert(size <= mm_buf->block->size && mm_buf->block->ofs + mm_buf->block->size <= mm->size);
  392. _glthread_UNLOCK_MUTEX(mm->mutex);
  393. return SUPER(mm_buf);
  394. }
  395. static void
  396. mm_bufmgr_destroy(struct pb_manager *mgr)
  397. {
  398. struct mm_pb_manager *mm = mm_pb_manager(mgr);
  399. _glthread_LOCK_MUTEX(mm->mutex);
  400. mmDestroy(mm->heap);
  401. pb_unmap(mm->buffer);
  402. pb_reference(&mm->buffer, NULL);
  403. _glthread_UNLOCK_MUTEX(mm->mutex);
  404. FREE(mgr);
  405. }
  406. struct pb_manager *
  407. mm_bufmgr_create_from_buffer(struct pb_buffer *buffer,
  408. size_t size, size_t align2)
  409. {
  410. struct mm_pb_manager *mm;
  411. if(!buffer)
  412. return NULL;
  413. mm = CALLOC_STRUCT(mm_pb_manager);
  414. if (!mm)
  415. return NULL;
  416. mm->base.create_buffer = mm_bufmgr_create_buffer;
  417. mm->base.destroy = mm_bufmgr_destroy;
  418. mm->size = size;
  419. mm->align2 = align2; /* 64-byte alignment */
  420. _glthread_INIT_MUTEX(mm->mutex);
  421. mm->buffer = buffer;
  422. mm->map = pb_map(mm->buffer,
  423. PIPE_BUFFER_USAGE_CPU_READ |
  424. PIPE_BUFFER_USAGE_CPU_WRITE);
  425. if(!mm->map)
  426. goto failure;
  427. mm->heap = mmInit(0, size);
  428. if (!mm->heap)
  429. goto failure;
  430. return SUPER(mm);
  431. failure:
  432. if(mm->heap)
  433. mmDestroy(mm->heap);
  434. if(mm->map)
  435. pb_unmap(mm->buffer);
  436. if(mm)
  437. FREE(mm);
  438. return NULL;
  439. }
  440. struct pb_manager *
  441. mm_bufmgr_create(struct pb_manager *provider,
  442. size_t size, size_t align2)
  443. {
  444. struct pb_buffer *buffer;
  445. struct pb_manager *mgr;
  446. struct pb_desc desc;
  447. assert(provider);
  448. assert(provider->create_buffer);
  449. memset(&desc, 0, sizeof(desc));
  450. desc.alignment = 1 << align2;
  451. buffer = provider->create_buffer(provider, size, &desc);
  452. if (!buffer)
  453. return NULL;
  454. mgr = mm_bufmgr_create_from_buffer(buffer, size, align2);
  455. if (!mgr) {
  456. pb_reference(&buffer, NULL);
  457. return NULL;
  458. }
  459. return mgr;
  460. }