VirtualBox

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

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

crOpenGL: fix pointer conversion warning

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