VirtualBox

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

Last change on this file since 74890 was 74890, checked in by vboxsync, 6 years ago

3D: Memory allocations fixed, bugref:9251. Merged changes r125768, r125779, r125780, r125812.

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