VirtualBox

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

Last change on this file since 77819 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.7 KB
Line 
1/* $Id: fakedri_drv.c 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBox OpenGL DRI driver functions
4 */
5
6/*
7 * Copyright (C) 2009-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define _GNU_SOURCE 1
19
20#include "cr_error.h"
21#include "cr_gl.h"
22#include "cr_mem.h"
23#include "stub.h"
24#include "fakedri_drv.h"
25#include "dri_glx.h"
26#include "iprt/mem.h"
27#include <iprt/errcore.h>
28#include <dlfcn.h>
29#include <elf.h>
30#include <unistd.h>
31
32#if defined(RT_OS_FREEBSD)
33#include <sys/param.h>
34#include <fcntl.h>
35#include <gelf.h>
36#include <libelf.h>
37#include <string.h>
38#endif
39
40/** X server message type definitions. */
41typedef enum {
42 X_PROBED, /* Value was probed */
43 X_CONFIG, /* Value was given in the config file */
44 X_DEFAULT, /* Value is a default */
45 X_CMDLINE, /* Value was given on the command line */
46 X_NOTICE, /* Notice */
47 X_ERROR, /* Error message */
48 X_WARNING, /* Warning message */
49 X_INFO, /* Informational message */
50 X_NONE, /* No prefix */
51 X_NOT_IMPLEMENTED, /* Not implemented */
52 X_UNKNOWN = -1 /* unknown -- this must always be last */
53} MessageType;
54
55#define VBOX_NO_MESA_PATCH_REPORTS
56
57//#define DEBUG_DRI_CALLS
58
59/// @todo this could be different...
60#ifdef RT_ARCH_AMD64
61# ifdef RT_OS_FREEBSD
62# define DRI_DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
63# define DRI_XORG_DRV_DIR "/usr/local/lib/xorg/modules/drivers/"
64# else
65# define DRI_DEFAULT_DRIVER_DIR "/usr/lib64/dri:/usr/lib/dri:/usr/lib/x86_64-linux-gnu/dri:/usr/lib/xorg/modules/dri"
66# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
67# endif
68#else
69# ifdef RT_OS_FREEBSD
70# define DRI_DEFAULT_DRIVER_DIR "/usr/local/lib/dri"
71# define DRI_XORG_DRV_DIR "/usr/local/lib/xorg/modules/drivers/"
72# else
73# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri:/usr/lib/i386-linux-gnu/dri:/usr/lib/xorg/modules/dri"
74# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
75# endif
76#endif
77
78#ifdef DEBUG_DRI_CALLS
79 #define SWDRI_SHOWNAME(pext, func) \
80 crDebug("SWDRI: sc %s->%s", #pext, #func)
81#else
82 #define SWDRI_SHOWNAME(pext, func)
83#endif
84
85#define SWDRI_SAFECALL(pext, func, ...) \
86 SWDRI_SHOWNAME(pext, func); \
87 if (pext && pext->func){ \
88 (*pext->func)(__VA_ARGS__); \
89 } else { \
90 crDebug("swcore_call NULL for "#func); \
91 }
92
93#define SWDRI_SAFERET(pext, func, ...) \
94 SWDRI_SHOWNAME(pext, func); \
95 if (pext && pext->func){ \
96 return (*pext->func)(__VA_ARGS__); \
97 } else { \
98 crDebug("swcore_call NULL for "#func); \
99 return 0; \
100 }
101
102#define SWDRI_SAFERET_CORE(func, ...) SWDRI_SAFERET(gpSwDriCoreExternsion, func, __VA_ARGS__)
103#define SWDRI_SAFECALL_CORE(func, ...) SWDRI_SAFECALL(gpSwDriCoreExternsion, func, __VA_ARGS__)
104#define SWDRI_SAFERET_SWRAST(func, ...) SWDRI_SAFERET(gpSwDriSwrastExtension, func, __VA_ARGS__)
105#define SWDRI_SAFECALL_SWRAST(func, ...) SWDRI_SAFECALL(gpSwDriSwrastExtension, func, __VA_ARGS__)
106
107#ifndef PAGESIZE
108#define PAGESIZE 4096
109#endif
110
111#ifdef RT_ARCH_AMD64
112# define DRI_ELFSYM Elf64_Sym
113#else
114# define DRI_ELFSYM Elf32_Sym
115#endif
116
117#ifdef RT_ARCH_AMD64
118typedef struct _FAKEDRI_PatchNode
119{
120 const char* psFuncName;
121 void *pDstStart, *pDstEnd;
122 const void *pSrcStart, *pSrcEnd;
123
124 struct _FAKEDRI_PatchNode *pNext;
125} FAKEDRI_PatchNode;
126static FAKEDRI_PatchNode *g_pFreeList=NULL, *g_pRepatchList=NULL;
127#endif
128
129static struct _glapi_table* vbox_glapi_table = NULL;
130fakedri_glxapi_table glxim;
131
132static const __DRIextension **gppSwDriExternsion = NULL;
133static const __DRIcoreExtension *gpSwDriCoreExternsion = NULL;
134static const __DRIswrastExtension *gpSwDriSwrastExtension = NULL;
135
136extern const __DRIextension * __driDriverExtensions[];
137
138#define VBOX_SET_MESA_FUNC(table, name, func) \
139 if (_glapi_get_proc_offset(name)>=0) SET_by_offset(table, _glapi_get_proc_offset(name), func); \
140 else crWarning("%s not found in mesa table", name)
141
142#define GLAPI_ENTRY(Func) VBOX_SET_MESA_FUNC(vbox_glapi_table, "gl"#Func, cr_gl##Func);
143
144static void
145vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd);
146
147static void
148vboxPatchMesaGLAPITable()
149{
150 void *pGLTable;
151
152 pGLTable = (void *)_glapi_get_dispatch();
153 vbox_glapi_table = crAlloc(_glapi_get_dispatch_table_size() * sizeof (void *));
154 if (!vbox_glapi_table)
155 {
156 crError("Not enough memory to allocate dispatch table");
157 }
158 crMemcpy(vbox_glapi_table, pGLTable, _glapi_get_dispatch_table_size() * sizeof (void *));
159
160 #include "fakedri_glfuncsList.h"
161
162 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glBlendEquationSeparateEXT", cr_glBlendEquationSeparate);
163 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glSampleMaskSGIS", cr_glSampleMaskEXT);
164 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glSamplePatternSGIS", cr_glSamplePatternEXT);
165 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2dMESA", cr_glWindowPos2d);
166 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2dvMESA", cr_glWindowPos2dv);
167 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2fMESA", cr_glWindowPos2f);
168 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2fvMESA", cr_glWindowPos2fv);
169 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2iMESA", cr_glWindowPos2i);
170 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2ivMESA", cr_glWindowPos2iv);
171 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2sMESA", cr_glWindowPos2s);
172 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2svMESA", cr_glWindowPos2sv);
173 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3dMESA", cr_glWindowPos3d);
174 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3dvMESA", cr_glWindowPos3dv);
175 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3fMESA", cr_glWindowPos3f);
176 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3fvMESA", cr_glWindowPos3fv);
177 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3iMESA", cr_glWindowPos3i);
178 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3ivMESA", cr_glWindowPos3iv);
179 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3sMESA", cr_glWindowPos3s);
180 VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3svMESA", cr_glWindowPos3sv);
181
182 _glapi_set_dispatch(vbox_glapi_table);
183};
184#undef GLAPI_ENTRY
185
186#define GLXAPI_ENTRY(Func) pGLXTable->Func = VBOXGLXTAG(glX##Func);
187static void
188vboxFillGLXAPITable(fakedri_glxapi_table *pGLXTable)
189{
190 #include "fakedri_glxfuncsList.h"
191}
192#undef GLXAPI_ENTRY
193
194static void
195vboxApplyPatch(const char* psFuncName, void *pDst, const void *pSrc, unsigned long size)
196{
197 void *alPatch;
198 int rv;
199
200 /* Get aligned start address we're going to patch*/
201 alPatch = (void*) ((uintptr_t)pDst & ~(uintptr_t)(PAGESIZE-1));
202
203#ifndef VBOX_NO_MESA_PATCH_REPORTS
204 crDebug("MProtecting: %p, %li", alPatch, pDst-alPatch+size);
205#endif
206
207 /* Get write access to mesa functions */
208 rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
209 if (RT_FAILURE(rv))
210 {
211 crError("mprotect failed with %x (%s)", rv, psFuncName);
212 }
213
214#ifndef VBOX_NO_MESA_PATCH_REPORTS
215 crDebug("Writing %li bytes to %p from %p", size, pDst, pSrc);
216#endif
217
218 crMemcpy(pDst, pSrc, size);
219
220 /** @todo Restore the protection, probably have to check what was it before us...*/
221 rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_EXEC);
222 if (RT_FAILURE(rv))
223 {
224 crError("mprotect2 failed with %x (%s)", rv, psFuncName);
225 }
226}
227
228#define FAKEDRI_JMP64_PATCH_SIZE 13
229
230#if defined(RT_OS_FREEBSD)
231/* Provide basic dladdr1 flags */
232enum {
233 RTLD_DL_SYMENT = 1
234};
235
236/* Provide a minimal local version of dladdr1 */
237static int
238dladdr1(const void *address, Dl_info *dlip, void **info, int flags)
239{
240 static DRI_ELFSYM desym;
241 GElf_Sym sym;
242 GElf_Shdr shdr;
243 Elf *elf;
244 Elf_Scn *scn;
245 Elf_Data *data;
246 int ret, fd, count, i;
247
248 /* Initialize variables */
249 fd = -1;
250 elf = NULL;
251
252 /* Call dladdr first */
253 ret = dladdr(address, dlip);
254 if (ret == 0) goto err_exit;
255
256 /* Check for supported flags */
257 if (flags != RTLD_DL_SYMENT) return 1;
258
259 /* Open shared library's ELF file */
260 if (elf_version(EV_CURRENT) == EV_NONE) goto err_exit;
261 fd = open(dlip->dli_fname, O_RDONLY);
262 if (fd < 0) goto err_exit;
263 elf = elf_begin(fd, ELF_C_READ, NULL);
264 if (elf == NULL) goto err_exit;
265
266 /* Find the '.dynsym' section */
267 scn = elf_nextscn(elf, NULL);
268 while (scn != NULL) {
269 if (gelf_getshdr(scn, &shdr) == NULL) goto err_exit;
270 if (shdr.sh_type == SHT_DYNSYM) break;
271 scn = elf_nextscn(elf, scn);
272 }
273 if (scn == NULL) goto err_exit;
274
275 /* Search for the requested symbol by name and offset */
276 data = elf_getdata(scn, NULL);
277 count = shdr.sh_size / shdr.sh_entsize;
278 for (i = 0; i < count; i++) {
279 gelf_getsym(data, i, &sym);
280 if ((strcmp(dlip->dli_sname,
281 elf_strptr(elf, shdr.sh_link, sym.st_name)) == 0) &&
282 (sym.st_value == (dlip->dli_saddr - dlip->dli_fbase))) {
283 break;
284 }
285 }
286
287 /* Close ELF file */
288 elf_end(elf);
289 close(fd);
290
291 /* Return symbol entry in native format */
292 desym.st_name = sym.st_name;
293 desym.st_info = sym.st_info;
294 desym.st_other = sym.st_other;
295 desym.st_shndx = sym.st_shndx;
296 desym.st_value = sym.st_value;
297 desym.st_size = sym.st_size;
298 *info = &desym;
299 return 1;
300
301 /* Error handler */
302err_exit:
303 if (elf != NULL) elf_end(elf);
304 if (fd >= 0) close(fd);
305 return 0;
306}
307#endif
308
309static void
310vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
311{
312 Dl_info dlip;
313 DRI_ELFSYM* sym=0;
314 int rv;
315 void *alPatch;
316 void *pMesaEntry;
317 char patch[FAKEDRI_JMP64_PATCH_SIZE];
318 void *shift;
319 int ignore_size=false;
320
321#ifndef VBOX_NO_MESA_PATCH_REPORTS
322 crDebug("\nvboxPatchMesaExport: %s", psFuncName);
323#endif
324
325 pMesaEntry = dlsym(RTLD_DEFAULT, psFuncName);
326
327 if (!pMesaEntry)
328 {
329 crDebug("%s not defined in current scope, are we being loaded by mesa's libGL.so?", psFuncName);
330 return;
331 }
332
333 rv = dladdr1(pMesaEntry, &dlip, (void**)&sym, RTLD_DL_SYMENT);
334 if (!rv || !sym)
335 {
336 crError("Failed to get size for %p(%s)", pMesaEntry, psFuncName);
337 return;
338 }
339
340#if VBOX_OGL_GLX_USE_CSTUBS
341 {
342 Dl_info dlip1;
343 DRI_ELFSYM* sym1=0;
344 int rv;
345
346 rv = dladdr1(pStart, &dlip1, (void**)&sym1, RTLD_DL_SYMENT);
347 if (!rv || !sym1)
348 {
349 crError("Failed to get size for vbox %p", pStart);
350 return;
351 }
352
353 pEnd = pStart + sym1->st_size;
354# ifndef VBOX_NO_MESA_PATCH_REPORTS
355 crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
356# endif
357 }
358#endif
359
360#ifndef VBOX_NO_MESA_PATCH_REPORTS
361 crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
362 crDebug("VBox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
363#endif
364
365#ifndef VBOX_OGL_GLX_USE_CSTUBS
366 if (sym->st_size<(pEnd-pStart))
367#endif
368 {
369#ifdef RT_ARCH_AMD64
370 int64_t offset;
371#endif
372 /* Try to insert 5 bytes jmp/jmpq to our stub code */
373
374 if (sym->st_size<5)
375 {
376 /** @todo we don't really know the size of targeted static function, but it's long enough in practice. We will also patch same place twice, but it's ok.*/
377 if (!crStrcmp(psFuncName, "glXDestroyContext") || !crStrcmp(psFuncName, "glXFreeContextEXT"))
378 {
379 if (((unsigned char*)dlip.dli_saddr)[0]==0xEB)
380 {
381 /*it's a rel8 jmp, so we're going to patch the place it targets instead of jmp itself*/
382 dlip.dli_saddr = (void*) ((intptr_t)dlip.dli_saddr + ((char*)dlip.dli_saddr)[1] + 2);
383 ignore_size = true;
384 }
385 else
386 {
387 crError("Can't patch size is too small.(%s)", psFuncName);
388 return;
389 }
390 }
391 else if (!crStrcmp(psFuncName, "glXCreateGLXPixmapMESA"))
392 {
393 /** @todo it's just a return 0, which we're fine with for now*/
394 return;
395 }
396 else
397 {
398 crError("Can't patch size is too small.(%s)", psFuncName);
399 return;
400 }
401 }
402
403 shift = (void*)((intptr_t)pStart-((intptr_t)dlip.dli_saddr+5));
404#ifdef RT_ARCH_AMD64
405 offset = (intptr_t)shift;
406 if (offset>INT32_MAX || offset<INT32_MIN)
407 {
408 /*try to insert 64bit abs jmp*/
409 if (sym->st_size>=FAKEDRI_JMP64_PATCH_SIZE || ignore_size)
410 {
411# ifndef VBOX_NO_MESA_PATCH_REPORTS
412 crDebug("Inserting movq/jmp instead");
413# endif
414 /*add 64bit abs jmp*/
415 patch[0] = 0x49; /*movq %r11,imm64*/
416 patch[1] = 0xBB;
417 crMemcpy(&patch[2], &pStart, 8);
418 patch[10] = 0x41; /*jmp *%r11*/
419 patch[11] = 0xFF;
420 patch[12] = 0xE3;
421 pStart = &patch[0];
422 pEnd = &patch[FAKEDRI_JMP64_PATCH_SIZE];
423 }
424 else
425 {
426 FAKEDRI_PatchNode *pNode;
427# ifndef VBOX_NO_MESA_PATCH_REPORTS
428 crDebug("Can't patch offset is too big. Pushing for 2nd pass(%s)", psFuncName);
429# endif
430 /*Add patch node to repatch with chain jmps in 2nd pass*/
431 pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
432 if (!pNode)
433 {
434 crError("Not enough memory.");
435 return;
436 }
437 pNode->psFuncName = psFuncName;
438 pNode->pDstStart = dlip.dli_saddr;
439 pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
440 pNode->pSrcStart = pStart;
441 pNode->pSrcEnd = pEnd;
442 pNode->pNext = g_pRepatchList;
443 g_pRepatchList = pNode;
444 return;
445 }
446 }
447 else
448#endif
449 {
450#ifndef VBOX_NO_MESA_PATCH_REPORTS
451 crDebug("Inserting jmp[q] with shift %p instead", shift);
452#endif
453 patch[0] = 0xE9;
454 crMemcpy(&patch[1], &shift, 4);
455 pStart = &patch[0];
456 pEnd = &patch[5];
457 }
458 }
459
460 vboxApplyPatch(psFuncName, dlip.dli_saddr, pStart, pEnd-pStart);
461
462#ifdef RT_ARCH_AMD64
463 /*Add rest of mesa function body to free list*/
464 if (sym->st_size-(pEnd-pStart)>=FAKEDRI_JMP64_PATCH_SIZE)
465 {
466 FAKEDRI_PatchNode *pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
467 if (pNode)
468 {
469 pNode->psFuncName = psFuncName;
470 pNode->pDstStart = dlip.dli_saddr+(pEnd-pStart);
471 pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
472 pNode->pSrcStart = dlip.dli_saddr;
473 pNode->pSrcEnd = NULL;
474 pNode->pNext = g_pFreeList;
475 g_pFreeList = pNode;
476# ifndef VBOX_NO_MESA_PATCH_REPORTS
477 crDebug("Added free node %s, func start=%p, free start=%p, size=%#lx",
478 psFuncName, pNode->pSrcStart, pNode->pDstStart, pNode->pDstEnd-pNode->pDstStart);
479# endif
480 }
481 }
482#endif
483}
484
485#ifdef RT_ARCH_AMD64
486static void
487vboxRepatchMesaExports(void)
488{
489 FAKEDRI_PatchNode *pFreeNode, *pPatchNode;
490 int64_t offset;
491 char patch[FAKEDRI_JMP64_PATCH_SIZE];
492
493 pPatchNode = g_pRepatchList;
494 while (pPatchNode)
495 {
496# ifndef VBOX_NO_MESA_PATCH_REPORTS
497 crDebug("\nvboxRepatchMesaExports %s", pPatchNode->psFuncName);
498# endif
499 /*find free place in mesa functions, to place 64bit jump to our stub code*/
500 pFreeNode = g_pFreeList;
501 while (pFreeNode)
502 {
503 if (pFreeNode->pDstEnd-pFreeNode->pDstStart>=FAKEDRI_JMP64_PATCH_SIZE)
504 {
505 offset = ((intptr_t)pFreeNode->pDstStart-((intptr_t)pPatchNode->pDstStart+5));
506 if (offset<=INT32_MAX && offset>=INT32_MIN)
507 {
508 break;
509 }
510 }
511 pFreeNode=pFreeNode->pNext;
512 }
513
514 if (!pFreeNode)
515 {
516 crError("Failed to find free space, to place repatch for %s.", pPatchNode->psFuncName);
517 return;
518 }
519
520 /*add 32bit rel jmp, from mesa orginal function to free space in other mesa function*/
521 patch[0] = 0xE9;
522 crMemcpy(&patch[1], &offset, 4);
523# ifndef VBOX_NO_MESA_PATCH_REPORTS
524 crDebug("Adding jmp from mesa %s to mesa %s+%#lx", pPatchNode->psFuncName, pFreeNode->psFuncName,
525 pFreeNode->pDstStart-pFreeNode->pSrcStart);
526# endif
527 vboxApplyPatch(pPatchNode->psFuncName, pPatchNode->pDstStart, &patch[0], 5);
528
529 /*add 64bit abs jmp, from free space to our stub code*/
530 patch[0] = 0x49; /*movq %r11,imm64*/
531 patch[1] = 0xBB;
532 crMemcpy(&patch[2], &pPatchNode->pSrcStart, 8);
533 patch[10] = 0x41; /*jmp *%r11*/
534 patch[11] = 0xFF;
535 patch[12] = 0xE3;
536# ifndef VBOX_NO_MESA_PATCH_REPORTS
537 crDebug("Adding jmp from mesa %s+%#lx to vbox %s", pFreeNode->psFuncName, pFreeNode->pDstStart-pFreeNode->pSrcStart,
538 pPatchNode->psFuncName);
539# endif
540 vboxApplyPatch(pFreeNode->psFuncName, pFreeNode->pDstStart, &patch[0], FAKEDRI_JMP64_PATCH_SIZE);
541 /*mark this space as used*/
542 pFreeNode->pDstStart = pFreeNode->pDstStart+FAKEDRI_JMP64_PATCH_SIZE;
543
544 pPatchNode = pPatchNode->pNext;
545 }
546}
547
548static void
549vboxFakeDriFreeList(FAKEDRI_PatchNode *pList)
550{
551 FAKEDRI_PatchNode *pNode;
552
553 while (pList)
554 {
555 pNode=pList;
556 pList=pNode->pNext;
557 crFree(pNode);
558 }
559}
560#endif
561
562#ifdef VBOX_OGL_GLX_USE_CSTUBS
563static void
564# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, NULL);
565vboxPatchMesaExports()
566#else
567static void
568# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, &vbox_glX##Func##_EndProc);
569vboxPatchMesaExports()
570#endif
571{
572 crDebug("Patching mesa glx entries");
573 #include "fakedri_glxfuncsList.h"
574
575#ifdef RT_ARCH_AMD64
576 vboxRepatchMesaExports();
577 vboxFakeDriFreeList(g_pRepatchList);
578 g_pRepatchList = NULL;
579 vboxFakeDriFreeList(g_pFreeList);
580 g_pFreeList = NULL;
581#endif
582}
583#undef GLXAPI_ENTRY
584
585bool vbox_load_sw_dri()
586{
587 const char *libPaths, *p, *next;;
588 char realDriverName[200];
589 void *handle;
590 int len, i;
591
592 /*code from Mesa-7.2/src/glx/x11/dri_common.c:driOpenDriver*/
593
594 libPaths = NULL;
595 if (geteuid() == getuid()) {
596 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
597 libPaths = getenv("LIBGL_DRIVERS_PATH");
598 if (!libPaths)
599 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
600 }
601 if (libPaths == NULL)
602 libPaths = DRI_DEFAULT_DRIVER_DIR;
603
604 handle = NULL;
605 for (p = libPaths; *p; p = next)
606 {
607 next = strchr(p, ':');
608 if (next == NULL)
609 {
610 len = strlen(p);
611 next = p + len;
612 }
613 else
614 {
615 len = next - p;
616 next++;
617 }
618
619 snprintf(realDriverName, sizeof realDriverName, "%.*s/%s_dri.so", len, p, "swrast");
620 crDebug("trying %s", realDriverName);
621 handle = dlopen(realDriverName, RTLD_NOW | RTLD_LOCAL);
622 if (handle) break;
623 }
624
625 /*end code*/
626
627 if (handle) gppSwDriExternsion = dlsym(handle, "__driDriverExtensions");
628
629 if (!gppSwDriExternsion)
630 {
631 crDebug("%s doesn't export __driDriverExtensions", realDriverName);
632 return false;
633 }
634 crDebug("loaded %s", realDriverName);
635
636 for (i = 0; gppSwDriExternsion[i]; i++)
637 {
638 if (strcmp(gppSwDriExternsion[i]->name, __DRI_CORE) == 0)
639 gpSwDriCoreExternsion = (__DRIcoreExtension *) gppSwDriExternsion[i];
640 if (strcmp(gppSwDriExternsion[i]->name, __DRI_SWRAST) == 0)
641 gpSwDriSwrastExtension = (__DRIswrastExtension *) gppSwDriExternsion[i];
642 }
643
644 return gpSwDriCoreExternsion && gpSwDriSwrastExtension;
645}
646
647void __attribute__ ((constructor)) vbox_install_into_mesa(void)
648{
649 {
650#ifdef _X_ATTRIBUTE_PRINTF
651 void (*pxf86Msg)(MessageType type, const char *format, ...) _X_ATTRIBUTE_PRINTF(2,3);
652#else
653 void (*pxf86Msg)(MessageType type, const char *format, ...) _printf_attribute(2,3);
654#endif
655
656 pxf86Msg = dlsym(RTLD_DEFAULT, "xf86Msg");
657 if (pxf86Msg)
658 {
659 pxf86Msg(X_INFO, "Next line is added to allow vboxvideo_drv.so to appear as whitelisted driver\n");
660 pxf86Msg(X_INFO, "The file referenced, is *NOT* loaded\n");
661 pxf86Msg(X_INFO, "Loading %s/ati_drv.so\n", DRI_XORG_DRV_DIR);
662
663 /* we're failing to proxy software dri driver calls for certain xservers, so just make sure we're unloaded for now */
664 __driDriverExtensions[0] = NULL;
665 return;
666 }
667 }
668
669 if (!stubInit())
670 {
671 crDebug("vboxdriInitScreen: stubInit failed");
672 return;
673 }
674
675 /* Load swrast_dri.so to proxy dri related calls there. */
676 if (!vbox_load_sw_dri())
677 {
678 crDebug("vboxdriInitScreen: vbox_load_sw_dri failed...going to fail badly");
679 return;
680 }
681
682 /* Handle gl api.
683 * In the end application call would look like this:
684 * app call glFoo->(mesa asm dispatch stub)->cr_glFoo(vbox asm dispatch stub)->SPU Foo function(packspuFoo or alike)
685 * Note, we don't need to install extension functions via _glapi_add_dispatch, because we'd override glXGetProcAddress.
686 */
687 /* Mesa's dispatch table is different across library versions, have to modify mesa's table using offset info functions*/
688 vboxPatchMesaGLAPITable();
689
690 /* Handle glx api.
691 * In the end application call would look like this:
692 * app call glxFoo->(mesa asm dispatch stub patched with vbox_glXFoo:jmp glxim[Foo's index])->VBOXGLXTAG(glxFoo)
693 */
694 /* Fill structure used by our assembly stubs */
695 vboxFillGLXAPITable(&glxim);
696 /* Now patch functions exported by libGL.so */
697 vboxPatchMesaExports();
698}
699
700/*
701 * @todo we're missing first glx related call from the client application.
702 * Luckily, this doesn't add much problems, except for some cases.
703 */
704
705/* __DRIcoreExtension */
706
707static __DRIscreen *
708vboxdriCreateNewScreen(int screen, int fd, unsigned int sarea_handle,
709 const __DRIextension **extensions, const __DRIconfig ***driverConfigs,
710 void *loaderPrivate)
711{
712 (void) fd;
713 (void) sarea_handle;
714 SWDRI_SAFERET_SWRAST(createNewScreen, screen, extensions, driverConfigs, loaderPrivate);
715}
716
717static void
718vboxdriDestroyScreen(__DRIscreen *screen)
719{
720 SWDRI_SAFECALL_CORE(destroyScreen, screen);
721}
722
723static const __DRIextension **
724vboxdriGetExtensions(__DRIscreen *screen)
725{
726 SWDRI_SAFERET_CORE(getExtensions, screen);
727}
728
729static int
730vboxdriGetConfigAttrib(const __DRIconfig *config,
731 unsigned int attrib,
732 unsigned int *value)
733{
734 SWDRI_SAFERET_CORE(getConfigAttrib, config, attrib, value);
735}
736
737static int
738vboxdriIndexConfigAttrib(const __DRIconfig *config, int index,
739 unsigned int *attrib, unsigned int *value)
740{
741 SWDRI_SAFERET_CORE(indexConfigAttrib, config, index, attrib, value);
742}
743
744static __DRIdrawable *
745vboxdriCreateNewDrawable(__DRIscreen *screen,
746 const __DRIconfig *config,
747 unsigned int drawable_id,
748 unsigned int head,
749 void *loaderPrivate)
750{
751 (void) drawable_id;
752 (void) head;
753 SWDRI_SAFERET_SWRAST(createNewDrawable, screen, config, loaderPrivate);
754}
755
756static void
757vboxdriDestroyDrawable(__DRIdrawable *drawable)
758{
759 SWDRI_SAFECALL_CORE(destroyDrawable, drawable);
760}
761
762static void
763vboxdriSwapBuffers(__DRIdrawable *drawable)
764{
765 SWDRI_SAFECALL_CORE(swapBuffers, drawable);
766}
767
768static __DRIcontext *
769vboxdriCreateNewContext(__DRIscreen *screen,
770 const __DRIconfig *config,
771 __DRIcontext *shared,
772 void *loaderPrivate)
773{
774 SWDRI_SAFERET_CORE(createNewContext, screen, config, shared, loaderPrivate);
775}
776
777static int
778vboxdriCopyContext(__DRIcontext *dest,
779 __DRIcontext *src,
780 unsigned long mask)
781{
782 SWDRI_SAFERET_CORE(copyContext, dest, src, mask);
783}
784
785static void
786vboxdriDestroyContext(__DRIcontext *context)
787{
788 SWDRI_SAFECALL_CORE(destroyContext, context);
789}
790
791static int
792vboxdriBindContext(__DRIcontext *ctx,
793 __DRIdrawable *pdraw,
794 __DRIdrawable *pread)
795{
796 SWDRI_SAFERET_CORE(bindContext, ctx, pdraw, pread);
797}
798
799static int
800vboxdriUnbindContext(__DRIcontext *ctx)
801{
802 SWDRI_SAFERET_CORE(unbindContext, ctx)
803}
804
805/* __DRIlegacyExtension */
806
807static __DRIscreen *
808vboxdriCreateNewScreen_Legacy(int scrn,
809 const __DRIversion *ddx_version,
810 const __DRIversion *dri_version,
811 const __DRIversion *drm_version,
812 const __DRIframebuffer *frame_buffer,
813 drmAddress pSAREA, int fd,
814 const __DRIextension **extensions,
815 const __DRIconfig ***driver_modes,
816 void *loaderPrivate)
817{
818 (void) ddx_version;
819 (void) dri_version;
820 (void) frame_buffer;
821 (void) pSAREA;
822 (void) fd;
823 SWDRI_SAFERET_SWRAST(createNewScreen, scrn, extensions, driver_modes, loaderPrivate);
824}
825
826static __DRIdrawable *
827vboxdriCreateNewDrawable_Legacy(__DRIscreen *psp, const __DRIconfig *config,
828 drm_drawable_t hwDrawable, int renderType,
829 const int *attrs, void *data)
830{
831 (void) hwDrawable;
832 (void) renderType;
833 (void) attrs;
834 (void) data;
835 SWDRI_SAFERET_SWRAST(createNewDrawable, psp, config, data);
836}
837
838static __DRIcontext *
839vboxdriCreateNewContext_Legacy(__DRIscreen *psp, const __DRIconfig *config,
840 int render_type, __DRIcontext *shared,
841 drm_context_t hwContext, void *data)
842{
843 (void) render_type;
844 (void) hwContext;
845 return vboxdriCreateNewContext(psp, config, shared, data);
846}
847
848
849static const __DRIlegacyExtension vboxdriLegacyExtension = {
850 { __DRI_LEGACY, __DRI_LEGACY_VERSION },
851 vboxdriCreateNewScreen_Legacy,
852 vboxdriCreateNewDrawable_Legacy,
853 vboxdriCreateNewContext_Legacy
854};
855
856static const __DRIcoreExtension vboxdriCoreExtension = {
857 { __DRI_CORE, __DRI_CORE_VERSION },
858 vboxdriCreateNewScreen, /* driCreateNewScreen */
859 vboxdriDestroyScreen,
860 vboxdriGetExtensions,
861 vboxdriGetConfigAttrib,
862 vboxdriIndexConfigAttrib,
863 vboxdriCreateNewDrawable, /* driCreateNewDrawable */
864 vboxdriDestroyDrawable,
865 vboxdriSwapBuffers,
866 vboxdriCreateNewContext,
867 vboxdriCopyContext,
868 vboxdriDestroyContext,
869 vboxdriBindContext,
870 vboxdriUnbindContext
871};
872
873/* This structure is used by dri_util from mesa, don't rename it! */
874DECLEXPORT(const __DRIextension *) __driDriverExtensions[] = {
875 &vboxdriLegacyExtension.base,
876 &vboxdriCoreExtension.base,
877 NULL
878};
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