VirtualBox

source: vbox/trunk/src/VBox/Additions/common/crOpenGL/fakedri_drv.c@ 19420

Last change on this file since 19420 was 18975, checked in by vboxsync, 15 years ago

crOpenGL: fix compiz to run on ubuntu64 without SKIP_CHECKS=yes (#3841)

File size: 15.3 KB
Line 
1/* $Id$ */
2
3/** @file
4 * VBox OpenGL DRI driver functions
5 */
6
7/*
8 * Copyright (C) 2009 Sun Microsystems, Inc.
9 *
10 * Sun Microsystems, Inc. confidential
11 * All rights reserved
12 */
13
14#define _GNU_SOURCE 1
15
16#include "cr_error.h"
17#include "cr_gl.h"
18#include "cr_mem.h"
19#include "stub.h"
20#include "fakedri_drv.h"
21#include "dri_glx.h"
22#include "iprt/mem.h"
23#include "iprt/err.h"
24#include <dlfcn.h>
25#include <elf.h>
26#include <unistd.h>
27#include "xf86.h"
28
29#define VBOX_NO_MESA_PATCH_REPORTS
30
31//#define DEBUG_DRI_CALLS
32
33//@todo this could be different...
34#ifdef RT_ARCH_AMD64
35# define DRI_DEFAULT_DRIVER_DIR "/usr/lib64/dri:/usr/lib/dri"
36# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
37#else
38# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri"
39# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
40#endif
41
42#ifdef DEBUG_DRI_CALLS
43 #define SWDRI_SHOWNAME(pext, func) \
44 crDebug("SWDRI: sc %s->%s", #pext, #func)
45#else
46 #define SWDRI_SHOWNAME(pext, func)
47#endif
48
49#define SWDRI_SAFECALL(pext, func, ...) \
50 SWDRI_SHOWNAME(pext, func); \
51 if (pext && pext->func){ \
52 (*pext->func)(__VA_ARGS__); \
53 } else { \
54 crDebug("swcore_call NULL for "#func); \
55 }
56
57#define SWDRI_SAFERET(pext, func, ...) \
58 SWDRI_SHOWNAME(pext, func); \
59 if (pext && pext->func){ \
60 return (*pext->func)(__VA_ARGS__); \
61 } else { \
62 crDebug("swcore_call NULL for "#func); \
63 return 0; \
64 }
65
66#define SWDRI_SAFERET_CORE(func, ...) SWDRI_SAFERET(gpSwDriCoreExternsion, func, __VA_ARGS__)
67#define SWDRI_SAFECALL_CORE(func, ...) SWDRI_SAFECALL(gpSwDriCoreExternsion, func, __VA_ARGS__)
68#define SWDRI_SAFERET_SWRAST(func, ...) SWDRI_SAFERET(gpSwDriSwrastExtension, func, __VA_ARGS__)
69#define SWDRI_SAFECALL_SWRAST(func, ...) SWDRI_SAFECALL(gpSwDriSwrastExtension, func, __VA_ARGS__)
70
71#ifndef PAGESIZE
72#define PAGESIZE 4096
73#endif
74
75static struct _glapi_table vbox_glapi_table;
76fakedri_glxapi_table glxim;
77
78static const __DRIextension **gppSwDriExternsion = NULL;
79static const __DRIcoreExtension *gpSwDriCoreExternsion = NULL;
80static const __DRIswrastExtension *gpSwDriSwrastExtension = NULL;
81
82extern const __DRIextension * __driDriverExtensions[];
83
84#define GLAPI_ENTRY(Func) pGLTable->Func = cr_gl##Func;
85static void
86vboxFillMesaGLAPITable(struct _glapi_table *pGLTable)
87{
88 #include "fakedri_glfuncsList.h"
89
90 pGLTable->SampleMaskSGIS = cr_glSampleMaskEXT;
91 pGLTable->SamplePatternSGIS = cr_glSamplePatternEXT;
92 pGLTable->WindowPos2dMESA = cr_glWindowPos2d;
93 pGLTable->WindowPos2dvMESA = cr_glWindowPos2dv;
94 pGLTable->WindowPos2fMESA = cr_glWindowPos2f;
95 pGLTable->WindowPos2fvMESA = cr_glWindowPos2fv;
96 pGLTable->WindowPos2iMESA = cr_glWindowPos2i;
97 pGLTable->WindowPos2ivMESA = cr_glWindowPos2iv;
98 pGLTable->WindowPos2sMESA = cr_glWindowPos2s;
99 pGLTable->WindowPos2svMESA = cr_glWindowPos2sv;
100 pGLTable->WindowPos3dMESA = cr_glWindowPos3d;
101 pGLTable->WindowPos3dvMESA = cr_glWindowPos3dv;
102 pGLTable->WindowPos3fMESA = cr_glWindowPos3f;
103 pGLTable->WindowPos3fvMESA = cr_glWindowPos3fv;
104 pGLTable->WindowPos3iMESA = cr_glWindowPos3i;
105 pGLTable->WindowPos3ivMESA = cr_glWindowPos3iv;
106 pGLTable->WindowPos3sMESA = cr_glWindowPos3s;
107 pGLTable->WindowPos3svMESA = cr_glWindowPos3sv;
108};
109#undef GLAPI_ENTRY
110
111#define GLXAPI_ENTRY(Func) pGLXTable->Func = VBOXGLXTAG(glX##Func);
112static void
113vboxFillGLXAPITable(fakedri_glxapi_table *pGLXTable)
114{
115 #include "fakedri_glxfuncsList.h"
116}
117#undef GLXAPI_ENTRY
118
119static void
120vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
121{
122 Dl_info dlip;
123 Elf32_Sym* sym=0;
124 int rv;
125 void *alPatch;
126 void *pMesaEntry;
127
128#ifndef VBOX_NO_MESA_PATCH_REPORTS
129 crDebug("vboxPatchMesaExport: %s", psFuncName);
130#endif
131
132 pMesaEntry = dlsym(RTLD_DEFAULT, psFuncName);
133
134 if (!pMesaEntry)
135 {
136 crDebug("%s not defined in current scope, are we being loaded by mesa's libGL.so?", psFuncName);
137 return;
138 }
139
140 rv = dladdr1(pMesaEntry, &dlip, (void**)&sym, RTLD_DL_SYMENT);
141 if (!rv || !sym)
142 {
143 crError("Failed to get size for %p(%s)", pMesaEntry, psFuncName);
144 return;
145 }
146
147#if VBOX_OGL_GLX_USE_CSTUBS
148 {
149 Dl_info dlip1;
150 Elf32_Sym* sym1=0;
151 int rv;
152
153 rv = dladdr1(pStart, &dlip1, (void**)&sym1, RTLD_DL_SYMENT);
154 if (!rv || !sym)
155 {
156 crError("Failed to get size for %p", pStart);
157 return;
158 }
159
160 pEnd = pStart + sym1->st_size;
161 crDebug("VBox Entry: %p, start: %p(%s:%s), size: %i", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
162 }
163#endif
164
165#ifndef VBOX_NO_MESA_PATCH_REPORTS
166 crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %i", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
167 crDebug("Vbox code: start: %p, end %p, size: %i", pStart, pEnd, pEnd-pStart);
168#endif
169
170 if (sym->st_size<(pEnd-pStart))
171 {
172 crDebug("Can't patch size too small.(%s)", psFuncName);
173 return;
174 }
175
176 /* Get aligned start adress we're going to patch*/
177 alPatch = (void*) ((uintptr_t)dlip.dli_saddr & ~(uintptr_t)(PAGESIZE-1));
178
179#ifndef VBOX_NO_MESA_PATCH_REPORTS
180 crDebug("MProtecting: %p, %i", alPatch, dlip.dli_saddr-alPatch+pEnd-pStart);
181#endif
182
183 /* Get write access to mesa functions */
184 rv = RTMemProtect(alPatch, dlip.dli_saddr-alPatch+pEnd-pStart,
185 RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
186 if (RT_FAILURE(rv))
187 {
188 crError("mprotect failed with %x (%s)", rv, psFuncName);
189 }
190
191#ifndef VBOX_NO_MESA_PATCH_REPORTS
192 crDebug("Writing %i bytes to %p from %p", pEnd-pStart, dlip.dli_saddr, pStart);
193#endif
194
195 crMemcpy(dlip.dli_saddr, pStart, pEnd-pStart);
196
197 /*@todo Restore the protection, probably have to check what was it before us...*/
198 rv = RTMemProtect(alPatch, dlip.dli_saddr-alPatch+pEnd-pStart,
199 RTMEM_PROT_READ|RTMEM_PROT_EXEC);
200 if (RT_FAILURE(rv))
201 {
202 crError("mprotect2 failed with %x (%s)", rv, psFuncName);
203 }
204}
205
206#ifdef VBOX_OGL_GLX_USE_CSTUBS
207static void
208# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, NULL);
209vboxPatchMesaExports()
210#else
211static void
212# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, &vbox_glX##Func##_EndProc);
213vboxPatchMesaExports()
214#endif
215{
216 crDebug("Patching mesa glx entries");
217 #include "fakedri_glxfuncsList.h"
218}
219#undef GLXAPI_ENTRY
220
221bool vbox_load_sw_dri()
222{
223 const char *libPaths, *p, *next;;
224 char realDriverName[200];
225 void *handle;
226 int len, i;
227
228 /*code from Mesa-7.2/src/glx/x11/dri_common.c:driOpenDriver*/
229
230 libPaths = NULL;
231 if (geteuid() == getuid()) {
232 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
233 libPaths = getenv("LIBGL_DRIVERS_PATH");
234 if (!libPaths)
235 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
236 }
237 if (libPaths == NULL)
238 libPaths = DRI_DEFAULT_DRIVER_DIR;
239
240 handle = NULL;
241 for (p = libPaths; *p; p = next)
242 {
243 next = strchr(p, ':');
244 if (next == NULL)
245 {
246 len = strlen(p);
247 next = p + len;
248 }
249 else
250 {
251 len = next - p;
252 next++;
253 }
254
255 snprintf(realDriverName, sizeof realDriverName, "%.*s/%s_dri.so", len, p, "swrast");
256 crDebug("trying %s", realDriverName);
257 handle = dlopen(realDriverName, RTLD_NOW | RTLD_LOCAL);
258 if (handle) break;
259 }
260
261 /*end code*/
262
263 if (handle) gppSwDriExternsion = dlsym(handle, "__driDriverExtensions");
264
265 if (!gppSwDriExternsion)
266 {
267 crDebug("%s doesn't export __driDriverExtensions", realDriverName);
268 return false;
269 }
270 crDebug("loaded %s", realDriverName);
271
272 for (i = 0; gppSwDriExternsion[i]; i++)
273 {
274 if (strcmp(gppSwDriExternsion[i]->name, __DRI_CORE) == 0)
275 gpSwDriCoreExternsion = (__DRIcoreExtension *) gppSwDriExternsion[i];
276 if (strcmp(gppSwDriExternsion[i]->name, __DRI_SWRAST) == 0)
277 gpSwDriSwrastExtension = (__DRIswrastExtension *) gppSwDriExternsion[i];
278 }
279
280 return gpSwDriCoreExternsion && gpSwDriSwrastExtension;
281}
282
283void __attribute__ ((constructor)) vbox_install_into_mesa(void)
284{
285 if (!stubInit())
286 {
287 crDebug("vboxdriInitScreen: stubInit failed");
288 return;
289 }
290
291 {
292 void (*pxf86Msg)(MessageType type, const char *format, ...) _printf_attribute(2,3);
293
294 pxf86Msg = dlsym(RTLD_DEFAULT, "xf86Msg");
295 if (pxf86Msg)
296 {
297 pxf86Msg(X_INFO, "Next line is added to allow vboxvideo_drv.so to appear as whitelisted driver\n");
298 pxf86Msg(X_INFO, "The file referenced, is *NOT* loaded\n");
299 pxf86Msg(X_INFO, "Loading %s/ati_drv.so\n", DRI_XORG_DRV_DIR);
300
301 /* we're failing to proxy software dri driver calls for certain xservers, so just make sure we're unloaded for now */
302 __driDriverExtensions[0] = NULL;
303 return;
304 }
305 }
306
307 /* Load swrast_dri.so to proxy dri related calls there. */
308 if (!vbox_load_sw_dri())
309 {
310 crDebug("vboxdriInitScreen: vbox_load_sw_dri failed...going to fail badly");
311 return;
312 }
313
314 /* Handle gl api.
315 * In the end application call would look like this:
316 * app call glFoo->(mesa asm dispatch stub)->cr_glFoo(vbox asm dispatch stub)->SPU Foo function(packspuFoo or alike)
317 * Note, we don't need to install extension functions via _glapi_add_dispatch, because we'd override glXGetProcAddress.
318 */
319 /* We don't support all mesa's functions. Initialize our table to mesa dispatch first*/
320 crMemcpy(&vbox_glapi_table, _glapi_get_dispatch(), sizeof(struct _glapi_table));
321 /* Now install our assembly dispatch entries into table */
322 vboxFillMesaGLAPITable(&vbox_glapi_table);
323 /* Install our dispatch table into mesa */
324 _glapi_set_dispatch(&vbox_glapi_table);
325
326 /* Handle glx api.
327 * In the end application call would look like this:
328 * app call glxFoo->(mesa asm dispatch stub patched with vbox_glXFoo:jmp glxim[Foo's index])->VBOXGLXTAG(glxFoo)
329 */
330 /* Fill structure used by our assembly stubs */
331 vboxFillGLXAPITable(&glxim);
332 /* Now patch functions exported by libGL.so */
333 vboxPatchMesaExports();
334}
335
336/*
337 * @todo we're missing first glx related call from the client application.
338 * Luckily, this doesn't add much problems, except for some cases.
339 */
340
341/* __DRIcoreExtension */
342
343static __DRIscreen *
344vboxdriCreateNewScreen(int screen, int fd, unsigned int sarea_handle,
345 const __DRIextension **extensions, const __DRIconfig ***driverConfigs,
346 void *loaderPrivate)
347{
348 (void) fd;
349 (void) sarea_handle;
350 SWDRI_SAFERET_SWRAST(createNewScreen, screen, extensions, driverConfigs, loaderPrivate);
351}
352
353static void
354vboxdriDestroyScreen(__DRIscreen *screen)
355{
356 SWDRI_SAFECALL_CORE(destroyScreen, screen);
357}
358
359static const __DRIextension **
360vboxdriGetExtensions(__DRIscreen *screen)
361{
362 SWDRI_SAFERET_CORE(getExtensions, screen);
363}
364
365static int
366vboxdriGetConfigAttrib(const __DRIconfig *config,
367 unsigned int attrib,
368 unsigned int *value)
369{
370 SWDRI_SAFERET_CORE(getConfigAttrib, config, attrib, value);
371}
372
373static int
374vboxdriIndexConfigAttrib(const __DRIconfig *config, int index,
375 unsigned int *attrib, unsigned int *value)
376{
377 SWDRI_SAFERET_CORE(indexConfigAttrib, config, index, attrib, value);
378}
379
380static __DRIdrawable *
381vboxdriCreateNewDrawable(__DRIscreen *screen,
382 const __DRIconfig *config,
383 unsigned int drawable_id,
384 unsigned int head,
385 void *loaderPrivate)
386{
387 (void) drawable_id;
388 (void) head;
389 SWDRI_SAFERET_SWRAST(createNewDrawable, screen, config, loaderPrivate);
390}
391
392static void
393vboxdriDestroyDrawable(__DRIdrawable *drawable)
394{
395 SWDRI_SAFECALL_CORE(destroyDrawable, drawable);
396}
397
398static void
399vboxdriSwapBuffers(__DRIdrawable *drawable)
400{
401 SWDRI_SAFECALL_CORE(swapBuffers, drawable);
402}
403
404static __DRIcontext *
405vboxdriCreateNewContext(__DRIscreen *screen,
406 const __DRIconfig *config,
407 __DRIcontext *shared,
408 void *loaderPrivate)
409{
410 SWDRI_SAFERET_CORE(createNewContext, screen, config, shared, loaderPrivate);
411}
412
413static int
414vboxdriCopyContext(__DRIcontext *dest,
415 __DRIcontext *src,
416 unsigned long mask)
417{
418 SWDRI_SAFERET_CORE(copyContext, dest, src, mask);
419}
420
421static void
422vboxdriDestroyContext(__DRIcontext *context)
423{
424 SWDRI_SAFECALL_CORE(destroyContext, context);
425}
426
427static int
428vboxdriBindContext(__DRIcontext *ctx,
429 __DRIdrawable *pdraw,
430 __DRIdrawable *pread)
431{
432 SWDRI_SAFERET_CORE(bindContext, ctx, pdraw, pread);
433}
434
435static int
436vboxdriUnbindContext(__DRIcontext *ctx)
437{
438 SWDRI_SAFERET_CORE(unbindContext, ctx)
439}
440
441/* __DRIlegacyExtension */
442
443static __DRIscreen *
444vboxdriCreateNewScreen_Legacy(int scrn,
445 const __DRIversion *ddx_version,
446 const __DRIversion *dri_version,
447 const __DRIversion *drm_version,
448 const __DRIframebuffer *frame_buffer,
449 drmAddress pSAREA, int fd,
450 const __DRIextension **extensions,
451 const __DRIconfig ***driver_modes,
452 void *loaderPrivate)
453{
454 (void) ddx_version;
455 (void) dri_version;
456 (void) frame_buffer;
457 (void) pSAREA;
458 (void) fd;
459 SWDRI_SAFERET_SWRAST(createNewScreen, scrn, extensions, driver_modes, loaderPrivate);
460}
461
462static __DRIdrawable *
463vboxdriCreateNewDrawable_Legacy(__DRIscreen *psp, const __DRIconfig *config,
464 drm_drawable_t hwDrawable, int renderType,
465 const int *attrs, void *data)
466{
467 (void) hwDrawable;
468 (void) renderType;
469 (void) attrs;
470 (void) data;
471 SWDRI_SAFERET_SWRAST(createNewDrawable, psp, config, data);
472}
473
474static __DRIcontext *
475vboxdriCreateNewContext_Legacy(__DRIscreen *psp, const __DRIconfig *config,
476 int render_type, __DRIcontext *shared,
477 drm_context_t hwContext, void *data)
478{
479 (void) render_type;
480 (void) hwContext;
481 return vboxdriCreateNewContext(psp, config, shared, data);
482}
483
484
485static const __DRIlegacyExtension vboxdriLegacyExtension = {
486 { __DRI_LEGACY, __DRI_LEGACY_VERSION },
487 vboxdriCreateNewScreen_Legacy,
488 vboxdriCreateNewDrawable_Legacy,
489 vboxdriCreateNewContext_Legacy
490};
491
492static const __DRIcoreExtension vboxdriCoreExtension = {
493 { __DRI_CORE, __DRI_CORE_VERSION },
494 vboxdriCreateNewScreen, /* driCreateNewScreen */
495 vboxdriDestroyScreen,
496 vboxdriGetExtensions,
497 vboxdriGetConfigAttrib,
498 vboxdriIndexConfigAttrib,
499 vboxdriCreateNewDrawable, /* driCreateNewDrawable */
500 vboxdriDestroyDrawable,
501 vboxdriSwapBuffers,
502 vboxdriCreateNewContext,
503 vboxdriCopyContext,
504 vboxdriDestroyContext,
505 vboxdriBindContext,
506 vboxdriUnbindContext
507};
508
509/* This structure is used by dri_util from mesa, don't rename it! */
510DECLEXPORT(const __DRIextension *) __driDriverExtensions[] = {
511 &vboxdriLegacyExtension.base,
512 &vboxdriCoreExtension.base,
513 NULL
514};
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