VirtualBox

source: vbox/trunk/src/VBox/GuestHost/OpenGL/spu_loader/spuload.c@ 79644

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

Additions,GuestHost/OpenGL,HostServices/SharedOpenGL: Get rid of the individual SPU shared libraries and merge them into the VBoxSharedCrOpenGL shared libraries on the host and VBoxOGL{,-x86} shared libraries for the guest additions, bugref:9435

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 14.1 KB
Line 
1/* Copyright (c) 2001, Stanford University
2 * All rights reserved
3 *
4 * See the file LICENSE.txt for information on redistributing this software.
5 */
6
7#include "cr_mem.h"
8#include "cr_string.h"
9#include "cr_dll.h"
10#include "cr_error.h"
11#include "cr_spu.h"
12
13
14#include <iprt/param.h>
15#include <iprt/string.h>
16#include <iprt/path.h>
17
18#include <stdio.h>
19
20#ifdef WINDOWS
21#ifdef VBOX_WDDM_WOW64
22#define DLL_SUFFIX "-x86.dll"
23#else
24#define DLL_SUFFIX ".dll"
25#endif
26#define DLL_PREFIX "VBoxOGL"
27#define snprintf _snprintf
28#elif defined(DARWIN)
29#define DLL_SUFFIX ".dylib"
30#define DLL_PREFIX "VBoxOGL"
31/*
32#define DLL_SUFFIX ".bundle"
33#define DLL_PREFIX ""
34*/
35#else
36#ifdef AIX
37#define DLL_SUFFIX ".o"
38#define DLL_PREFIX "VBoxOGL"
39#else
40#define DLL_SUFFIX ".so"
41#define DLL_PREFIX "VBoxOGL"
42#endif
43#endif
44
45extern void __buildDispatch( SPU *spu );
46
47static char *__findDLL( char *name, char *dir )
48{
49 static char path[8092];
50
51 if (!dir)
52 {
53#if defined(DARWIN)
54 char szSharedLibPath[8092];
55 int rc = RTPathAppPrivateArch (szSharedLibPath, sizeof(szSharedLibPath));
56 if (RT_SUCCESS(rc))
57 sprintf ( path, "%s/%s%sspu%s", szSharedLibPath, DLL_PREFIX, name, DLL_SUFFIX );
58 else
59#endif /* DARWIN */
60#ifdef VBOX
61 snprintf ( path, sizeof(path), "%s%sspu%s", DLL_PREFIX, name, DLL_SUFFIX );
62#else
63 sprintf ( path, "%s%sspu%s", DLL_PREFIX, name, DLL_SUFFIX );
64#endif
65 }
66 else
67 {
68#ifdef VBOX
69 snprintf ( path, sizeof(path), "%s/%s%sspu%s", dir, DLL_PREFIX, name, DLL_SUFFIX );
70#else
71 sprintf ( path, "%s/%s%sspu%s", dir, DLL_PREFIX, name, DLL_SUFFIX );
72#endif
73 }
74 return path;
75}
76
77/**
78 * Load a single SPU from disk and initialize it. Is there any reason
79 * to export this from the SPU loader library? */
80
81SPU * crSPULoad( SPU *child, int id, char *name, char *dir, void *server )
82{
83 SPU *the_spu;
84 char *path;
85 bool fNeedSuperSPU = false;
86
87 CRASSERT( name != NULL );
88
89 the_spu = (SPU*)crAlloc( sizeof( *the_spu ) );
90 /* ensure all fields are initially zero,
91 * NOTE: what actually MUST be zero at this point is the_spu->superSPU, otherwise
92 * crSPUUnloadChain in the failure branches below will misbehave */
93 crMemset(the_spu, 0, sizeof (*the_spu));
94 the_spu->id = id;
95 the_spu->privatePtr = NULL;
96 path = __findDLL( name, dir );
97 the_spu->dll = crDLLOpen( path, 0/*resolveGlobal*/ );
98 if (the_spu->dll == NULL)
99 {
100 crError("Couldn't load the DLL \"%s\"!\n", path);
101 crFree(the_spu);
102 return NULL;
103 }
104#if defined(DEBUG_misha) && defined(RT_OS_WINDOWS)
105 crDbgCmdSymLoadPrint(path, the_spu->dll->hinstLib);
106#endif
107 the_spu->entry_point =
108 (SPULoadFunction) crDLLGetNoError( the_spu->dll, SPU_ENTRY_POINT_NAME );
109 if (!the_spu->entry_point)
110 {
111 crError( "Couldn't load the SPU entry point \"%s\" from SPU \"%s\"!",
112 SPU_ENTRY_POINT_NAME, name );
113 crSPUUnloadChain(the_spu);
114 return NULL;
115 }
116
117 /* This basically calls the SPU's SPULoad() function */
118 if (!the_spu->entry_point( &(the_spu->name), &(the_spu->super_name),
119 &(the_spu->init), &(the_spu->self),
120 &(the_spu->cleanup),
121 &(the_spu->spu_flags)) )
122 {
123 crError( "I found the SPU \"%s\", but loading it failed!", name );
124 crSPUUnloadChain(the_spu);
125 return NULL;
126 }
127#ifdef IN_GUEST
128 if (crStrcmp(the_spu->name,"error"))
129 {
130 /* the default super/base class for an SPU is the error SPU */
131 if (the_spu->super_name == NULL)
132 {
133 the_spu->super_name = "error";
134 }
135 the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
136 fNeedSuperSPU = true;
137 }
138#else
139 if (crStrcmp(the_spu->name,"hosterror"))
140 {
141 /* the default super/base class for an SPU is the error SPU */
142 if (the_spu->super_name == NULL)
143 {
144 the_spu->super_name = "hosterror";
145 }
146 the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
147 fNeedSuperSPU = true;
148 }
149#endif
150 else
151 {
152 the_spu->superSPU = NULL;
153 }
154 if (fNeedSuperSPU && !the_spu->superSPU)
155 {
156 crError( "Unable to load super SPU \"%s\" of \"%s\"!", the_spu->super_name, name );
157 crSPUUnloadChain(the_spu);
158 return NULL;
159 }
160 crDebug("Initializing %s SPU", name);
161 the_spu->function_table = the_spu->init( id, child, the_spu, 0, 1 );
162 if (!the_spu->function_table) {
163 crDebug("Failed to init %s SPU", name);
164 crSPUUnloadChain(the_spu);
165 return NULL;
166 }
167 __buildDispatch( the_spu );
168 /*crDebug( "initializing dispatch table %p (for SPU %s)", (void*)&(the_spu->dispatch_table), name );*/
169 crSPUInitDispatchTable( &(the_spu->dispatch_table) );
170 /*crDebug( "Done initializing the dispatch table for SPU %s, calling the self function", name );*/
171
172 the_spu->dispatch_table.server = server;
173 the_spu->self( &(the_spu->dispatch_table) );
174 /*crDebug( "Done with the self function" );*/
175
176 return the_spu;
177}
178
179/**
180 * Load the entire chain of SPUs and initialize all of them.
181 * This function returns the first one in the chain.
182 */
183SPU *
184crSPULoadChain( int count, int *ids, char **names, char *dir, void *server )
185{
186 int i;
187 SPU *child_spu = NULL;
188 CRASSERT( count > 0 );
189
190 for (i = count-1 ; i >= 0 ; i--)
191 {
192 int spu_id = ids[i];
193 char *spu_name = names[i];
194 SPU *the_spu, *temp;
195
196 /* This call passes the previous version of spu, which is the SPU's
197 * "child" in this chain. */
198
199 the_spu = crSPULoad( child_spu, spu_id, spu_name, dir, server );
200 if (!the_spu) {
201 return NULL;
202 }
203
204 if (child_spu != NULL)
205 {
206 /* keep track of this so that people can pass functions through but
207 * still get updated when API's change on the fly. */
208 for (temp = the_spu ; temp ; temp = temp->superSPU )
209 {
210 struct _copy_list_node *node = (struct _copy_list_node *) crAlloc( sizeof( *node ) );
211 node->copy = &(temp->dispatch_table);
212 node->next = child_spu->dispatch_table.copyList;
213 child_spu->dispatch_table.copyList = node;
214 }
215 }
216 child_spu = the_spu;
217 }
218 return child_spu;
219}
220
221
222/**
223 * Returns the SPU registration record for the given name.
224 *
225 * @returns Pointer to the SPU registration record on success or NULL if not found.
226 * @param pszName The name to look for.
227 * @param papSpuReg Pointer to the NULL terminated array of builtin SPU registration record pointers.
228 */
229PCSPUREG crSPUGetRegFromName(const char *pszName, PCSPUREG *papSpuReg)
230{
231 while (*papSpuReg)
232 {
233 if (!RTStrCmp(pszName, (*papSpuReg)->pszName))
234 return *papSpuReg;
235 papSpuReg++;
236 }
237
238 return NULL;
239}
240
241
242/**
243 * Creates a SPU chain from the given SPU registration structure (VBox only).
244 *
245 * @returns Pointer to the SPU head in the chain on success.
246 * @param pSpuChild Pointer to the child SPU if any.
247 * @param iId ID to assign to the head SPU.
248 * @param pszName Name of the SPU to initialize.
249 * @param pvServer The server owning the SPU chain.
250 * @param papSpuReg Pointer to the NULL terminated array of builtin SPU registration record pointers.
251 */
252SPU * crSPUInitFromReg(SPU *pSpuChild, int iId, const char *pszName, void *pvServer, PCSPUREG *papSpuReg)
253{
254 SPU *pSpu;
255 bool fNeedSuperSPU = false;
256 PCSPUREG pSpuReg = crSPUGetRegFromName(pszName, papSpuReg);
257 AssertPtrReturn(pSpuReg, NULL);
258
259 pSpu = (SPU*)crAlloc(sizeof(*pSpu));
260 crMemset(pSpu, 0, sizeof (*pSpu));
261 pSpu->id = iId;
262 pSpu->privatePtr = NULL;
263
264 /* Init the SPU structure from the SPU registration record. */
265 pSpu->name = (char *)pSpuReg->pszName;
266 pSpu->super_name = (char *)pSpuReg->pszSuperName;
267 pSpu->init = pSpuReg->pfnInit;
268 pSpu->self = pSpuReg->pfnDispatch;
269 pSpu->cleanup = pSpuReg->pfnCleanup;
270 pSpu->spu_flags = pSpuReg->fFlags;
271
272#ifdef IN_GUEST
273 if (crStrcmp(pSpu->name,"error"))
274 {
275 /* the default super/base class for an SPU is the error SPU */
276 if (pSpu->super_name == NULL)
277 pSpu->super_name = "error";
278
279 pSpu->superSPU = crSPUInitFromReg(pSpuChild, iId, pSpu->super_name, pvServer, papSpuReg);
280 fNeedSuperSPU = true;
281 }
282#else
283 if (crStrcmp(pSpu->name,"hosterror"))
284 {
285 /* the default super/base class for an SPU is the error SPU */
286 if (pSpu->super_name == NULL)
287 pSpu->super_name = "hosterror";
288
289 pSpu->superSPU = crSPUInitFromReg(pSpuChild, iId, pSpu->super_name, pvServer, papSpuReg);
290 fNeedSuperSPU = true;
291 }
292#endif
293 else
294 pSpu->superSPU = NULL;
295
296 if (fNeedSuperSPU && !pSpu->superSPU)
297 {
298 crError( "Unable to load super SPU \"%s\" of \"%s\"!", pSpu->super_name, pSpuReg->pszName);
299 crSPUUnloadChain(pSpu);
300 return NULL;
301 }
302 crDebug("Initializing %s SPU", pSpuReg->pszName);
303 pSpu->function_table = pSpu->init(iId, pSpuChild, pSpu, 0, 1);
304 if (!pSpu->function_table) {
305 crDebug("Failed to init %s SPU", pSpuReg->pszName);
306 crSPUUnloadChain(pSpu);
307 return NULL;
308 }
309 __buildDispatch( pSpu );
310 /*crDebug( "initializing dispatch table %p (for SPU %s)", (void*)&(pSpu->dispatch_table), name );*/
311 crSPUInitDispatchTable( &(pSpu->dispatch_table) );
312 /*crDebug( "Done initializing the dispatch table for SPU %s, calling the self function", name );*/
313
314 pSpu->dispatch_table.server = pvServer;
315 pSpu->self( &(pSpu->dispatch_table) );
316 /*crDebug( "Done with the self function" );*/
317
318 return pSpu;
319}
320
321
322/**
323 * Initializes a give nchain of SPUs from the builtin SPU registration descriptors (VBox only).
324 *
325 * @returns Pointer to the Head SPU on success or NULL on failure.
326 * @param cSpus The number of SPUs to initialize.
327 * @param paIds Pointer to the array of IDs.
328 * @param papszNames Pointer to the array of SPU names to initalize.
329 * @param pvServer The server owning the SPU chain.
330 * @param papSpuReg Pointer to the NULL terminated array of builtin SPU registration record pointers.
331 */
332SPU *crSPUInitChainFromReg(int cSpus, int *paIds, const char * const *papszNames, void *pvServer, PCSPUREG *papSpuReg)
333{
334 int i = 0;
335 SPU *pSpuChild = NULL;
336 CRASSERT( cSpus > 0 );
337
338 for (i = cSpus - 1; i >= 0; i--)
339 {
340 int idSpu = paIds[i];
341 const char *pszSpuName = papszNames[i];
342
343 /*
344 * This call passes the previous version of spu, which is the SPU's
345 * "child" in this chain.
346 */
347 SPU *pSpu = crSPUInitFromReg( pSpuChild, idSpu, pszSpuName, pvServer, papSpuReg);
348 if (!pSpu)
349 return NULL; /** @todo Proper rollback. */
350
351 if (pSpuChild != NULL)
352 {
353 SPU *pTmp;
354
355 /* keep track of this so that people can pass functions through but
356 * still get updated when API's change on the fly. */
357 for (pTmp = pSpu ; pTmp ; pTmp = pTmp->superSPU )
358 {
359 struct _copy_list_node *node = (struct _copy_list_node *) crAlloc( sizeof( *node ) );
360 node->copy = &(pTmp->dispatch_table);
361 node->next = pSpuChild->dispatch_table.copyList;
362 pSpuChild->dispatch_table.copyList = node;
363 }
364 }
365 pSpuChild = pSpu;
366 }
367
368 return pSpuChild;
369}
370
371
372#if 00
373/* XXXX experimental code - not used at this time */
374/**
375 * Like crSPUChangeInterface(), but don't loop over all functions in
376 * the table to search for 'old_func'.
377 */
378void
379crSPUChangeFunction(SPUDispatchTable *table, unsigned int funcOffset,
380 void *newFunc)
381{
382 SPUGenericFunction *f = (SPUGenericFunction *) table + funcOffset;
383 struct _copy_list_node *temp;
384
385 CRASSERT(funcOffset < sizeof(*table) / sizeof(SPUGenericFunction));
386
387 printf("%s\n", __FUNCTION__);
388 if (table->mark == 1)
389 return;
390 table->mark = 1;
391 *f = newFunc;
392
393 /* update all copies of this table */
394#if 1
395 for (temp = table->copyList ; temp ; temp = temp->next)
396 {
397 crSPUChangeFunction( temp->copy, funcOffset, newFunc );
398 }
399#endif
400 if (table->copy_of != NULL)
401 {
402 crSPUChangeFunction( table->copy_of, funcOffset, newFunc );
403 }
404#if 0
405 for (temp = table->copyList ; temp ; temp = temp->next)
406 {
407 crSPUChangeFunction( temp->copy, funcOffset, newFunc );
408 }
409#endif
410 table->mark = 0;
411}
412#endif
413
414
415
416/**
417 * Call the cleanup() function for each SPU in a chain, close the SPU
418 * DLLs and free the SPU objects.
419 * \param headSPU pointer to the first SPU in the chain
420 */
421void
422crSPUUnloadChain(SPU *headSPU)
423{
424 SPU *the_spu = headSPU, *next_spu;
425
426 while (the_spu)
427 {
428 crDebug("Cleaning up SPU %s", the_spu->name);
429
430 if (the_spu->cleanup)
431 the_spu->cleanup();
432
433 next_spu = the_spu->superSPU;
434 if (the_spu->dll != NULL)
435 crDLLClose(the_spu->dll);
436 crFree(the_spu);
437 the_spu = next_spu;
438 }
439}
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