VirtualBox

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

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

Host 3D: Expando SPU, DLM module.

  • DLM module reworked. Now it uses hardware way in order to execute Display List (software approach dropped);
  • Chromium/utils slightly extended with more helper functions needed for Expando/DLM;
  • More testing needed especially for glCallLists() and glListBase();
  • Expando/DLM code now enabed for Mac hosts.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.9 KB
Line 
1/* $Id: dlm_lists.c 56566 2015-06-20 08:10:59Z 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 * Privide 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 /* The references list has no allocated information; it's
61 * just a set of entries. So we don't need to free any
62 * information as each entry is deleted.
63 */
64 crFreeHashtable(pListInfo->references, NULL);
65
66 /* Free host OpenGL resources. */
67 if (dispatchTable)
68 dispatchTable->DeleteLists(pListInfo->hwid, 1);
69
70 crFree(pListInfo);
71 }
72}
73
74
75/**
76 * Generate host and guest IDs, setup IDs mapping between host and guest.
77 */
78GLuint DLM_APIENTRY crDLMGenLists(GLsizei range, SPUDispatchTable *dispatchTable)
79{
80 CRDLMContextState *listState = CURRENT_STATE();
81 GLuint idHostRangeStart = 0;
82 GLuint idGuestRangeStart = 0;
83
84 crDebug("DLM: GenLists(%d) (DLM=%p).", range, listState ? listState->dlm : 0);
85
86 if (listState)
87 {
88 idHostRangeStart = dispatchTable->GenLists(range);
89 if (idHostRangeStart > 0)
90 {
91 idGuestRangeStart = crHashtableAllocKeys(listState->dlm->displayLists, range);
92 if (idGuestRangeStart > 0)
93 {
94 GLuint i;
95 bool fSuccess = true;
96
97 /* Now have successfully generated IDs range for host and guest. Let's make IDs association. */
98 for (i = 0; i < (GLuint)range; i++)
99 {
100 DLMListInfo *pListInfo;
101
102 pListInfo = (DLMListInfo *)crCalloc(sizeof(DLMListInfo));
103 if (pListInfo)
104 {
105 crMemset(pListInfo, 0, sizeof(DLMListInfo));
106 pListInfo->hwid = idHostRangeStart + i;
107
108 /* Insert pre-initialized list data which contains IDs mapping into the hash. */
109 crHashtableReplace(listState->dlm->displayLists, idGuestRangeStart + i, pListInfo, NULL);
110 }
111 else
112 {
113 fSuccess = false;
114 break;
115 }
116 }
117
118 /* All structures allocated and initialized successfully. */
119 if (fSuccess)
120 return idGuestRangeStart;
121
122 /* Rollback some data was not allocated. */
123 crDLMDeleteLists(idGuestRangeStart, range, NULL /* we do DeleteLists() later in this routine */ );
124 }
125 else
126 crDebug("DLM: Can't allocate Display List IDs range for the guest.");
127
128 dispatchTable->DeleteLists(idHostRangeStart, range);
129 }
130 else
131 crDebug("DLM: Can't allocate Display List IDs range on the host side.");
132 }
133 else
134 crDebug("DLM: GenLists(%u) called with no current state.", range);
135
136 /* Can't reserve IDs range. */
137 return 0;
138}
139
140
141/**
142 * Release host and guest IDs, free memory resources.
143 */
144void DLM_APIENTRY crDLMDeleteLists(GLuint list, GLsizei range, SPUDispatchTable *dispatchTable)
145{
146 CRDLMContextState *listState = CURRENT_STATE();
147
148 crDebug("DLM: DeleteLists(%u, %d) (DLM=%p).", list, range, listState ? listState->dlm : 0);
149
150 if (listState)
151 {
152 if (range >= 0)
153 {
154 int i;
155
156 /* Free resources: host memory, host IDs and guest IDs. */
157 DLM_LOCK(listState->dlm)
158 for (i = 0; i < range; i++)
159 crHashtableDeleteEx(listState->dlm->displayLists, list + i, crdlmFreeDisplayListResourcesCb, dispatchTable);
160 DLM_UNLOCK(listState->dlm)
161 }
162 else
163 crDebug("DLM: DeleteLists(%u, %d) not allowed.", list, range);
164 }
165 else
166 crDebug("DLM: DeleteLists(%u, %d) called with no current state.", list, range);
167}
168
169
170/**
171 * Start recording a list.
172 */
173void DLM_APIENTRY
174crDLMNewList(GLuint list, GLenum mode, SPUDispatchTable *dispatchTable)
175{
176 DLMListInfo *listInfo;
177 CRDLMContextState *listState = CURRENT_STATE();
178
179 crDebug("DLM: NewList(%u, %u) (DLM=%p).", list, mode, listState ? listState->dlm : 0);
180
181 if (listState)
182 {
183 /* Valid list ID should be > 0. */
184 if (list > 0)
185 {
186 if (listState->currentListInfo == NULL)
187 {
188 listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
189 if (listInfo)
190 {
191 listInfo->first = listInfo->last = NULL;
192 listInfo->stateFirst = listInfo->stateLast = NULL;
193 listInfo->references = crAllocHashtable();
194 if (listInfo->references)
195 {
196 listInfo->numInstances = 0;
197 listInfo->listSent = GL_FALSE;
198 listInfo->bbox.xmin = FLT_MAX;
199 listInfo->bbox.xmax = -FLT_MAX;
200 listInfo->bbox.ymin = FLT_MAX;
201 listInfo->bbox.ymax = -FLT_MAX;
202 listInfo->bbox.zmin = FLT_MAX;
203 listInfo->bbox.zmax = -FLT_MAX;
204
205 listState->currentListInfo = listInfo;
206 listState->currentListIdentifier = list;
207 listState->currentListMode = mode;
208
209 dispatchTable->NewList(listInfo->hwid, mode);
210
211 crDebug("DLM: create new list with [guest, host] ID pair [%u, %u].", list, listInfo->hwid);
212
213 return;
214 }
215 else
216 crDebug("DLM: Could not allocate memory in NewList.");
217 }
218 else
219 crDebug("DLM: Requested Display List %u was not previously reserved with glGenLists().", list);
220 }
221 else
222 crDebug("DLM: NewList called with display list %u while display list %u was already open.", list, listState->currentListIdentifier);
223 }
224 else
225 crDebug("DLM: NewList called with a list identifier of 0.");
226 }
227 else
228 crDebug("DLM: NewList(%u, %u) called with no current state.\n", list, mode);
229}
230
231
232/**
233 * Stop recording a list.
234 */
235void DLM_APIENTRY crDLMEndList(SPUDispatchTable *dispatchTable)
236{
237 CRDLMContextState *listState = CURRENT_STATE();
238
239 crDebug("DLM: EndList() (DLM=%p).", listState ? listState->dlm : 0);
240
241 if (listState)
242 {
243 /* Check if list was ever started. */
244 if (listState->currentListInfo)
245 {
246 /* reset the current state to show the list had been ended */
247 listState->currentListIdentifier = 0;
248 listState->currentListInfo = NULL;
249 listState->currentListMode = GL_FALSE;
250
251 dispatchTable->EndList();
252 }
253 else
254 crDebug("DLM: glEndList() is assuming glNewList() was issued previously.");
255 }
256 else
257 crDebug("DLM: EndList called with no current state.");
258}
259
260
261/**
262 * Execute list on hardware and cach ethis call if we currently recording a list.
263 */
264void DLM_APIENTRY crDLMCallList(GLuint list, SPUDispatchTable *dispatchTable)
265{
266 CRDLMContextState *listState = CURRENT_STATE();
267
268 //crDebug("DLM: CallList(%u).", list);
269
270 if (listState)
271 {
272 DLMListInfo *listInfo;
273
274 /* Add to calls cache if we recording a list. */
275 if (listState->currentListInfo)
276 crDLMCompileCallList(list);
277
278 /* Find hwid for list. */
279 listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
280 if (listInfo)
281 dispatchTable->CallList(listInfo->hwid);
282 else
283 crDebug("DLM: CallList(%u) issued for non-existent list.", list);
284 }
285 else
286 crDebug("DLM: CallList(%u) called with no current state.", list);
287}
288
289
290/* Helper for crDLMCallLists().
291 * We need to extract list ID by index from array of given type and cast it to GLuint.
292 * Please replece it w/ something more elegant if better solution will be found!
293 */
294inline GLuint crDLMGetListByIndex(const GLvoid *aValues, GLsizei index, GLenum type)
295{
296 GLuint element = 0;
297
298 switch (type)
299 {
300#define CRDLM_LIST_BY_INDEX_HANDLE_TYPE(_type_name, _size_of_type) \
301 case _type_name: \
302 { \
303 crMemcpy((void *)&element, (void *)((void *)(aValues) + (index * (_size_of_type))) \
304 , (_size_of_type)); \
305 break; \
306 }
307
308 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_BYTE, sizeof(GLbyte));
309 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_UNSIGNED_BYTE, sizeof(GLubyte));
310 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_SHORT, sizeof(GLshort));
311 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_UNSIGNED_SHORT, sizeof(GLushort));
312 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_INT, sizeof(GLint));
313 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_UNSIGNED_INT, sizeof(GLuint));
314 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_FLOAT, sizeof(GLfloat));
315 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_2_BYTES, 2);
316 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_3_BYTES, 3);
317 CRDLM_LIST_BY_INDEX_HANDLE_TYPE(GL_4_BYTES, 4);
318
319 default:
320 crError("DLM: attempt to pass to crDLMCallLists() unknown type: %u.", index);
321
322#undef CRDLM_LIST_BY_INDEX_HANDLE_TYPE
323 }
324
325 return element;
326}
327
328/**
329 * Execute lists on hardware and cach ethis call if we currently recording a list.
330 */
331void DLM_APIENTRY crDLMCallLists(GLsizei n, GLenum type, const GLvoid *lists, SPUDispatchTable *dispatchTable)
332{
333 CRDLMContextState *listState = CURRENT_STATE();
334
335 crDebug("DLM: CallLists(%d, %u, %p).", n, type, lists);
336
337 if (listState)
338 {
339 GLsizei i;
340
341 /* Add to calls cache if we recording a list. */
342 if (listState->currentListInfo)
343 crDLMCompileCallLists(n, type, lists);
344
345 /* This is sad, but we need to translate guest IDs into host ones.
346 * Since spec does not promise that @param lists conain contiguous set of IDs,
347 * the only way to do that is to iterate over each guest ID and perform translation.
348 * This might have negative performance impact. */
349 for (i = 0; i < n; i++)
350 {
351 DLMListInfo *listInfo;
352 GLuint guest_id = crDLMGetListByIndex(lists, n, type);
353
354 if (guest_id > 0)
355 {
356 listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, guest_id);
357 if (listInfo)
358 dispatchTable->CallList(listInfo->hwid);
359 else
360 crDebug("DLM: CallLists(%d, %u, %p) was unabbe to resolve host ID for guest ID %u.", n, type, lists, guest_id);
361 }
362 else
363 crDebug("DLM: CallLists(%d, %u, %p) received bad array of IDs.", n, type, lists);
364 }
365 }
366 else
367 crDebug("DLM: CallLists(%d, %u, %p) called with no current state.", n, type, lists);
368}
369
370
371/**
372 * Set list base, remember its value and add call to the cache.
373 */
374void DLM_APIENTRY crDLMListBase(GLuint base, SPUDispatchTable *dispatchTable)
375{
376 CRDLMContextState *listState = CURRENT_STATE();
377
378 crDebug("DLM: ListBase(%u).", base);
379
380 if (listState)
381 {
382 listState->listBase = base;
383 crDLMCompileListBase(base);
384 dispatchTable->ListBase(base);
385 }
386 else
387 crDebug("DLM: ListBase(%u) called with no current state.", base);
388}
389
390
391/**
392 * Check if specified list ID belongs to valid Display List.
393 * Positive result is only returned in case both conditions below are satisfied:
394 *
395 * - given list found in DLM hash table (i.e., it was previously allocated
396 * with crDLMGenLists and still not released with crDLMDeleteLists);
397 *
398 * - list is valid on the host side.
399 */
400GLboolean DLM_APIENTRY crDLMIsList(GLuint list, SPUDispatchTable *dispatchTable)
401{
402 CRDLMContextState *listState = CURRENT_STATE();
403
404 crDebug("DLM: IsList(%u).", list);
405
406 if (listState)
407 {
408 if (list > 0)
409 {
410 DLMListInfo *listInfo = (DLMListInfo *)crHashtableSearch(listState->dlm->displayLists, list);
411 if (listInfo)
412 {
413 if (dispatchTable->IsList(listInfo->hwid))
414 return true;
415 else
416 crDebug("DLM: list [%u, %u] not found on the host side.", list, listInfo->hwid);
417 }
418 else
419 crDebug("DLM: list %u not found in guest cache.", list);
420 }
421 else
422 crDebug("DLM: IsList(%u) is not allowed.", list);
423 }
424 else
425 crDebug("DLM: IsList(%u) called with no current state.", list);
426
427 return false;
428}
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