VirtualBox

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

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

Host 3D: Display Lists: fix crash: only add glListBase() to cache if we are currently recording a list.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.1 KB
Line 
1/* $Id: dlm_lists.c 56943 2015-07-15 17:45:54Z vboxsync $ */
2
3/** @file
4 * Implementation of all the Display Lists related routines:
5 *
6 * glGenLists, glDeleteLists, glNewList, glEndList, glCallList, glCallLists,
7 * glListBase and glIsList.
8 *
9 * Provide OpenGL IDs mapping between host and guest.
10 */
11
12/*
13 * Copyright (C) 2015 Oracle Corporation
14 *
15 * This file is part of VirtualBox Open Source Edition (OSE), as
16 * available from http://www.virtualbox.org. This file is free software;
17 * you can redistribute it and/or modify it under the terms of the GNU
18 * General Public License (GPL) as published by the Free Software
19 * Foundation, in version 2 as it comes in the "COPYING" file of the
20 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22 */
23
24#include <float.h>
25#include "cr_dlm.h"
26#include "cr_mem.h"
27#include "dlm.h"
28
29
30/**
31 * Destroy each list entry.
32 */
33static void crdlmFreeDisplayListElements(DLMInstanceList *instance)
34{
35 while (instance)
36 {
37 DLMInstanceList *nextInstance = instance->next;
38 crFree(instance);
39 instance = nextInstance;
40 }
41}
42
43
44/**
45 * A callback routine used when iterating over all
46 * available lists in order to remove them.
47 *
48 * NOTE: @param pParam2 might be NULL.
49 */
50void crdlmFreeDisplayListResourcesCb(void *pParm1, void *pParam2)
51{
52 DLMListInfo *pListInfo = (DLMListInfo *)pParm1;
53 SPUDispatchTable *dispatchTable = (SPUDispatchTable *)pParam2;
54
55 if (pListInfo)
56 {
57 crdlmFreeDisplayListElements(pListInfo->first);
58 pListInfo->first = pListInfo->last = NULL;
59
60 /* Free host OpenGL resources. */
61 if (dispatchTable)
62 dispatchTable->DeleteLists(pListInfo->hwid, 1);
63
64 crFree(pListInfo);
65 }
66}
67
68
69/**
70 * Generate host and guest IDs, setup IDs mapping between host and guest.
71 */
72GLuint DLM_APIENTRY crDLMGenLists(GLsizei range, SPUDispatchTable *dispatchTable)
73{
74 CRDLMContextState *listState = CURRENT_STATE();
75 GLuint idHostRangeStart = 0;
76 GLuint idGuestRangeStart = 0;
77
78 crDebug("DLM: GenLists(%d) (DLM=%p).", range, listState ? listState->dlm : 0);
79
80 if (listState)
81 {
82 idHostRangeStart = dispatchTable->GenLists(range);
83 if (idHostRangeStart > 0)
84 {
85 idGuestRangeStart = crHashtableAllocKeys(listState->dlm->displayLists, range);
86 if (idGuestRangeStart > 0)
87 {
88 GLuint i;
89 bool fSuccess = true;
90
91 /* Now have successfully generated IDs range for host and guest. Let's make IDs association. */
92 for (i = 0; i < (GLuint)range; i++)
93 {
94 DLMListInfo *pListInfo;
95
96 pListInfo = (DLMListInfo *)crCalloc(sizeof(DLMListInfo));
97 if (pListInfo)
98 {
99 crMemset(pListInfo, 0, sizeof(DLMListInfo));
100 pListInfo->hwid = idHostRangeStart + i;
101
102 /* Insert pre-initialized list data which contains IDs mapping into the hash. */
103 crHashtableReplace(listState->dlm->displayLists, idGuestRangeStart + i, pListInfo, NULL);
104 }
105 else
106 {
107 fSuccess = false;
108 break;
109 }
110 }
111
112 /* All structures allocated and initialized successfully. */
113 if (fSuccess)
114 return idGuestRangeStart;
115
116 /* Rollback some data was not allocated. */
117 crDLMDeleteLists(idGuestRangeStart, range, NULL /* we do DeleteLists() later in this routine */ );
118 }
119 else
120 crDebug("DLM: Can't allocate Display List IDs range for the guest.");
121
122 dispatchTable->DeleteLists(idHostRangeStart, range);
123 }
124 else
125 crDebug("DLM: Can't allocate Display List IDs range on the host side.");
126 }
127 else
128 crDebug("DLM: GenLists(%u) called with no current state.", range);
129
130 /* Can't reserve IDs range. */
131 return 0;
132}
133
134
135/**
136 * Release host and guest IDs, free memory resources.
137 */
138void DLM_APIENTRY crDLMDeleteLists(GLuint list, GLsizei range, SPUDispatchTable *dispatchTable)
139{
140 CRDLMContextState *listState = CURRENT_STATE();
141
142 crDebug("DLM: DeleteLists(%u, %d) (DLM=%p).", list, range, listState ? listState->dlm : 0);
143
144 if (listState)
145 {
146 if (range >= 0)
147 {
148 int i;
149
150 /* Free resources: host memory, host IDs and guest IDs. */
151 DLM_LOCK(listState->dlm)
152 for (i = 0; i < range; i++)
153 crHashtableDeleteEx(listState->dlm->displayLists, list + i, crdlmFreeDisplayListResourcesCb, dispatchTable);
154 DLM_UNLOCK(listState->dlm)
155 }
156 else
157 crDebug("DLM: DeleteLists(%u, %d) not allowed.", list, range);
158 }
159 else
160 crDebug("DLM: DeleteLists(%u, %d) called with no current state.", list, range);
161}
162
163
164/**
165 * Start recording a list.
166 */
167void DLM_APIENTRY
168crDLMNewList(GLuint list, GLenum mode, SPUDispatchTable *dispatchTable)
169{
170 DLMListInfo *listInfo;
171 CRDLMContextState *listState = CURRENT_STATE();
172
173 crDebug("DLM: NewList(%u, %u) (DLM=%p).", list, mode, listState ? listState->dlm : 0);
174
175 if (listState)
176 {
177 /* Valid list ID should be > 0. */
178 if (list > 0)
179 {
180 if (listState->currentListInfo == NULL)
181 {
182 listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
183 if (listInfo)
184 {
185 listInfo->first = listInfo->last = NULL;
186 listInfo->stateFirst = listInfo->stateLast = NULL;
187
188 listInfo->numInstances = 0;
189
190 listState->currentListInfo = listInfo;
191 listState->currentListIdentifier = list;
192 listState->currentListMode = mode;
193
194 dispatchTable->NewList(listInfo->hwid, mode);
195
196 crDebug("DLM: create new list with [guest, host] ID pair [%u, %u].", list, listInfo->hwid);
197
198 return;
199 }
200 else
201 crDebug("DLM: Requested Display List %u was not previously reserved with glGenLists().", list);
202 }
203 else
204 crDebug("DLM: NewList called with display list %u while display list %u was already open.", list, listState->currentListIdentifier);
205 }
206 else
207 crDebug("DLM: NewList called with a list identifier of 0.");
208 }
209 else
210 crDebug("DLM: NewList(%u, %u) called with no current state.\n", list, mode);
211}
212
213
214/**
215 * Stop recording a list.
216 */
217void DLM_APIENTRY crDLMEndList(SPUDispatchTable *dispatchTable)
218{
219 CRDLMContextState *listState = CURRENT_STATE();
220
221 crDebug("DLM: EndList() (DLM=%p).", listState ? listState->dlm : 0);
222
223 if (listState)
224 {
225 /* Check if list was ever started. */
226 if (listState->currentListInfo)
227 {
228 /* reset the current state to show the list had been ended */
229 listState->currentListIdentifier = 0;
230 listState->currentListInfo = NULL;
231 listState->currentListMode = GL_FALSE;
232
233 dispatchTable->EndList();
234 }
235 else
236 crDebug("DLM: glEndList() is assuming glNewList() was issued previously.");
237 }
238 else
239 crDebug("DLM: EndList called with no current state.");
240}
241
242
243/**
244 * Execute list on hardware and cach ethis call if we currently recording a list.
245 */
246void DLM_APIENTRY crDLMCallList(GLuint list, SPUDispatchTable *dispatchTable)
247{
248 CRDLMContextState *listState = CURRENT_STATE();
249
250 //crDebug("DLM: CallList(%u).", list);
251
252 if (listState)
253 {
254 DLMListInfo *listInfo;
255
256 /* Add to calls cache if we recording a list. */
257 if (listState->currentListInfo)
258 crDLMCompileCallList(list);
259
260 /* Find hwid for list.
261 * We need to take into account listBase:
262 * - displayLists hash table contains absolute IDs, so we need to add offset in order to resolve guest ID;
263 * - we also need to substract from hwid in order to execute correct list. */
264 listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list + listState->listBase);
265 if (listInfo)
266 dispatchTable->CallList(listInfo->hwid - listState->listBase);
267 else
268 crDebug("DLM: CallList(%u) issued for non-existent list.", list);
269 }
270 else
271 crDebug("DLM: CallList(%u) called with no current state.", list);
272}
273
274
275/* This routine translates guest Display List IDs in given format to host IDs.
276 * It is based on TranslateListIDs() function from crserverlib/server_lists.c. */
277static bool
278crDLMConvertListIDs(CRDLMContextState *pListState, GLsizei n, GLenum type, const GLvoid *aGuest, GLuint *aHost)
279{
280#define CRDLM_HANDLE_CONVERSION_CASE(_type, _item) \
281 { \
282 const _type *src = (const _type *)aGuest; \
283 for (i = 0; i < n; i++) \
284 { \
285 GLuint idGuest = (GLuint)(_item) + pListState->listBase; \
286 pListInfo = (DLMListInfo *)crHashtableSearch(pListState->dlm->displayLists, idGuest); \
287 if (pListInfo) \
288 { \
289 aHost[i] = pListInfo->hwid - pListState->listBase; \
290 } \
291 else \
292 { \
293 crDebug("DLM: CallLists() cannot resolve host list ID for guest ID %u.", idGuest); \
294 fSuccess = false; \
295 break; \
296 } \
297 } \
298 }
299
300 GLsizei i;
301 DLMListInfo *pListInfo;
302 bool fSuccess = true;
303
304 switch (type)
305 {
306 case GL_UNSIGNED_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i]); break;
307 case GL_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLbyte, src[i]); break;
308 case GL_UNSIGNED_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLushort, src[i]); break;
309 case GL_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLshort, src[i]); break;
310 case GL_UNSIGNED_INT: CRDLM_HANDLE_CONVERSION_CASE(GLuint, src[i]); break;
311 case GL_INT: CRDLM_HANDLE_CONVERSION_CASE(GLint, src[i]); break;
312 case GL_FLOAT: CRDLM_HANDLE_CONVERSION_CASE(GLfloat, src[i]); break;
313
314 case GL_2_BYTES:
315 {
316 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 2 + 0] * 256 +
317 src[i * 2 + 1]);
318 break;
319 }
320
321 case GL_3_BYTES:
322 {
323 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 3 + 0] * 256 * 256 +
324 src[i * 3 + 1] * 256 +
325 src[i * 3 + 2]);
326 break;
327 }
328
329 case GL_4_BYTES:
330 {
331 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 4 + 0] * 256 * 256 * 256 +
332 src[i * 4 + 1] * 256 * 256 +
333 src[i * 4 + 2] * 256 +
334 src[i * 4 + 3]);
335 break;
336 }
337
338 default:
339 crWarning("DLM: attempt to pass to crDLMCallLists() an unknown type: 0x%x.", type);
340 }
341
342 return fSuccess;
343#undef CRDLM_HANDLE_CONVERSION_CASE
344}
345
346
347/**
348 * Execute lists on hardware and cache this call if we currently recording a list.
349 */
350void DLM_APIENTRY crDLMCallLists(GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable)
351{
352 CRDLMContextState *pListState = CURRENT_STATE();
353
354 crDebug("DLM: CallLists(%d, %u, %p).", n, type, lists);
355
356 if (pListState)
357 {
358 GLsizei i;
359 GLuint *aHostIDs;
360
361 /* Add to calls cache if we recording a list. */
362 if (pListState->currentListInfo)
363 crDLMCompileCallLists(n, type, lists);
364
365 aHostIDs = (GLuint *)crAlloc(n * sizeof(GLuint));
366 if (aHostIDs)
367 {
368 if (crDLMConvertListIDs(pListState, n, type, lists, aHostIDs))
369 dispatchTable->CallLists(n, type, aHostIDs);
370 else
371 crDebug("DLM: CallLists() failed.");
372
373 crFree(aHostIDs);
374 }
375 else
376 crDebug("DLM: no memory on CallLists().");
377 }
378 else
379 crDebug("DLM: CallLists(%d, %u, %p) called with no current state.", n, type, lists);
380}
381
382
383/**
384 * Set list base, remember its value and add call to the cache.
385 */
386void DLM_APIENTRY crDLMListBase(GLuint base, SPUDispatchTable *dispatchTable)
387{
388 CRDLMContextState *pListState = CURRENT_STATE();
389
390 crDebug("DLM: ListBase(%u).", base);
391
392 if (pListState)
393 {
394 pListState->listBase = base;
395
396 /* Only add to cache if we are currently recording a list. */
397 /* TODO: Do we really need to chache it? */
398 if (pListState->currentListInfo)
399 crDLMCompileListBase(base);
400
401 dispatchTable->ListBase(base);
402 }
403 else
404 crDebug("DLM: ListBase(%u) called with no current state.", base);
405}
406
407
408/**
409 * Check if specified list ID belongs to valid Display List.
410 * Positive result is only returned in case both conditions below are satisfied:
411 *
412 * - given list found in DLM hash table (i.e., it was previously allocated
413 * with crDLMGenLists and still not released with crDLMDeleteLists);
414 *
415 * - list is valid on the host side.
416 */
417GLboolean DLM_APIENTRY crDLMIsList(GLuint list, SPUDispatchTable *dispatchTable)
418{
419 CRDLMContextState *listState = CURRENT_STATE();
420
421 crDebug("DLM: IsList(%u).", list);
422
423 if (listState)
424 {
425 if (list > 0)
426 {
427 DLMListInfo *listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
428 if (listInfo)
429 {
430 if (dispatchTable->IsList(listInfo->hwid))
431 return true;
432 else
433 crDebug("DLM: list [%u, %u] not found on the host side.", list, listInfo->hwid);
434 }
435 else
436 crDebug("DLM: list %u not found in guest cache.", list);
437 }
438 else
439 crDebug("DLM: IsList(%u) is not allowed.", list);
440 }
441 else
442 crDebug("DLM: IsList(%u) called with no current state.", list);
443
444 return false;
445}
Note: See TracBrowser for help on using the repository browser.

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