VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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