Leaked source code of windows server 2003
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.

1010 lines
27 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: dl_list.c
  3. *
  4. * Display list management rountines.
  5. *
  6. * Copyright (c) 1995-96 Microsoft Corporation
  7. \**************************************************************************/
  8. /*
  9. ** Copyright 1991-1993, Silicon Graphics, Inc.
  10. ** All Rights Reserved.
  11. **
  12. ** This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  13. ** the contents of this file may not be disclosed to third parties, copied or
  14. ** duplicated in any form, in whole or in part, without the prior written
  15. ** permission of Silicon Graphics, Inc.
  16. **
  17. ** RESTRICTED RIGHTS LEGEND:
  18. ** Use, duplication or disclosure by the Government is subject to restrictions
  19. ** as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  20. ** and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  21. ** successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  22. ** rights reserved under the Copyright Laws of the United States.
  23. **
  24. ** Basic display list routines.
  25. **
  26. */
  27. #include "precomp.h"
  28. #pragma hdrstop
  29. extern GLCLTPROCTABLE ListCompCltProcTable;
  30. extern GLEXTPROCTABLE ListCompExtProcTable;
  31. __GLdlist *__glShrinkDlist(__GLcontext *gc, __GLdlist *dlist);
  32. // #define DL_HEAP_VERBOSE
  33. #ifdef DL_HEAP_VERBOSE
  34. int cbDlistTotal = 0;
  35. extern ULONG glSize;
  36. #ifdef DBG
  37. #define GL_MSIZE(pv) _msize((BYTE *)(pv)-16)
  38. #else
  39. #define GL_MSIZE(pv) _msize(pv)
  40. #endif
  41. #endif
  42. #if defined(DL_BLOCK_VERBOSE) || defined(DL_HEAP_VERBOSE)
  43. #include "malloc.h"
  44. #endif
  45. /*
  46. ** Arbitrary limit for looking up multiple display lists at once
  47. ** (with glCallLists()). Any number from 128 to 1024 should work well.
  48. ** This value doesn't change the functionality of OpenGL at all, but
  49. ** will make minor variations to the performance characteristics.
  50. */
  51. #define MAX_LISTS_CACHE 256
  52. const GLubyte __GLdlsize_tab[] = {
  53. /* GL_BYTE */ 1,
  54. /* GL_UNSIGNED_BYTE */ 1,
  55. /* GL_SHORT */ 2,
  56. /* GL_UNSIGNED_SHORT */ 2,
  57. /* GL_INT */ 4,
  58. /* GL_UNSIGNED_INT */ 4,
  59. /* GL_FLOAT */ 4,
  60. /* GL_2_BYTES */ 2,
  61. /* GL_3_BYTES */ 3,
  62. /* GL_4_BYTES */ 4,
  63. };
  64. #define __glCallListsSize(type) \
  65. ((type) >= GL_BYTE && (type) <= GL_4_BYTES ? \
  66. __GLdlsize_tab[(type)-GL_BYTE] : -1)
  67. #define DL_LINK_SIZE (sizeof(__GLlistExecFunc *)+sizeof(GLubyte *))
  68. #define DL_TERMINATOR_SIZE sizeof(GLubyte *)
  69. #define DL_OVERHEAD (offsetof(__GLdlist, head)+DL_LINK_SIZE+\
  70. DL_TERMINATOR_SIZE)
  71. // This value should be a power of two
  72. #define DL_BLOCK_SIZE (256 * 1024)
  73. // This value is chosen specifically to give the initial total size
  74. // of the dlist an even block size
  75. #define DL_INITIAL_SIZE (DL_BLOCK_SIZE-DL_OVERHEAD)
  76. // Skip to the next block in the display list block chain
  77. const GLubyte * FASTCALL __glle_NextBlock(__GLcontext *gc, const GLubyte *PC)
  78. {
  79. #ifdef DL_BLOCK_VERBOSE
  80. DbgPrint("NextBlock: %08lX\n", *(const GLubyte * UNALIGNED64 *)PC);
  81. #endif
  82. return *(const GLubyte * UNALIGNED64 *)PC;
  83. }
  84. /*
  85. ** Used to pad display list entries to double word boundaries where needed
  86. ** (for those few OpenGL commands which take double precision values).
  87. */
  88. const GLubyte * FASTCALL __glle_Nop(__GLcontext *gc, const GLubyte *PC)
  89. {
  90. return PC;
  91. }
  92. void APIENTRY
  93. glcltNewList ( IN GLuint list, IN GLenum mode )
  94. {
  95. __GLdlistMachine *dlstate;
  96. __GL_SETUP();
  97. // Must use the client side begin state
  98. if (gc->paTeb->flags & POLYARRAY_IN_BEGIN)
  99. {
  100. GLSETERROR(GL_INVALID_OPERATION);
  101. return;
  102. }
  103. dlstate = &gc->dlist;
  104. /* Valid mode? */
  105. switch(mode) {
  106. case GL_COMPILE:
  107. case GL_COMPILE_AND_EXECUTE:
  108. break;
  109. default:
  110. GLSETERROR(GL_INVALID_ENUM);
  111. return;
  112. }
  113. if (dlstate->currentList) {
  114. /* Must call EndList before calling NewList again! */
  115. GLSETERROR(GL_INVALID_OPERATION);
  116. return;
  117. }
  118. if (list == 0) {
  119. GLSETERROR(GL_INVALID_VALUE);
  120. return;
  121. }
  122. // If we are in COMPILE mode, we need to clear the command buffer,
  123. // the poly array buffer, and the poly material buffer so that we
  124. // can use them to compile poly array. Otherwise, previously batched
  125. // commands may be lost.
  126. if (mode == GL_COMPILE)
  127. glsbAttention();
  128. ASSERTOPENGL((DL_BLOCK_SIZE & (DL_BLOCK_SIZE-1)) == 0,
  129. "DL_BLOCK_SIZE is not a power of two\n");
  130. ASSERTOPENGL(dlstate->listData == NULL,
  131. "listData non-NULL in NewList\n");
  132. dlstate->listData = __glAllocDlist(gc, DL_INITIAL_SIZE);
  133. if (dlstate->listData == NULL)
  134. {
  135. GLSETERROR(GL_OUT_OF_MEMORY);
  136. return;
  137. }
  138. /*
  139. ** Save current client dispatch pointers into saved state in context. Then
  140. ** switch to the list tables.
  141. */
  142. gc->savedCltProcTable.cEntries = ListCompCltProcTable.cEntries;
  143. gc->savedExtProcTable.cEntries = ListCompExtProcTable.cEntries;
  144. GetCltProcTable(&gc->savedCltProcTable, &gc->savedExtProcTable, FALSE);
  145. SetCltProcTable(&ListCompCltProcTable, &ListCompExtProcTable, FALSE);
  146. dlstate->currentList = list;
  147. dlstate->mode = mode;
  148. dlstate->nesting = 0;
  149. #if 0
  150. dlstate->drawBuffer = GL_FALSE;
  151. #endif
  152. dlstate->beginRec = NULL;
  153. (*dlstate->initState)(gc);
  154. }
  155. void APIENTRY
  156. glcltEndList ( void )
  157. {
  158. __GLdlistMachine *dlstate;
  159. __GLdlist *dlist;
  160. __GLdlist *newDlist;
  161. __GLdlist *prevDlist;
  162. GLubyte *allEnd;
  163. GLubyte *data;
  164. GLuint totalSize;
  165. GLuint currentList;
  166. POLYARRAY *pa;
  167. __GL_SETUP();
  168. pa = gc->paTeb;
  169. dlstate = &gc->dlist;
  170. /* Must call NewList() first! */
  171. if (dlstate->currentList == 0) {
  172. GLSETERROR(GL_INVALID_OPERATION);
  173. return;
  174. }
  175. // In COMPILE_AND_EXECUTE mode, EndList must not be called in Begin.
  176. // In COMPILE mode, however, this flag should be clear (enforced in NewList)
  177. // unless it was set in the poly array compilation code.
  178. if (dlstate->mode == GL_COMPILE_AND_EXECUTE &&
  179. pa->flags & POLYARRAY_IN_BEGIN)
  180. {
  181. GLSETERROR(GL_INVALID_OPERATION);
  182. return;
  183. }
  184. // If we are in the middle of compiling poly array, end the poly array
  185. // compilation.
  186. if (gc->dlist.beginRec)
  187. {
  188. ASSERTOPENGL(pa->flags & POLYARRAY_IN_BEGIN, "not in begin!\n");
  189. gc->dlist.beginRec->flags |= DLIST_BEGIN_NO_MATCHING_END;
  190. // Record the last POLYDATA since it may contain attribute changes.
  191. __glDlistCompilePolyData(gc, GL_TRUE);
  192. // Terminate poly array compilation
  193. gc->dlist.beginRec = NULL;
  194. }
  195. // If we are in COMPILE mode, we need to reset the command buffer,
  196. // the poly array buffer, and the poly material buffer.
  197. if (gc->dlist.mode == GL_COMPILE)
  198. {
  199. glsbResetBuffers(gc->dlist.beginRec ? TRUE : FALSE);
  200. // Clear begin flag too
  201. pa->flags &= ~POLYARRAY_IN_BEGIN;
  202. }
  203. dlist = dlstate->listData;
  204. #if 0
  205. // Copy over the DrawBuffer flag
  206. dlist->drawBuffer = dlstate->drawBuffer;
  207. #endif
  208. // Shrink this block to remove wasted space
  209. dlist = __glShrinkDlist(gc, dlist);
  210. // Remember the true end of the list
  211. allEnd = dlist->head+dlist->used;
  212. // Reverse the order of the list
  213. prevDlist = NULL;
  214. while (dlist->nextBlock != NULL)
  215. {
  216. newDlist = dlist->nextBlock;
  217. dlist->nextBlock = prevDlist;
  218. prevDlist = dlist;
  219. dlist = newDlist;
  220. }
  221. dlist->nextBlock = prevDlist;
  222. // Set the end pointer correctly
  223. dlist->end = allEnd;
  224. // Mark the end of the display list data with 0:
  225. *((DWORD *)dlist->end) = 0;
  226. dlstate->listData = NULL;
  227. currentList = dlstate->currentList;
  228. dlstate->currentList = 0;
  229. #ifdef DL_HEAP_VERBOSE
  230. DbgPrint("Dlists using %8d, total %8d\n",
  231. cbDlistTotal, glSize);
  232. #endif
  233. #ifdef DL_BLOCK_VERBOSE
  234. DbgPrint("List %d: start %08lX, end %08lX\n", currentList,
  235. dlist->head, dlist->end);
  236. DbgPrint("Blocks at:");
  237. newDlist = dlist;
  238. while (newDlist != NULL)
  239. {
  240. DbgPrint(" %08lX:%d", newDlist, GL_MSIZE(newDlist));
  241. newDlist = newDlist->nextBlock;
  242. }
  243. DbgPrint("\n");
  244. #endif
  245. // __glNamesNewData sets dlist refcount to 1.
  246. if (!__glNamesNewData(gc, gc->dlist.namesArray, currentList, dlist))
  247. {
  248. /*
  249. ** No memory!
  250. ** Nuke the list!
  251. */
  252. __glFreeDlist(gc, dlist);
  253. }
  254. /* Switch back to saved dispatch state */
  255. SetCltProcTable(&gc->savedCltProcTable, &gc->savedExtProcTable, FALSE);
  256. }
  257. #ifdef NT_SERVER_SHARE_LISTS
  258. /******************************Public*Routine******************************\
  259. *
  260. * DlLockLists
  261. *
  262. * Remember the locked lists for possible later cleanup
  263. *
  264. * History:
  265. * Mon Dec 12 18:58:32 1994 -by- Drew Bliss [drewb]
  266. * Created
  267. *
  268. \**************************************************************************/
  269. // Number of locks to allocate when the lock list needs to grow
  270. // Must be a power of two
  271. #define DL_LOCK_LIST_BLOCK 32
  272. GLboolean DlLockLists(__GLcontext *gc, GLsizei n, __GLdlist **dlists)
  273. {
  274. DlLockArray *pdla;
  275. DlLockEntry *pdle;
  276. GLsizei nNewSize;
  277. pdla = &gc->dla;
  278. // Extend current lock array if needed
  279. if (pdla->nAllocated-pdla->nFilled < n)
  280. {
  281. // Round the needed size up to the block size
  282. nNewSize = (pdla->nAllocated+n+DL_LOCK_LIST_BLOCK-1) &
  283. ~(DL_LOCK_LIST_BLOCK-1);
  284. pdle = GCREALLOC(gc, pdla->pdleEntries, sizeof(DlLockEntry)*nNewSize);
  285. if (pdle == NULL)
  286. {
  287. return 0;
  288. }
  289. pdla->nAllocated = nNewSize;
  290. pdla->pdleEntries = pdle;
  291. }
  292. // We must have enough space now
  293. ASSERTOPENGL(pdla->nAllocated-pdla->nFilled >= n, "no enough space!\n");
  294. // Lock down dlists and remember them
  295. pdle = pdla->pdleEntries+pdla->nFilled;
  296. pdla->nFilled += n;
  297. while (n-- > 0)
  298. {
  299. pdle->dlist = *dlists;
  300. DBGLEVEL3(LEVEL_INFO, "Locked %p for %p, ref %d\n", *dlists, gc,
  301. (*dlists)->refcount);
  302. dlists++;
  303. pdle++;
  304. }
  305. return (GLboolean) (pdla->nFilled != 0); // return high water mark
  306. }
  307. /******************************Public*Routine******************************\
  308. *
  309. * DlUnlockLists
  310. *
  311. * Remove list lock entries.
  312. *
  313. * History:
  314. * Mon Dec 12 18:58:54 1994 -by- Drew Bliss [drewb]
  315. * Created
  316. *
  317. \**************************************************************************/
  318. void DlUnlockLists(__GLcontext *gc, GLsizei n)
  319. {
  320. DlLockArray *pdla;
  321. DlLockEntry *pdle;
  322. GLsizei i;
  323. __GLdlist *dlist;
  324. // Since DlLockLists and DlUnlockLists are called in a recursive manner,
  325. // we can simply decrement the filled count.
  326. pdla = &gc->dla;
  327. pdla->nFilled -= n;
  328. // Lock list doesn't shrink. This would be fairly easy since realloc
  329. // is guaranteed not to fail when the memory block shrinks
  330. // Is this important?
  331. }
  332. /******************************Public*Routine******************************\
  333. *
  334. * DlReleaseLocks
  335. *
  336. * Releases any locks in the lock list and frees the lock list
  337. *
  338. * Must be executed under the dlist semaphore
  339. *
  340. * History:
  341. * Tue Dec 13 11:45:26 1994 -by- Drew Bliss [drewb]
  342. * Created
  343. *
  344. \**************************************************************************/
  345. void DlReleaseLocks(__GLcontext *gc)
  346. {
  347. DlLockArray *pdla;
  348. DlLockEntry *pdle;
  349. __GL_NAMES_ASSERT_LOCKED(gc->dlist.namesArray);
  350. pdla = &gc->dla;
  351. DBGLEVEL3(LEVEL_INFO, "Cleaning up %p, locks %d (%d)\n", gc,
  352. pdla->nFilled, pdla->nAllocated);
  353. // Sanity check the counts
  354. ASSERTOPENGL(pdla->nFilled <= pdla->nAllocated, "bad nFilled!\n");
  355. pdle = pdla->pdleEntries;
  356. while (pdla->nFilled)
  357. {
  358. pdla->nFilled--;
  359. // This function is called to clean up display list locks held by
  360. // glCallList or glCallLists when it dies. We need to release the
  361. // locks here and free the dlists if their refcounts reach 0.
  362. // The refcounts will reach 0 here only when the dlists were deleted
  363. // by another thread while this thread was also holding the locks.
  364. __glDisposeDlist(gc, pdle->dlist);
  365. pdle++;
  366. }
  367. pdla->nAllocated = 0;
  368. if (pdla->pdleEntries)
  369. {
  370. GCFREE(gc, pdla->pdleEntries);
  371. }
  372. }
  373. #endif // NT_SERVER_SIDE
  374. // If the a dlist was deleted by another thread while we have it locked,
  375. // we need to free the dlist here.
  376. void FASTCALL DlCleanup(__GLcontext *gc, void *pData)
  377. {
  378. __glFreeDlist(gc, (__GLdlist *)pData);
  379. }
  380. void FASTCALL DoCallList(GLuint list)
  381. {
  382. __GLdlist *dlist;
  383. __GLdlistMachine *dlstate;
  384. const GLubyte *end, *PC;
  385. __GLlistExecFunc *fp;
  386. __GL_SETUP();
  387. dlstate = &gc->dlist;
  388. if (dlstate->nesting >= __GL_MAX_LIST_NESTING) {
  389. /* Force unwinding of the display list */
  390. dlstate->nesting = __GL_MAX_LIST_NESTING*2;
  391. return;
  392. }
  393. /* Increment dlist refcount */
  394. dlist = __glNamesLockData(gc, gc->dlist.namesArray, list);
  395. /* No list, no action! */
  396. if (!dlist) {
  397. return;
  398. }
  399. #ifdef NT_SERVER_SHARE_LISTS
  400. if (!DlLockLists(gc, 1, &dlist))
  401. {
  402. /* Decrement dlist refcount */
  403. __glNamesUnlockData(gc, (void *)dlist, DlCleanup);
  404. GLSETERROR(GL_OUT_OF_MEMORY);
  405. return;
  406. }
  407. #endif
  408. dlstate->nesting++;
  409. end = dlist->end;
  410. PC = dlist->head;
  411. while (PC != end)
  412. {
  413. // Get the current function pointer.
  414. fp = *((__GLlistExecFunc * const UNALIGNED64 *) PC);
  415. // Execute the current function. Return value is pointer to
  416. // next function/parameter block in the display list.
  417. PC = (*fp)(gc, PC+sizeof(__GLlistExecFunc * const *));
  418. }
  419. dlstate->nesting--;
  420. /* Decrement dlist refcount */
  421. // Will perform cleanup if necessary
  422. __glNamesUnlockData(gc, (void *)dlist, DlCleanup);
  423. #ifdef NT_SERVER_SHARE_LISTS
  424. DlUnlockLists(gc, 1);
  425. #endif
  426. }
  427. /*
  428. ** Display list compilation and execution versions of CallList and CallLists
  429. ** are maintained here for the sake of sanity. Note that __glle_CallList
  430. ** may not call glcltCallList or it will break the infinite recursive
  431. ** display list prevention code.
  432. */
  433. void APIENTRY
  434. __gllc_CallList ( IN GLuint list )
  435. {
  436. struct __gllc_CallList_Rec *data;
  437. __GL_SETUP();
  438. if (list == 0) {
  439. __gllc_InvalidValue();
  440. return;
  441. }
  442. // It is extremely difficult to make CallList(s) work with poly array
  443. // compilation. For example, in the call sequence in COMPILE_AND_EXECUTE
  444. // mode [Begin, TexCoord, CallList, Vertex, ...], it is difficult to record
  445. // the partial POLYDATA in both COMPILE and COMPILE_AND_EXECUTE modes.
  446. // That is, we may end up recording and playing back TexCoord twice in the
  447. // above example. As a result, we may have to stop building poly array in
  448. // some cases. Fortunately, this situation is rare.
  449. if (gc->dlist.beginRec)
  450. {
  451. gc->dlist.beginRec->flags |= DLIST_BEGIN_HAS_CALLLIST;
  452. // Record the last POLYDATA since it may contain attribute changes.
  453. __glDlistCompilePolyData(gc, GL_TRUE);
  454. }
  455. data = (struct __gllc_CallList_Rec *)
  456. __glDlistAddOpUnaligned(gc,
  457. DLIST_SIZE(sizeof(struct __gllc_CallList_Rec)),
  458. DLIST_GENERIC_OP(CallList));
  459. if (data == NULL) return;
  460. data->list = list;
  461. __glDlistAppendOp(gc, data, __glle_CallList);
  462. if (gc->dlist.beginRec)
  463. {
  464. POLYARRAY *pa;
  465. pa = gc->paTeb;
  466. // In COMPILE_AND_EXECUTE mode, we can actually get out of the Begin mode.
  467. // Although it is an application error, we need to terminate poly array
  468. // compilation!
  469. if (!(pa->flags & POLYARRAY_IN_BEGIN))
  470. gc->dlist.beginRec = NULL;
  471. else
  472. {
  473. // If there is a partial vertex record after CallList(s), we will terminate
  474. // the poly array compilation. Otherwise, it is safe to continue the
  475. // processing.
  476. if (pa->pdNextVertex->flags)
  477. {
  478. // Terminate poly array compilation
  479. gc->dlist.beginRec = NULL;
  480. if (gc->dlist.mode == GL_COMPILE)
  481. {
  482. glsbResetBuffers(TRUE);
  483. // Clear begin flag too
  484. pa->flags &= ~POLYARRAY_IN_BEGIN;
  485. }
  486. }
  487. }
  488. }
  489. }
  490. const GLubyte * FASTCALL __glle_CallList(__GLcontext *gc, const GLubyte *PC)
  491. {
  492. struct __gllc_CallList_Rec *data;
  493. data = (struct __gllc_CallList_Rec *) PC;
  494. DoCallList(data->list);
  495. return PC + sizeof(struct __gllc_CallList_Rec);
  496. }
  497. void APIENTRY
  498. glcltCallList ( IN GLuint list )
  499. {
  500. __GL_SETUP();
  501. if (list == 0) {
  502. GLSETERROR(GL_INVALID_VALUE);
  503. return;
  504. }
  505. gc->dlist.nesting = 0;
  506. DoCallList(list);
  507. }
  508. void FASTCALL DoCallLists(GLsizei n, GLenum type, const GLvoid *lists)
  509. {
  510. __GLdlist *dlists[MAX_LISTS_CACHE];
  511. __GLdlist *dlist;
  512. __GLdlistMachine *dlstate;
  513. GLint i, dlcount, datasize;
  514. const GLubyte *listiter;
  515. const GLubyte *end, *PC;
  516. __GLlistExecFunc *fp;
  517. __GL_SETUP();
  518. dlstate = &gc->dlist;
  519. datasize = __glCallListsSize(type);
  520. if (dlstate->nesting >= __GL_MAX_LIST_NESTING) {
  521. /* Force unwinding of the display list */
  522. dlstate->nesting = __GL_MAX_LIST_NESTING*2;
  523. return;
  524. }
  525. dlstate->nesting++;
  526. listiter = (const GLubyte *) lists;
  527. while (n) {
  528. dlcount = n;
  529. if (dlcount > MAX_LISTS_CACHE) dlcount = MAX_LISTS_CACHE;
  530. #ifdef NT_SERVER_SHARE_LISTS
  531. // Is there anything we can do here in the failure case besides
  532. // just skip the lists? This is more or less consistent
  533. // with the behavior for not-found lists
  534. /* Increment dlist refcount */
  535. __glNamesLockDataList(gc, gc->dlist.namesArray, dlcount, type,
  536. gc->state.list.listBase,
  537. (const GLvoid *) listiter, (void **)dlists);
  538. if (!DlLockLists(gc, dlcount, dlists))
  539. {
  540. /* Decrement dlist refcount */
  541. __glNamesUnlockDataList(gc, dlcount, (void **)dlists, DlCleanup);
  542. GLSETERROR(GL_OUT_OF_MEMORY);
  543. }
  544. else
  545. {
  546. #else
  547. __glNamesLockDataList(gc, gc->dlist.namesArray, dlcount, type,
  548. gc->state.list.listBase,
  549. (const GLvoid *) listiter, (void **)dlists);
  550. #endif
  551. i = 0;
  552. while (i < dlcount) {
  553. dlist = dlists[i];
  554. end = dlist->end;
  555. PC = dlist->head;
  556. while (PC != end)
  557. {
  558. // Get the current function pointer.
  559. fp = *((__GLlistExecFunc * const UNALIGNED64 *) PC);
  560. // Execute the current function. Return value is pointer to
  561. // next function/parameter block in the display list.
  562. PC = (*fp)(gc, PC+sizeof(__GLlistExecFunc * const *));
  563. }
  564. i++;
  565. }
  566. /* Decrement dlist refcount */
  567. // Will perform cleanup if necessary
  568. __glNamesUnlockDataList(gc, dlcount, (void **)dlists, DlCleanup);
  569. #ifdef NT_SERVER_SHARE_LISTS
  570. DlUnlockLists(gc, dlcount);
  571. }
  572. #endif
  573. listiter += dlcount * datasize;
  574. n -= dlcount;
  575. }
  576. dlstate->nesting--;
  577. }
  578. /*
  579. ** Display list compilation and execution versions of CallList and CallLists
  580. ** are maintained here for the sake of sanity. Note that __glle_CallLists
  581. ** may not call glcltCallLists or it will break the infinite recursive
  582. ** display list prevention code.
  583. */
  584. void APIENTRY
  585. __gllc_CallLists ( IN GLsizei n, IN GLenum type, IN const GLvoid *lists )
  586. {
  587. GLuint size;
  588. GLint arraySize;
  589. struct __gllc_CallLists_Rec *data;
  590. __GL_SETUP();
  591. if (n < 0) {
  592. __gllc_InvalidValue();
  593. return;
  594. }
  595. else if (n == 0) {
  596. return;
  597. }
  598. // It is extremely difficult to make CallList(s) work with poly array
  599. // compilation. For example, in the call sequence in COMPILE_AND_EXECUTE
  600. // mode [Begin, TexCoord, CallList, Vertex, ...], it is difficult to record
  601. // the partial POLYDATA in both COMPILE and COMPILE_AND_EXECUTE modes.
  602. // That is, we may end up recording and playing back TexCoord twice in the
  603. // above example. As a result, we may have to stop building poly array in
  604. // some cases. Fortunately, this situation is rare.
  605. if (gc->dlist.beginRec)
  606. {
  607. gc->dlist.beginRec->flags |= DLIST_BEGIN_HAS_CALLLIST;
  608. // Record the last POLYDATA since it may contain attribute changes.
  609. __glDlistCompilePolyData(gc, GL_TRUE);
  610. }
  611. arraySize = __glCallListsSize(type)*n;
  612. if (arraySize < 0) {
  613. __gllc_InvalidEnum();
  614. return;
  615. }
  616. #ifdef NT
  617. size = sizeof(struct __gllc_CallLists_Rec) + __GL_PAD(arraySize);
  618. #else
  619. arraySize = __GL_PAD(arraySize);
  620. size = sizeof(struct __gllc_CallLists_Rec) + arraySize;
  621. #endif
  622. data = (struct __gllc_CallLists_Rec *)
  623. __glDlistAddOpUnaligned(gc, DLIST_SIZE(size),
  624. DLIST_GENERIC_OP(CallLists));
  625. if (data == NULL) return;
  626. data->n = n;
  627. data->type = type;
  628. __GL_MEMCOPY((GLubyte *)data + sizeof(struct __gllc_CallLists_Rec),
  629. lists, arraySize);
  630. __glDlistAppendOp(gc, data, __glle_CallLists);
  631. if (gc->dlist.beginRec)
  632. {
  633. POLYARRAY *pa;
  634. pa = gc->paTeb;
  635. // In COMPILE_AND_EXECUTE mode, we can actually get out of the Begin mode.
  636. // Although it is an application error, we need to terminate poly array
  637. // compilation!
  638. if (!(pa->flags & POLYARRAY_IN_BEGIN))
  639. gc->dlist.beginRec = NULL;
  640. else
  641. {
  642. // If there is a partial vertex record after CallList(s), we will terminate
  643. // the poly array compilation. Otherwise, it is safe to continue the
  644. // processing.
  645. if (pa->pdNextVertex->flags)
  646. {
  647. // Terminate poly array compilation
  648. gc->dlist.beginRec = NULL;
  649. if (gc->dlist.mode == GL_COMPILE)
  650. {
  651. glsbResetBuffers(TRUE);
  652. // Clear begin flag too
  653. pa->flags &= ~POLYARRAY_IN_BEGIN;
  654. }
  655. }
  656. }
  657. }
  658. }
  659. const GLubyte * FASTCALL __glle_CallLists(__GLcontext *gc, const GLubyte *PC)
  660. {
  661. GLuint size;
  662. GLuint arraySize;
  663. struct __gllc_CallLists_Rec *data;
  664. data = (struct __gllc_CallLists_Rec *) PC;
  665. DoCallLists(data->n, data->type, (GLvoid *) (data+1));
  666. arraySize = __GL_PAD(__glCallListsSize(data->type)*data->n);
  667. size = sizeof(struct __gllc_CallLists_Rec) + arraySize;
  668. return PC + size;
  669. }
  670. void APIENTRY
  671. glcltCallLists ( IN GLsizei n, IN GLenum type, IN const GLvoid *lists )
  672. {
  673. __GL_SETUP();
  674. if (n < 0) {
  675. GLSETERROR(GL_INVALID_VALUE);
  676. return;
  677. }
  678. else if (n == 0) {
  679. return;
  680. }
  681. if ((GLint) __glCallListsSize(type) < 0) {
  682. GLSETERROR(GL_INVALID_ENUM);
  683. return;
  684. }
  685. gc->dlist.nesting = 0;
  686. DoCallLists(n, type, lists);
  687. }
  688. /************************************************************************/
  689. // Expand a dlist
  690. __GLdlist *__glDlistGrow(GLuint size)
  691. {
  692. __GLdlist *dlist, *newDlist;
  693. GLubyte * UNALIGNED64 *op;
  694. __GL_SETUP();
  695. newDlist = __glAllocDlist(gc, size);
  696. if (newDlist == NULL)
  697. {
  698. GLSETERROR(GL_OUT_OF_MEMORY);
  699. return NULL;
  700. }
  701. // Add on record to link old block to new block
  702. dlist = gc->dlist.listData;
  703. op = (GLubyte **)(dlist->head+dlist->used);
  704. *(__GLlistExecFunc * UNALIGNED64 *)op = __glle_NextBlock;
  705. *(op+1) = newDlist->head;
  706. // Shrink old block down to remove any wasted space at the end of it
  707. dlist = __glShrinkDlist(gc, dlist);
  708. // Link new block into chain
  709. newDlist->nextBlock = dlist;
  710. gc->dlist.listData = newDlist;
  711. return newDlist;
  712. }
  713. // Shrink a dlist block down to the minimum size
  714. // Guaranteed not to fail since we can always just use the overly
  715. // large block if the realloc fails
  716. // NOTE: This function should only be used during build time
  717. // where the nextBlock links are in the opposite direction of
  718. // the __glle_NextBlock link record links
  719. __GLdlist *__glShrinkDlist(__GLcontext *gc, __GLdlist *dlist)
  720. {
  721. __GLdlist *newDlist, *prevDlist;
  722. // If the amount of unused space is small, don't bother shrinking the block.
  723. if (dlist->size - dlist->used < 4096)
  724. return dlist;
  725. // If it is in COMPILE_AND_EXECUTE mode, flush the command buffer before
  726. // reallocating listData. Shrinking listData may invalidate the memory
  727. // pointers placed in the command buffer by the the display list execution
  728. // code. When we are in the middle of building POLYARRAY, glsbAttention
  729. // will not flush commands batched before the Begin call. As a result,
  730. // we also need to flush the command buffer before compiling the Begin call.
  731. if (gc->dlist.mode == GL_COMPILE_AND_EXECUTE)
  732. glsbAttention();
  733. #ifdef DL_HEAP_VERBOSE
  734. cbDlistTotal -= GL_MSIZE(dlist);
  735. #endif
  736. newDlist = (__GLdlist *)GCREALLOC(gc, dlist, dlist->used+DL_OVERHEAD);
  737. // If the realloc fails, just use the original list
  738. if (newDlist != NULL)
  739. {
  740. // If the realloc moved the block, fix up the link from the
  741. // previous block. This should be relatively rare
  742. if (newDlist != dlist && newDlist->nextBlock != NULL)
  743. {
  744. prevDlist = newDlist->nextBlock;
  745. ASSERTOPENGL(*(__GLlistExecFunc * UNALIGNED64 *)
  746. (prevDlist->head+prevDlist->used) == __glle_NextBlock,
  747. "Link not found where expected\n");
  748. *(GLubyte * UNALIGNED64 *)(prevDlist->head+prevDlist->used+
  749. sizeof(__GLlistExecFunc *)) = newDlist->head;
  750. }
  751. // If we are compiling the poly array record, we need to fix up
  752. // the Begin pointer! Note that if beginRec is not in the moved
  753. // block, the pointer does not change!
  754. if (newDlist != dlist && gc->dlist.beginRec &&
  755. (GLubyte *) gc->dlist.beginRec >= dlist->head &&
  756. (GLubyte *) gc->dlist.beginRec <= dlist->head + dlist->used)
  757. {
  758. gc->dlist.beginRec += newDlist->head - dlist->head;
  759. }
  760. dlist = newDlist;
  761. dlist->size = dlist->used;
  762. }
  763. #ifdef DL_HEAP_VERBOSE
  764. cbDlistTotal += GL_MSIZE(dlist);
  765. #endif
  766. return dlist;
  767. }
  768. __GLdlist *__glAllocDlist(__GLcontext *gc, GLuint size)
  769. {
  770. __GLdlist *dlist;
  771. __GLdlist temp;
  772. GLuint memsize;
  773. // Add on overhead and round size to an even block
  774. memsize = (size+DL_OVERHEAD+DL_BLOCK_SIZE-1) & ~(DL_BLOCK_SIZE-1);
  775. // Check overflow
  776. if (memsize < size)
  777. return NULL;
  778. size = memsize-DL_OVERHEAD;
  779. dlist = (__GLdlist *)GCALLOC(gc, memsize);
  780. if (dlist == NULL)
  781. return NULL;
  782. #if 0 // NT_SERVER_SHARE_LISTS
  783. dlist->refcount = 1;
  784. #else
  785. // refcount is set to 1 in __glNamesNewData.
  786. dlist->refcount = 0;
  787. #endif
  788. dlist->size = size;
  789. dlist->used = 0;
  790. dlist->nextBlock = NULL;
  791. #ifdef DL_HEAP_VERBOSE
  792. cbDlistTotal += GL_MSIZE(dlist);
  793. #endif
  794. return dlist;
  795. }
  796. void FASTCALL __glFreeDlist(__GLcontext *gc, __GLdlist *dlist)
  797. {
  798. __GLdlist *dlistNext;
  799. #ifdef NT_SERVER_SHARE_LISTS
  800. if (dlist->refcount != 0)
  801. {
  802. WARNING2("dlist %p refcount on free is %d\n", dlist, dlist->refcount);
  803. }
  804. #endif
  805. while (dlist != NULL)
  806. {
  807. dlistNext = dlist->nextBlock;
  808. #ifdef DL_HEAP_VERBOSE
  809. cbDlistTotal -= GL_MSIZE(dlist);
  810. #endif
  811. GCFREE(gc, dlist);
  812. dlist = dlistNext;
  813. }
  814. #ifdef DL_HEAP_VERBOSE
  815. DbgPrint("Dlists using %8d, total %8d\n",
  816. cbDlistTotal, glSize);
  817. #endif
  818. }