-
Notifications
You must be signed in to change notification settings - Fork 2
/
dlm_lists.c
274 lines (236 loc) · 7.78 KB
/
dlm_lists.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#include <float.h>
#include "cr_dlm.h"
#include "cr_mem.h"
#include "dlm.h"
/* This file defines the display list functions such as NewList, EndList,
* IsList, DeleteLists, etc.
* Generally, SPUs will call these as needed to implement display lists.
* See the expando, replicate, and tilesort SPUs for examples.
*
* The functions which compile GL functions into our display lists are named:
* void DLM_APIENTRY crdlm_<function name>
* where <function_name> is the Chromium function name (which in
* turn is the GL function name with the "gl" prefix removed).
*
* All these entry points require that a CRDLMContextState structure
* be created (with crDLMNewContext()) and assigned to the current
* thread (with crDLMSetCurrentState()).
*/
/*
* Begin compiling a list.
*/
void DLM_APIENTRY
crDLMNewList(GLuint listIdentifier, GLenum mode)
{
DLMListInfo *listInfo;
CRDLMContextState *listState = CURRENT_STATE();
/* Error checks: 0 is not a valid identifier, and
* we can't call NewList if NewList has been called
* more recently than EndList.
*
* The caller is expected to check for an improper
* mode parameter (GL_INVALID_ENUM), or for a NewList
* within a glBegin/glEnd (GL_INVALID_OPERATION).
*/
if (listState == NULL)
{
crWarning("DLM error: NewList(%d,%d) called with no current state (%s line %d)\n",
(int) listIdentifier, (int) mode, __FILE__, __LINE__);
return;
}
if (listIdentifier == 0)
{
crdlm_error(__LINE__, __FILE__, GL_INVALID_VALUE,
"NewList called with a list identifier of 0");
return;
}
if (listState->currentListInfo != NULL)
{
char msg[1000];
sprintf(msg, "NewList called with display list %d while display list %d was already open",
(int) listIdentifier, (int) listState->currentListIdentifier);
crdlm_error(__LINE__, __FILE__, GL_INVALID_OPERATION, msg);
return;
}
listInfo = (DLMListInfo *) crCalloc(sizeof(DLMListInfo));
if (!(listInfo))
{
char msg[1000];
sprintf(msg, "could not allocate %u bytes of memory in NewList",
(unsigned) sizeof(DLMListInfo));
crdlm_error(__LINE__, __FILE__, GL_OUT_OF_MEMORY, msg);
return;
}
listInfo->first = listInfo->last = NULL;
listInfo->stateFirst = listInfo->stateLast = NULL;
listInfo->references = crAllocHashtable();
if (!(listInfo->references))
{
crFree(listInfo);
crdlm_error(__LINE__, __FILE__, GL_OUT_OF_MEMORY,
"could not allocate memory in NewList");
return;
}
listInfo->numInstances = 0;
listInfo->listSent = GL_FALSE;
listInfo->bbox.xmin = FLT_MAX;
listInfo->bbox.xmax = -FLT_MAX;
listInfo->bbox.ymin = FLT_MAX;
listInfo->bbox.ymax = -FLT_MAX;
listInfo->bbox.zmin = FLT_MAX;
listInfo->bbox.zmax = -FLT_MAX;
listState->currentListInfo = listInfo;
listState->currentListIdentifier = listIdentifier;
listState->currentListMode = mode;
}
/* This small utility routine is used to traverse a buffer
* list, freeing each buffer. It is used to free the buffer
* list in the DLMListInfo structure, both when freeing the
* entire structure and when freeing just the retained content.
*/
static void free_instance_list(DLMInstanceList * instance)
{
while (instance)
{
DLMInstanceList *nextInstance = instance->next;
crFree(instance);
instance = nextInstance;
}
}
/* This utility routine frees a DLMListInfo structure and all
* of its components. It is used directly, when deleting a
* single list; it is also used as a callback function for
* hash tree operations (Free and Replace).
*
* The parameter is listed as a (void *) instead of a (DLMListInfo *)
* in order that the function can be used as a callback routine for
* the hash table functions. The (void *) designation causes no
* other harm, save disabling type-checking on the pointer argument
* of the function.
*/
void crdlm_free_list(void *parm)
{
DLMListInfo *listInfo = (DLMListInfo *) parm;
free_instance_list(listInfo->first);
listInfo->first = listInfo->last = NULL;
/* The references list has no allocated information; it's
* just a set of entries. So we don't need to free any
* information as each entry is deleted.
*/
crFreeHashtable(listInfo->references, NULL);
crFree(listInfo);
}
void DLM_APIENTRY crDLMEndList(void)
{
CRDLMContextState *listState = CURRENT_STATE();
/* Error check: cannot call EndList without a (successful)
* preceding NewList.
*
* The caller is expected to check for glNewList within
* a glBegin/glEnd sequence.
*/
if (listState == NULL)
{
crWarning("DLM error: EndList called with no current state (%s line %d)\n",
__FILE__, __LINE__);
return;
}
if (listState->currentListInfo == NULL)
{
crdlm_error(__LINE__, __FILE__, GL_INVALID_OPERATION,
"EndList called while no display list was open");
return;
}
DLM_LOCK(listState->dlm)
/* This function will either replace the list information that's
* already present with our new list information, freeing the
* former list information; or will add the new information
* to the set of display lists, depending on whether the
* list already exists or not.
*/
crHashtableReplace(listState->dlm->displayLists,
listState->currentListIdentifier,
listState->currentListInfo, crdlm_free_list);
DLM_UNLOCK(listState->dlm)
/* reset the current state to show the list had been ended */
listState->currentListIdentifier = 0;
listState->currentListInfo = NULL;
listState->currentListMode = GL_FALSE;
}
void DLM_APIENTRY crDLMDeleteLists(GLuint firstListIdentifier, GLsizei range)
{
CRDLMContextState *listState = CURRENT_STATE();
register int i;
if (listState == NULL)
{
crWarning
("DLM error: DeleteLists(%d,%d) called with no current state (%s line %d)\n",
(int) firstListIdentifier, (int) range, __FILE__, __LINE__);
return;
}
if (range < 0)
{
char msg[1000];
sprintf(msg, "DeleteLists called with range (%d) less than zero", (int) range);
crdlm_error(__LINE__, __FILE__, GL_INVALID_VALUE, msg);
return;
}
/* Interestingly, there doesn't seem to be an error for deleting
* display list 0, which cannot exist.
*
* We could delete the desired lists by walking the entire hash of
* display lists and looking for and deleting any in our range; or we
* could delete lists one by one. The former is faster if the hashing
* algorithm is inefficient or if we're deleting all or most of our
* lists; the latter is faster if we're deleting a relatively small
* number of lists.
*
* For now, we'll go with the latter; it's also easier to implement
* given the current functions available.
*/
DLM_LOCK(listState->dlm)
for (i = 0; i < range; i++)
{
crHashtableDelete(listState->dlm->displayLists,
firstListIdentifier + i, crdlm_free_list);
}
DLM_UNLOCK(listState->dlm)
}
GLboolean DLM_APIENTRY crDLMIsList(GLuint list)
{
CRDLMContextState *listState = CURRENT_STATE();
if (listState == NULL)
{
crWarning
("DLM error: IsLists(%d) called with no current state (%s line %d)\n",
(int) list, __FILE__, __LINE__);
return 0;
}
if (list == 0)
return GL_FALSE;
return crHashtableIsKeyUsed(listState->dlm->displayLists, list);
}
GLuint DLM_APIENTRY crDLMGenLists(GLsizei range)
{
CRDLMContextState *listState = CURRENT_STATE();
if (listState == NULL)
{
crWarning
("DLM error: GenLists(%d) called with no current state (%s line %d)\n",
(int) range, __FILE__, __LINE__);
return 0;
}
return crHashtableAllocKeys(listState->dlm->displayLists, range);
}
void DLM_APIENTRY crDLMListBase( GLuint base )
{
CRDLMContextState *listState = CURRENT_STATE();
if (listState == NULL)
{
crWarning
("DLM error: ListBase(%d) called with no current state (%s line %d)\n",
(int) base, __FILE__, __LINE__);
return;
}
listState->listBase = base;
}