VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedOpenGL/dlm/dlm.c@ 55012

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

Host 3D: crServer: DLM: prevent thread local storage keys leak.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.0 KB
Line 
1/* $Id: dlm.c 55012 2015-03-30 16:35:43Z vboxsync $ */
2
3#include <float.h>
4#include "cr_dlm.h"
5#include "cr_mem.h"
6#include "dlm.h"
7
8/**
9 * \mainpage Dlm
10 *
11 * \section DlmIntroduction Introduction
12 *
13 * Chromium consists of all the top-level files in the cr
14 * directory. The dlm module basically takes care of API dispatch,
15 * and OpenGL state management.
16 *
17 */
18
19/**
20 * Module globals: the current DLM state, bound either to each thread, or
21 * to a global.
22 */
23#ifdef CHROMIUM_THREADSAFE
24CRtsd CRDLMTSDKey;
25#else
26CRDLMContextState *CRDLMCurrentState = NULL;
27#endif
28
29#define MIN(a,b) ((a)<(b)?(a):(b))
30
31
32/*************************************************************************/
33
34#ifdef CHROMIUM_THREADSAFE
35/**
36 * This is the thread-specific destructor function for the
37 * data used in the DLM. It's very simple: if a thread exits
38 * that has DLM-specific data, the data represents the listState
39 * for the thread. All data and buffers associated with the list
40 * can be deleted, and the structure itself can be freed.
41 *
42 * Most Chromium threads don't have such things; but then,
43 * if a thread dies elsewhere in Chromium, huge buffers
44 * of information won't still be floating around in
45 * unrecoverable allocated areas, either.
46 */
47static void threadDestructor(void *tsd)
48{
49 CRDLMContextState *listState = (CRDLMContextState *)tsd;
50
51 if (listState) {
52 if (listState->currentListInfo) {
53 crdlm_free_list(listState->currentListInfo);
54 }
55
56 crFree(listState);
57 }
58}
59#endif
60
61/**
62 * This function creates and initializes a new display list
63 * manager. It returns a pointer to the manager, or NULL in
64 * the case of insufficient memory. The dispatch table pointer
65 * is passed in to allow the utilities to muck with the table
66 * to gain functional control when GL calls are made.
67 */
68CRDLM DLM_APIENTRY *crDLMNewDLM(unsigned int userConfigSize, const CRDLMConfig *userConfig)
69{
70 CRDLM *dlm;
71
72 /* This is the default configuration. We'll overwrite it later
73 * with user-supplied configuration information.
74 */
75 CRDLMConfig config = {
76 CRDLM_DEFAULT_BUFFERSIZE,
77 };
78
79 dlm = crAlloc(sizeof(*dlm));
80 if (!dlm) {
81 return NULL;
82 }
83
84 /* Start off by initializing all entries that require further
85 * memory allocation, so we can free up all the memory if there's
86 * a problem.
87 */
88 if (!(dlm->displayLists = crAllocHashtable())) {
89 crFree(dlm);
90 return NULL;
91 }
92
93 /* The creator counts as the first user. */
94 dlm->userCount = 1;
95
96#ifdef CHROMIUM_THREADSAFE
97 /* This mutex ensures that only one thread is changing the displayLists
98 * hash at a time. Note that we may also need a mutex to guarantee that
99 * the hash is not changed by one thread while another thread is
100 * traversing it; this issue has not yet been resolved.
101 */
102 crInitMutex(&(dlm->dlMutex));
103
104 /* Although the thread-specific data (TSD) functions will initialize
105 * the thread key themselves when needed, those functions do not allow
106 * us to specify a thread destructor. Since a thread could potentially
107 * exit with considerable memory allocated (e.g. if a thread exits
108 * after it has issued NewList but before EndList, and while there
109 * are considerable content buffers allocated), I do the initialization
110 * myself, in order to be able to reclaim those resources if a thread
111 * exits.
112 */
113 crInitTSDF(&(dlm->tsdKey), threadDestructor);
114 crInitTSD(&CRDLMTSDKey);
115#endif
116
117 /* Copy over any appropriate configuration values */
118 if (userConfig != NULL) {
119 /* Copy over as much configuration information as is provided.
120 * Note that if the CRDLMConfig structure strictly grows, this
121 * allows forward compatability - routines compiled with
122 * older versions of the structure will only initialize that
123 * section of the structure that they know about.
124 */
125 crMemcpy((void *)&config, (void *) userConfig,
126 MIN(userConfigSize, sizeof(config)));
127 }
128 dlm->bufferSize = config.bufferSize;
129
130 /* Return the pointer to the newly-allocated display list manager */
131 return dlm;
132}
133
134void DLM_APIENTRY crDLMUseDLM(CRDLM *dlm)
135{
136 DLM_LOCK(dlm);
137 dlm->userCount++;
138 DLM_UNLOCK(dlm);
139}
140
141/**
142 * This routine is called when a context or thread is done with a DLM.
143 * It maintains an internal count of users, and will only actually destroy
144 * itself when no one is still using the DLM.
145 */
146void DLM_APIENTRY crDLMFreeDLM(CRDLM *dlm)
147{
148 /* We're about to change the displayLists hash; lock it first */
149 DLM_LOCK(dlm)
150
151 /* Decrement the user count. If the user count has gone to
152 * 0, then free the rest of the DLM. Otherwise, other
153 * contexts or threads are still using this DLM; keep
154 * it around.
155 */
156 dlm->userCount--;
157 if (dlm->userCount == 0) {
158
159 /* Free the set of display lists. As each one is freed, the
160 * crdlm_free_list function will be called to free up its
161 * internal resources. The crdlm_free_list() routine is
162 * cast to a (void *) to avoid warnings about being an
163 */
164 crFreeHashtable(dlm->displayLists, crdlm_free_list);
165 dlm->displayLists = NULL;
166
167 /* Must unlock before freeing the mutex */
168 DLM_UNLOCK(dlm)
169
170#ifdef CHROMIUM_THREADSAFE
171 /* We release the mutex here; we really should delete the
172 * thread data key, but there's no utility in Chromium to
173 * do this.
174 *
175 * Note that, should one thread release the entire DLM
176 * while other threads still believe they are using it,
177 * any other threads that have current display lists (i.e.
178 * have issued glNewList more recently than glEndList)
179 * will be unable to reclaim their (likely very large)
180 * content buffers, as there will be no way to reclaim
181 * the thread-specific data.
182 *
183 * On the other hand, if one thread really does release
184 * the DLM while other threads still believe they are
185 * using it, unreclaimed memory is the least of the
186 * application's problems...
187 */
188 crFreeMutex(&(dlm->dlMutex));
189
190 /* We free the TSD key here as well. Note that this will
191 * strand any threads that still have thread-specific data
192 * tied to this key; but as stated above, if any threads
193 * still do have thread-specific data attached to this DLM,
194 * they're in big trouble anyway.
195 */
196 crFreeTSD(&(dlm->tsdKey));
197 crFreeTSD(&CRDLMTSDKey);
198#endif
199
200 /* Free the master record, and we're all done. */
201 crFree(dlm);
202 }
203 else {
204 /* We're keeping the DLM around for other users. Unlock it,
205 * but retain its memory and display lists.
206 */
207 DLM_UNLOCK(dlm)
208 }
209}
210
211/**
212 * The actual run-time state of a DLM is bound to a context
213 * (because each context can be used by at most one thread at
214 * a time, and a thread can only use one context at a time,
215 * while multiple contexts can use the same DLM).
216 * This creates the structure required to hold the state, and
217 * returns it to the caller, who should store it with any other
218 * context-specific information.
219 */
220
221CRDLMContextState DLM_APIENTRY *crDLMNewContext(CRDLM *dlm)
222{
223 CRDLMContextState *state;
224
225 /* Get a record for our own internal state structure */
226 state = (CRDLMContextState *)crAlloc(sizeof(CRDLMContextState));
227 if (!state) {
228 return NULL;
229 }
230
231 state->dlm = dlm;
232 state->currentListIdentifier = 0;
233 state->currentListInfo = NULL;
234 state->currentListMode = GL_FALSE;
235 state->listBase = 0;
236 state->replayState = CRDLM_IMMEDIATE;
237
238 /* Increment the use count of the DLM provided. This guarantees that
239 * the DLM won't be released until all the contexts have released it.
240 */
241 crDLMUseDLM(dlm);
242
243 return state;
244}
245
246
247/**
248 * This routine should be called when a MakeCurrent changes the current
249 * context. It sets the thread data (or global data, in an unthreaded
250 * environment) appropriately; this in turn changes the behavior of
251 * the installed DLM API functions.
252 */
253void DLM_APIENTRY crDLMSetCurrentState(CRDLMContextState *state)
254{
255 CRDLMContextState *currentState = CURRENT_STATE();
256 if (currentState != state) {
257 SET_CURRENT_STATE(state);
258 }
259}
260
261CRDLMContextState DLM_APIENTRY *crDLMGetCurrentState(void)
262{
263 return CURRENT_STATE();
264}
265
266/**
267 * This routine, of course, is used to release a DLM context when it
268 * is no longer going to be used.
269 */
270
271void DLM_APIENTRY crDLMFreeContext(CRDLMContextState *state)
272{
273 CRDLMContextState *listState = CURRENT_STATE();
274
275 /* If we're currently using this context, release it first */
276 if (listState == state) {
277 crDLMSetCurrentState(NULL);
278 }
279
280 /* Try to free the DLM. This will either decrement the use count,
281 * or will actually free the DLM, if we were the last user.
282 */
283 crDLMFreeDLM(state->dlm);
284 state->dlm = NULL;
285
286 /* If any buffers still remain (e.g. because there was an open
287 * display list), remove those as well.
288 */
289 if (state->currentListInfo) {
290 crdlm_free_list((void *)state->currentListInfo);
291 }
292 state->currentListInfo = NULL;
293 state->currentListIdentifier = 0;
294
295 /* Free the state record itself */
296 crFree(state);
297}
298
299
300/**
301 * This function can be used if the caller wishes to free up the
302 * potentially considerable resources used to store the display list
303 * content, without losing the rest of the display list management.
304 * For one example, consider an SPU that conditionally sends its
305 * input stream to multiple servers. It could broadcast all display
306 * lists to all servers, or it could only send display lists to servers
307 * that need them. After all servers have the display list, the SPU
308 * may wish to release the resources used to manage the content.
309 */
310CRDLMError DLM_APIENTRY crDLMDeleteListContent(CRDLM *dlm, unsigned long listIdentifier)
311{
312 DLMListInfo *listInfo;
313 DLMInstanceList *instance;
314
315 listInfo = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
316 if (listInfo && (instance = listInfo->first)) {
317 while (instance) {
318 DLMInstanceList *nextInstance;
319 nextInstance = instance->next;
320 crFree(instance);
321 instance = nextInstance;
322 }
323 listInfo->first = listInfo->last = NULL;
324 }
325 return GL_NO_ERROR;
326}
327
328/* Return whether the current thread is involved in playback.
329 * This is useful for some routines to selectively choose their
330 * unpack state, for example (as replayed DLM functions must be
331 * unpacked with crStateNativePixelPacking instead of the
332 * normal unpack state, for example.
333 */
334CRDLMReplayState DLM_APIENTRY crDLMGetReplayState(void)
335{
336 CRDLMContextState *listState = CURRENT_STATE();
337 if (listState) {
338 return listState->replayState;
339 }
340 else {
341 return CRDLM_IMMEDIATE;
342 }
343}
344
345/**
346 *
347 * Playback/execute a list.
348 * dlm - the display list manager context
349 * listIdentifier - the display list ID (as specified by app) to playback
350 * dispatchTable - the GL dispatch table to jump through as we execute commands
351 */
352void DLM_APIENTRY crDLMReplayDLMList(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
353{
354 DLMListInfo *listInfo;
355
356 listInfo = (DLMListInfo *)crHashtableSearch(dlm->displayLists, listIdentifier);
357 if (listInfo) {
358 DLMInstanceList *instance = listInfo->first;
359 while (instance) {
360 /* mutex, to make sure another thread doesn't change the list? */
361 /* For now, leave it alone. */
362 (*instance->execute)(instance, dispatchTable);
363 instance = instance->next;
364 }
365 }
366}
367
368/* Playback/execute a list in the current DLM */
369void DLM_APIENTRY crDLMReplayList(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
370{
371 CRDLMContextState *listState = CURRENT_STATE();
372 if (listState) {
373 CRDLMReplayState oldReplayState = listState->replayState;
374 listState->replayState = CRDLM_REPLAY_ALL_FUNCTIONS;
375 crDLMReplayDLMList(listState->dlm, listIdentifier, dispatchTable);
376 listState->replayState = oldReplayState;
377 }
378}
379
380/*
381 * Playback/execute the state changing portions of a list.
382 * dlm - the display list manager context
383 * listIdentifier - the display list ID (as specified by app) to playback
384 * dispatchTable - the GL dispatch table to jump through as we execute commands
385 */
386void DLM_APIENTRY crDLMReplayDLMListState(CRDLM *dlm, unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
387{
388 DLMListInfo *listInfo;
389
390 listInfo = (DLMListInfo *)crHashtableSearch(dlm->displayLists, listIdentifier);
391 if (listInfo) {
392 DLMInstanceList *instance = listInfo->stateFirst;
393 while (instance) {
394 /* mutex, to make sure another thread doesn't change the list? */
395 /* For now, leave it alone. */
396 (*instance->execute)(instance, dispatchTable);
397 instance = instance->stateNext;
398 }
399 }
400}
401
402void DLM_APIENTRY crDLMReplayListState(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
403{
404 CRDLMContextState *listState = CURRENT_STATE();
405 if (listState) {
406 CRDLMReplayState oldReplayState = listState->replayState;
407 listState->replayState = CRDLM_REPLAY_STATE_FUNCTIONS;
408 crDLMReplayDLMListState(listState->dlm, listIdentifier, dispatchTable);
409 listState->replayState = oldReplayState;
410 }
411}
412
413/* This is a switch statement that lists every "type" value valid for a
414 * glCallLists() function call, with code for decoding the subsequent
415 * values correctly. It uses the current value of the EXPAND() macro,
416 * which must expand into an appropriate action to be taken.
417 * Its codification here allows for multiple uses.
418 */
419#define CALL_LISTS_SWITCH(type, defaultAction) \
420 switch (type) {\
421 EXPAND(GL_BYTE, GLbyte *, *p, p++)\
422 EXPAND(GL_UNSIGNED_BYTE, GLubyte *, *p, p++)\
423 EXPAND(GL_SHORT, GLshort *, *p, p++)\
424 EXPAND(GL_UNSIGNED_SHORT, GLushort *, *p, p++)\
425 EXPAND(GL_INT, GLint *, *p, p++)\
426 EXPAND(GL_FLOAT, GLfloat *, *p, p++)\
427 EXPAND(GL_2_BYTES, unsigned char *, 256*p[0] + p[1], p += 2)\
428 EXPAND(GL_3_BYTES, unsigned char *, 65536*p[0] + 256*p[1] + p[2], p += 3)\
429 EXPAND(GL_4_BYTES, unsigned char *, 16777216*p[0] + 65536*p[1] + 256*p[2] + p[3], p += 4)\
430 default:\
431 defaultAction;\
432 }
433
434void DLM_APIENTRY crDLMReplayDLMLists(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
435{
436 unsigned long listId;
437 CRDLMContextState *listState = CURRENT_STATE();
438
439#define EXPAND(TYPENAME, TYPE, REFERENCE, INCREMENT) \
440 case TYPENAME: {\
441 TYPE p = (TYPE)lists;\
442 while (n--) {\
443 listId = listState->listBase + (unsigned long) (REFERENCE);\
444 crDLMReplayDLMList(dlm, listId, dispatchTable);\
445 INCREMENT;\
446 }\
447 break;\
448 }
449
450 CALL_LISTS_SWITCH(type, break)
451#undef EXPAND
452
453}
454
455void DLM_APIENTRY crDLMReplayLists(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
456{
457 CRDLMContextState *listState = CURRENT_STATE();
458 if (listState) {
459 crDLMReplayDLMLists(listState->dlm, n, type, lists, dispatchTable);
460 }
461}
462
463void DLM_APIENTRY crDLMReplayDLMListsState(CRDLM *dlm, GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
464{
465 unsigned long listId;
466 CRDLMContextState *listState = CURRENT_STATE();
467
468#define EXPAND(TYPENAME, TYPE, REFERENCE, INCREMENT) \
469 case TYPENAME: {\
470 TYPE p = (TYPE)lists;\
471 while (n--) {\
472 listId = listState->listBase + (unsigned long) (REFERENCE);\
473 crDLMReplayDLMListState(dlm, listId, dispatchTable);\
474 INCREMENT;\
475 }\
476 break;\
477 }
478
479 CALL_LISTS_SWITCH(type, break)
480#undef EXPAND
481
482}
483
484void DLM_APIENTRY crDLMReplayListsState(GLsizei n, GLenum type, const GLvoid * lists, SPUDispatchTable *dispatchTable)
485{
486 CRDLMContextState *listState = CURRENT_STATE();
487 if (listState) {
488 crDLMReplayDLMListsState(listState->dlm, n, type, lists, dispatchTable);
489 }
490}
491
492/* When we compiled the display list, we packed all pixel data
493 * tightly. When we execute the display list, we have to make
494 * sure that the client state reflects that the pixel data is
495 * tightly packed, or it will be interpreted incorrectly.
496 */
497void DLM_APIENTRY crDLMSetupClientState(SPUDispatchTable *dispatchTable)
498{
499 dispatchTable->PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
500 dispatchTable->PixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
501 dispatchTable->PixelStorei(GL_UNPACK_SKIP_ROWS, 0);
502 dispatchTable->PixelStorei(GL_UNPACK_ALIGNMENT, 1);
503}
504
505void DLM_APIENTRY crDLMRestoreClientState(CRClientState *clientState, SPUDispatchTable *dispatchTable)
506{
507 if (clientState) {
508 dispatchTable->PixelStorei(GL_UNPACK_ROW_LENGTH, clientState->unpack.rowLength);
509 dispatchTable->PixelStorei(GL_UNPACK_SKIP_PIXELS, clientState->unpack.skipPixels);
510 dispatchTable->PixelStorei(GL_UNPACK_SKIP_ROWS, clientState->unpack.skipRows);
511 dispatchTable->PixelStorei(GL_UNPACK_ALIGNMENT, clientState->unpack.alignment);
512 }
513}
514
515void DLM_APIENTRY crDLMSendDLMList(CRDLM *dlm, unsigned long listIdentifier,
516 SPUDispatchTable *dispatchTable)
517{
518 dispatchTable->NewList(listIdentifier, GL_COMPILE);
519 crDLMReplayDLMList(dlm, listIdentifier, dispatchTable);
520 dispatchTable->EndList();
521}
522
523void DLM_APIENTRY crDLMSendList(unsigned long listIdentifier, SPUDispatchTable *dispatchTable)
524{
525 CRDLMContextState *listState = CURRENT_STATE();
526 if (listState) {
527 crDLMSendDLMList(listState->dlm, listIdentifier, dispatchTable);
528 }
529}
530
531struct sendListsCallbackParms {
532 CRDLM *dlm;
533 SPUDispatchTable *dispatchTable;
534};
535
536static void sendListsCallback(unsigned long key, void *data, void *dataPtr2)
537{
538 struct sendListsCallbackParms *parms = (struct sendListsCallbackParms *)dataPtr2;
539
540 crDLMSendDLMList(parms->dlm, key, parms->dispatchTable);
541}
542
543void DLM_APIENTRY crDLMSendAllDLMLists(CRDLM *dlm, SPUDispatchTable *dispatchTable)
544{
545 struct sendListsCallbackParms parms;
546
547 /* This is how we pass our parameter information to the callback routine -
548 * through a pointer to this local structure.
549 */
550 parms.dlm = dlm;
551 parms.dispatchTable = dispatchTable;
552
553 crHashtableWalk(dlm->displayLists, sendListsCallback, (void *)&parms);
554}
555
556void DLM_APIENTRY crDLMSendAllLists(SPUDispatchTable *dispatchTable)
557{
558 CRDLMContextState *listState = CURRENT_STATE();
559 if (listState) {
560 crDLMSendAllDLMLists(listState->dlm, dispatchTable);
561 }
562}
563
564/** Another clever callback arrangement to get the desired data. */
565struct getRefsCallbackParms {
566 int remainingOffset;
567 int remainingCount;
568 unsigned int *buffer;
569 int totalCount;
570};
571
572static void getRefsCallback(unsigned long key, void *data, void *dataPtr2)
573{
574 struct getRefsCallbackParms *cbParms =
575 (struct getRefsCallbackParms *)dataPtr2;
576
577 /* Count the total number of references */
578 cbParms->totalCount++;
579
580 /* If we haven't yet reached the desired offset, decrement it */
581 if (cbParms->remainingOffset > 0) {
582 cbParms->remainingOffset--;
583 }
584 else if (cbParms->remainingCount > 0) {
585 /* Store data until we've stored all we can.
586 */
587 *(cbParms->buffer++) = key;
588 cbParms->remainingCount--;
589 }
590}
591
592int DLM_APIENTRY crDLMGetReferences(CRDLM *dlm, unsigned long listIdentifier,
593 int firstIndex, int sizeofBuffer, unsigned int *buffer)
594{
595 DLMListInfo *listInfo;
596
597 listInfo = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
598 if (listInfo) {
599 struct getRefsCallbackParms cbParms;
600
601 cbParms.remainingOffset = firstIndex;
602 cbParms.remainingCount = sizeofBuffer;
603 cbParms.buffer = buffer;
604 cbParms.totalCount = 0;
605
606 crHashtableWalk(listInfo->references, getRefsCallback, (void *)&cbParms);
607
608 return cbParms.totalCount;
609 }
610 else {
611 /* No list exists; it therefore has no references */
612 return 0;
613 }
614}
615
616CRDLMError DLM_APIENTRY crDLMGetDLMBounds(CRDLM *dlm, unsigned long listIdentifier, CRDLMBounds *bounds)
617{
618 DLMListInfo *listInfo
619 = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
620 if (listInfo) {
621 *bounds = listInfo->bbox;
622 return GL_NO_ERROR;
623 }
624 else {
625 return GL_INVALID_OPERATION;
626 }
627}
628
629CRDLMError DLM_APIENTRY crDLMGetBounds(unsigned long listIdentifier, CRDLMBounds *bounds)
630{
631 CRDLMContextState *listState = CURRENT_STATE();
632 if (listState) {
633 return crDLMGetDLMBounds(listState->dlm, listIdentifier, bounds);
634 }
635 else {
636 return CRDLM_ERROR_STATE;
637 }
638}
639
640
641/**
642 * Set the bounding box for a display list.
643 */
644void DLM_APIENTRY crDLMSetDLMBounds(CRDLM *dlm, unsigned long listIdentifier,
645 double xmin, double ymin, double zmin,
646 double xmax, double ymax, double zmax)
647{
648 DLMListInfo *listInfo
649 = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
650 if (!listInfo) {
651 /* allocate a list info now */
652 CRDLMContextState *listState = CURRENT_STATE();
653 listInfo = (DLMListInfo *) crCalloc(sizeof(DLMListInfo));
654 crHashtableReplace(listState->dlm->displayLists,
655 listIdentifier, listInfo, crdlm_free_list);
656 }
657 if (listInfo) {
658 listInfo->bbox.xmin = xmin;
659 listInfo->bbox.ymin = ymin;
660 listInfo->bbox.zmin = zmin;
661 listInfo->bbox.xmax = xmax;
662 listInfo->bbox.ymax = ymax;
663 listInfo->bbox.zmax = zmax;
664 }
665}
666
667void DLM_APIENTRY crDLMSetBounds(unsigned long listIdentifier,
668 double xmin, double ymin, double zmin,
669 double xmax, double ymax, double zmax)
670{
671 CRDLMContextState *listState = CURRENT_STATE();
672 if (listState) {
673 crDLMSetDLMBounds(listState->dlm, listIdentifier,
674 xmin, ymin, zmin, xmax, ymax, zmax);
675 }
676}
677
678/**
679 * Return GL_TRUE if the given list has a valid bounding box
680 */
681GLboolean DLM_APIENTRY crDLMListHasDLMBounds(CRDLM *dlm, unsigned long listIdentifier)
682{
683 DLMListInfo *listInfo
684 = (DLMListInfo *) crHashtableSearch(dlm->displayLists, listIdentifier);
685 if (listInfo)
686 return listInfo->bbox.xmin != FLT_MAX;
687 else
688 return GL_FALSE;
689}
690
691GLboolean DLM_APIENTRY crDLMListHasBounds(unsigned long listIdentifier)
692{
693 CRDLMContextState *listState = CURRENT_STATE();
694 if (listState) {
695 return crDLMListHasDLMBounds(listState->dlm, listIdentifier);
696 }
697 return 0;
698}
699
700/*
701 * Return id of list currently being compiled. Returns 0 of there's no
702 * current DLM state, or if no list is being compiled.
703 */
704GLuint DLM_APIENTRY crDLMGetCurrentList(void)
705{
706 CRDLMContextState *listState = CURRENT_STATE();
707 return listState ? listState->currentListIdentifier : 0;
708}
709
710/*
711 * Return mode of list currently being compiled. Should be
712 * GL_FALSE if no list is being compiled, or GL_COMPILE if a
713 * list is being compiled but not executed, or GL_COMPILE_AND_EXECUTE
714 * if a list is being compiled and executed.
715 */
716GLenum DLM_APIENTRY crDLMGetCurrentMode(void)
717{
718 CRDLMContextState *listState = CURRENT_STATE();
719 return listState ? listState->currentListMode : 0;
720}
721
722
723static CRDLMErrorCallback ErrorCallback = NULL;
724
725void DLM_APIENTRY crDLMErrorFunction(CRDLMErrorCallback callback)
726{
727 ErrorCallback = callback;
728}
729
730void crdlm_error(int line, const char *file, GLenum error, const char *info)
731{
732 if (ErrorCallback)
733 (*ErrorCallback)(line, file, error, info);
734}
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