1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
|
/* Copyright (c) 2001, Stanford University
* All rights reserved
*
* See the file LICENSE.txt for information on redistributing this software.
*/
#include "cr_mem.h"
#include "cr_environment.h"
#include "cr_string.h"
#include "cr_dll.h"
#include "cr_error.h"
#include "cr_spu.h"
#include <iprt/param.h>
#include <iprt/string.h>
#include <iprt/path.h>
#include <stdio.h>
#ifdef WINDOWS
#ifdef VBOX_WDDM_WOW64
#define DLL_SUFFIX "-x86.dll"
#else
#define DLL_SUFFIX ".dll"
#endif
#define DLL_PREFIX "VBoxOGL"
#define snprintf _snprintf
#elif defined(DARWIN)
#define DLL_SUFFIX ".dylib"
#define DLL_PREFIX "VBoxOGL"
/*
#define DLL_SUFFIX ".bundle"
#define DLL_PREFIX ""
*/
#else
#ifdef AIX
#define DLL_SUFFIX ".o"
#define DLL_PREFIX "VBoxOGL"
#else
#define DLL_SUFFIX ".so"
#define DLL_PREFIX "VBoxOGL"
#endif
#endif
extern void __buildDispatch( SPU *spu );
static char *__findDLL( char *name, char *dir )
{
static char path[8092];
if (!dir)
{
#if defined(DARWIN)
char szSharedLibPath[8092];
int rc = RTPathAppPrivateArch (szSharedLibPath, sizeof(szSharedLibPath));
if (RT_SUCCESS(rc))
sprintf ( path, "%s/%s%sspu%s", szSharedLibPath, DLL_PREFIX, name, DLL_SUFFIX );
else
#endif /* DARWIN */
#ifdef VBOX
snprintf ( path, sizeof(path), "%s%sspu%s", DLL_PREFIX, name, DLL_SUFFIX );
#else
sprintf ( path, "%s%sspu%s", DLL_PREFIX, name, DLL_SUFFIX );
#endif
}
else
{
#ifdef VBOX
snprintf ( path, sizeof(path), "%s/%s%sspu%s", dir, DLL_PREFIX, name, DLL_SUFFIX );
#else
sprintf ( path, "%s/%s%sspu%s", dir, DLL_PREFIX, name, DLL_SUFFIX );
#endif
}
return path;
}
/**
* Load a single SPU from disk and initialize it. Is there any reason
* to export this from the SPU loader library? */
SPU * crSPULoad( SPU *child, int id, char *name, char *dir, void *server )
{
SPU *the_spu;
char *path;
CRASSERT( name != NULL );
the_spu = (SPU*)crAlloc( sizeof( *the_spu ) );
/* ensure all fields are initially zero,
* NOTE: what actually MUST be zero at this point is the_spu->superSPU, otherwise
* crSPUUnloadChain in the failure branches below will misbehave */
crMemset(the_spu, 0, sizeof (*the_spu));
the_spu->id = id;
the_spu->privatePtr = NULL;
path = __findDLL( name, dir );
the_spu->dll = crDLLOpen( path, 0/*resolveGlobal*/ );
the_spu->entry_point =
(SPULoadFunction) crDLLGetNoError( the_spu->dll, SPU_ENTRY_POINT_NAME );
if (!the_spu->entry_point)
{
crError( "Couldn't load the SPU entry point \"%s\" from SPU \"%s\"!",
SPU_ENTRY_POINT_NAME, name );
crSPUUnloadChain(the_spu);
return NULL;
}
/* This basically calls the SPU's SPULoad() function */
if (!the_spu->entry_point( &(the_spu->name), &(the_spu->super_name),
&(the_spu->init), &(the_spu->self),
&(the_spu->cleanup),
&(the_spu->options),
&(the_spu->spu_flags)) )
{
crError( "I found the SPU \"%s\", but loading it failed!", name );
crSPUUnloadChain(the_spu);
return NULL;
}
#ifdef IN_GUEST
if (crStrcmp(the_spu->name,"error"))
{
/* the default super/base class for an SPU is the error SPU */
if (the_spu->super_name == NULL)
{
the_spu->super_name = "error";
}
the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
}
#else
if (crStrcmp(the_spu->name,"hosterror"))
{
/* the default super/base class for an SPU is the error SPU */
if (the_spu->super_name == NULL)
{
the_spu->super_name = "hosterror";
}
the_spu->superSPU = crSPULoad( child, id, the_spu->super_name, dir, server );
}
#endif
else
{
the_spu->superSPU = NULL;
}
crDebug("Initializing %s SPU", name);
the_spu->function_table = the_spu->init( id, child, the_spu, 0, 1 );
if (!the_spu->function_table) {
crDebug("Failed to init %s SPU", name);
crSPUUnloadChain(the_spu);
return NULL;
}
__buildDispatch( the_spu );
/*crDebug( "initializing dispatch table %p (for SPU %s)", (void*)&(the_spu->dispatch_table), name );*/
crSPUInitDispatchTable( &(the_spu->dispatch_table) );
/*crDebug( "Done initializing the dispatch table for SPU %s, calling the self function", name );*/
the_spu->dispatch_table.server = server;
the_spu->self( &(the_spu->dispatch_table) );
/*crDebug( "Done with the self function" );*/
return the_spu;
}
/**
* Load the entire chain of SPUs and initialize all of them.
* This function returns the first one in the chain.
*/
SPU *
crSPULoadChain( int count, int *ids, char **names, char *dir, void *server )
{
int i;
SPU *child_spu = NULL;
CRASSERT( count > 0 );
for (i = count-1 ; i >= 0 ; i--)
{
int spu_id = ids[i];
char *spu_name = names[i];
SPU *the_spu, *temp;
/* This call passes the previous version of spu, which is the SPU's
* "child" in this chain. */
the_spu = crSPULoad( child_spu, spu_id, spu_name, dir, server );
if (!the_spu) {
return NULL;
}
if (child_spu != NULL)
{
/* keep track of this so that people can pass functions through but
* still get updated when API's change on the fly. */
for (temp = the_spu ; temp ; temp = temp->superSPU )
{
struct _copy_list_node *node = (struct _copy_list_node *) crAlloc( sizeof( *node ) );
node->copy = &(temp->dispatch_table);
node->next = child_spu->dispatch_table.copyList;
child_spu->dispatch_table.copyList = node;
}
}
child_spu = the_spu;
}
return child_spu;
}
#if 00
/* XXXX experimental code - not used at this time */
/**
* Like crSPUChangeInterface(), but don't loop over all functions in
* the table to search for 'old_func'.
*/
void
crSPUChangeFunction(SPUDispatchTable *table, unsigned int funcOffset,
void *newFunc)
{
SPUGenericFunction *f = (SPUGenericFunction *) table + funcOffset;
struct _copy_list_node *temp;
CRASSERT(funcOffset < sizeof(*table) / sizeof(SPUGenericFunction));
printf("%s\n", __FUNCTION__);
if (table->mark == 1)
return;
table->mark = 1;
*f = newFunc;
/* update all copies of this table */
#if 1
for (temp = table->copyList ; temp ; temp = temp->next)
{
crSPUChangeFunction( temp->copy, funcOffset, newFunc );
}
#endif
if (table->copy_of != NULL)
{
crSPUChangeFunction( table->copy_of, funcOffset, newFunc );
}
#if 0
for (temp = table->copyList ; temp ; temp = temp->next)
{
crSPUChangeFunction( temp->copy, funcOffset, newFunc );
}
#endif
table->mark = 0;
}
#endif
/**
* Call the cleanup() function for each SPU in a chain, close the SPU
* DLLs and free the SPU objects.
* \param headSPU pointer to the first SPU in the chain
*/
void
crSPUUnloadChain(SPU *headSPU)
{
SPU *the_spu = headSPU, *next_spu;
while (the_spu)
{
crDebug("Cleaning up SPU %s", the_spu->name);
if (the_spu->cleanup)
the_spu->cleanup();
next_spu = the_spu->superSPU;
crDLLClose(the_spu->dll);
crFree(the_spu);
the_spu = next_spu;
}
}
|