VirtualBox

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

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

Host 3D: Display Lists: fix IDs convertion.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.2 KB
Line 
1/* $Id: dlm_lists.c 56948 2015-07-16 09:08:42Z 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 * and return resulting IDs as an array of elements of type GL_UNSIGNED_INT.
277 * It is based on TranslateListIDs() function from crserverlib/server_lists.c. */
278static bool
279crDLMConvertListIDs(CRDLMContextState *pListState, GLsizei n, GLenum type, const GLvoid *aGuest, GLuint *aHost)
280{
281#define CRDLM_HANDLE_CONVERSION_CASE(_type, _item) \
282 { \
283 const _type *src = (const _type *)aGuest; \
284 for (i = 0; i < n; i++) \
285 { \
286 GLuint idGuest = (GLuint)(_item) + pListState->listBase; \
287 pListInfo = (DLMListInfo *)crHashtableSearch(pListState->dlm->displayLists, idGuest); \
288 if (pListInfo) \
289 { \
290 aHost[i] = pListInfo->hwid - pListState->listBase; \
291 } \
292 else \
293 { \
294 crDebug("DLM: CallLists() cannot resolve host list ID for guest ID %u.", idGuest); \
295 fSuccess = false; \
296 break; \
297 } \
298 } \
299 }
300
301 GLsizei i;
302 DLMListInfo *pListInfo;
303 bool fSuccess = true;
304
305 switch (type)
306 {
307 case GL_UNSIGNED_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i]); break;
308 case GL_BYTE: CRDLM_HANDLE_CONVERSION_CASE(GLbyte, src[i]); break;
309 case GL_UNSIGNED_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLushort, src[i]); break;
310 case GL_SHORT: CRDLM_HANDLE_CONVERSION_CASE(GLshort, src[i]); break;
311 case GL_UNSIGNED_INT: CRDLM_HANDLE_CONVERSION_CASE(GLuint, src[i]); break;
312 case GL_INT: CRDLM_HANDLE_CONVERSION_CASE(GLint, src[i]); break;
313 case GL_FLOAT: CRDLM_HANDLE_CONVERSION_CASE(GLfloat, src[i]); break;
314
315 case GL_2_BYTES:
316 {
317 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 2 + 0] * 256 +
318 src[i * 2 + 1]);
319 break;
320 }
321
322 case GL_3_BYTES:
323 {
324 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 3 + 0] * 256 * 256 +
325 src[i * 3 + 1] * 256 +
326 src[i * 3 + 2]);
327 break;
328 }
329
330 case GL_4_BYTES:
331 {
332 CRDLM_HANDLE_CONVERSION_CASE(GLubyte, src[i * 4 + 0] * 256 * 256 * 256 +
333 src[i * 4 + 1] * 256 * 256 +
334 src[i * 4 + 2] * 256 +
335 src[i * 4 + 3]);
336 break;
337 }
338
339 default:
340 crWarning("DLM: attempt to pass to crDLMCallLists() an unknown type: 0x%x.", type);
341 }
342
343 return fSuccess;
344#undef CRDLM_HANDLE_CONVERSION_CASE
345}
346
347
348/**
349 * Execute lists on hardware and cache this call if we currently recording a list.
350 */
351void DLM_APIENTRY crDLMCallLists(GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable)
352{
353 CRDLMContextState *pListState = CURRENT_STATE();
354
355 crDebug("DLM: CallLists(%d, %u, %p).", n, type, lists);
356
357 if (pListState)
358 {
359 GLsizei i;
360 GLuint *aHostIDs;
361
362 /* Add to calls cache if we recording a list. */
363 if (pListState->currentListInfo)
364 crDLMCompileCallLists(n, type, lists);
365
366 aHostIDs = (GLuint *)crAlloc(n * sizeof(GLuint));
367 if (aHostIDs)
368 {
369 /* Convert IDs. Resulting array contains elements of type of GL_UNSIGNED_INT. */
370 if (crDLMConvertListIDs(pListState, n, type, lists, aHostIDs))
371 dispatchTable->CallLists(n, GL_UNSIGNED_INT, aHostIDs);
372 else
373 crDebug("DLM: CallLists() failed.");
374
375 crFree(aHostIDs);
376 }
377 else
378 crDebug("DLM: no memory on CallLists().");
379 }
380 else
381 crDebug("DLM: CallLists(%d, %u, %p) called with no current state.", n, type, lists);
382}
383
384
385/**
386 * Set list base, remember its value and add call to the cache.
387 */
388void DLM_APIENTRY crDLMListBase(GLuint base, SPUDispatchTable *dispatchTable)
389{
390 CRDLMContextState *pListState = CURRENT_STATE();
391
392 crDebug("DLM: ListBase(%u).", base);
393
394 if (pListState)
395 {
396 pListState->listBase = base;
397
398 /* Only add to cache if we are currently recording a list. */
399 /* TODO: Do we really need to chache it? */
400 if (pListState->currentListInfo)
401 crDLMCompileListBase(base);
402
403 dispatchTable->ListBase(base);
404 }
405 else
406 crDebug("DLM: ListBase(%u) called with no current state.", base);
407}
408
409
410/**
411 * Check if specified list ID belongs to valid Display List.
412 * Positive result is only returned in case both conditions below are satisfied:
413 *
414 * - given list found in DLM hash table (i.e., it was previously allocated
415 * with crDLMGenLists and still not released with crDLMDeleteLists);
416 *
417 * - list is valid on the host side.
418 */
419GLboolean DLM_APIENTRY crDLMIsList(GLuint list, SPUDispatchTable *dispatchTable)
420{
421 CRDLMContextState *listState = CURRENT_STATE();
422
423 crDebug("DLM: IsList(%u).", list);
424
425 if (listState)
426 {
427 if (list > 0)
428 {
429 DLMListInfo *listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
430 if (listInfo)
431 {
432 if (dispatchTable->IsList(listInfo->hwid))
433 return true;
434 else
435 crDebug("DLM: list [%u, %u] not found on the host side.", list, listInfo->hwid);
436 }
437 else
438 crDebug("DLM: list %u not found in guest cache.", list);
439 }
440 else
441 crDebug("DLM: IsList(%u) is not allowed.", list);
442 }
443 else
444 crDebug("DLM: IsList(%u) called with no current state.", list);
445
446 return false;
447}
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