VirtualBox

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

Last change on this file since 35039 was 35039, checked in by vboxsync, 13 years ago

crOpenGL: fix glmark2 incorrect rendering with mesa 7.9

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.3 KB
Line 
1/* $Id: fakedri_drv.c 35039 2010-12-13 17:37:15Z vboxsync $ */
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
86#ifdef RT_ARCH_AMD64
87typedef struct _FAKEDRI_PatchNode
88{
89 const char* psFuncName;
90 void *pDstStart, *pDstEnd;
91 const void *pSrcStart, *pSrcEnd;
92
93 struct _FAKEDRI_PatchNode *pNext;
94} FAKEDRI_PatchNode;
95static FAKEDRI_PatchNode *g_pFreeList=NULL, *g_pRepatchList=NULL;
96#endif
97
98static struct _glapi_table* vbox_glapi_table = NULL;
99fakedri_glxapi_table glxim;
100
101static const __DRIextension **gppSwDriExternsion = NULL;
102static const __DRIcoreExtension *gpSwDriCoreExternsion = NULL;
103static const __DRIswrastExtension *gpSwDriSwrastExtension = NULL;
104
105extern const __DRIextension * __driDriverExtensions[];
106
107#define GLAPI_ENTRY(Func) SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("gl"#Func), cr_gl##Func);
108
109static void
110vboxPatchMesaGLAPITable()
111{
112 void *pGLTable;
113
114 pGLTable = (void *)_glapi_get_dispatch();
115 vbox_glapi_table = crAlloc(_glapi_get_dispatch_table_size() * sizeof (void *));
116 if (!vbox_glapi_table)
117 {
118 crError("Not enough memory to allocate dispatch table");
119 }
120 crMemcpy(vbox_glapi_table, pGLTable, _glapi_get_dispatch_table_size() * sizeof (void *));
121
122 #include "fakedri_glfuncsList.h"
123
124 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glBlendEquationSeparateEXT"), cr_glBlendEquationSeparate);
125 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glSampleMaskSGIS"), cr_glSampleMaskEXT);
126 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glSamplePatternSGIS"), cr_glSamplePatternEXT);
127 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2dMESA"), cr_glWindowPos2d);
128 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2dvMESA"), cr_glWindowPos2dv);
129 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2fMESA"), cr_glWindowPos2f);
130 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2fvMESA"), cr_glWindowPos2fv);
131 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2iMESA"), cr_glWindowPos2i);
132 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2ivMESA"), cr_glWindowPos2iv);
133 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2sMESA"), cr_glWindowPos2s);
134 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos2svMESA"), cr_glWindowPos2sv);
135 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3dMESA"), cr_glWindowPos3d);
136 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3dvMESA"), cr_glWindowPos3dv);
137 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3fMESA"), cr_glWindowPos3f);
138 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3fvMESA"), cr_glWindowPos3fv);
139 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3iMESA"), cr_glWindowPos3i);
140 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3ivMESA"), cr_glWindowPos3iv);
141 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3sMESA"), cr_glWindowPos3s);
142 SET_by_offset(vbox_glapi_table, _glapi_get_proc_offset("glWindowPos3svMESA"), cr_glWindowPos3sv);
143
144 _glapi_set_dispatch(vbox_glapi_table);
145};
146#undef GLAPI_ENTRY
147
148#define GLXAPI_ENTRY(Func) pGLXTable->Func = VBOXGLXTAG(glX##Func);
149static void
150vboxFillGLXAPITable(fakedri_glxapi_table *pGLXTable)
151{
152 #include "fakedri_glxfuncsList.h"
153}
154#undef GLXAPI_ENTRY
155
156static void
157vboxApplyPatch(const char* psFuncName, void *pDst, const void *pSrc, unsigned long size)
158{
159 void *alPatch;
160 int rv;
161
162 /* Get aligned start address we're going to patch*/
163 alPatch = (void*) ((uintptr_t)pDst & ~(uintptr_t)(PAGESIZE-1));
164
165#ifndef VBOX_NO_MESA_PATCH_REPORTS
166 crDebug("MProtecting: %p, %li", alPatch, pDst-alPatch+size);
167#endif
168
169 /* Get write access to mesa functions */
170 rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
171 if (RT_FAILURE(rv))
172 {
173 crError("mprotect failed with %x (%s)", rv, psFuncName);
174 }
175
176#ifndef VBOX_NO_MESA_PATCH_REPORTS
177 crDebug("Writing %li bytes to %p from %p", size, pDst, pSrc);
178#endif
179
180 crMemcpy(pDst, pSrc, size);
181
182 /*@todo Restore the protection, probably have to check what was it before us...*/
183 rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_EXEC);
184 if (RT_FAILURE(rv))
185 {
186 crError("mprotect2 failed with %x (%s)", rv, psFuncName);
187 }
188}
189
190#define FAKEDRI_JMP64_PATCH_SIZE 13
191
192static void
193vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
194{
195 Dl_info dlip;
196 DRI_ELFSYM* sym=0;
197 int rv;
198 void *alPatch;
199 void *pMesaEntry;
200 char patch[FAKEDRI_JMP64_PATCH_SIZE];
201 void *shift;
202 int ignore_size=false;
203
204#ifndef VBOX_NO_MESA_PATCH_REPORTS
205 crDebug("\nvboxPatchMesaExport: %s", psFuncName);
206#endif
207
208 pMesaEntry = dlsym(RTLD_DEFAULT, psFuncName);
209
210 if (!pMesaEntry)
211 {
212 crDebug("%s not defined in current scope, are we being loaded by mesa's libGL.so?", psFuncName);
213 return;
214 }
215
216 rv = dladdr1(pMesaEntry, &dlip, (void**)&sym, RTLD_DL_SYMENT);
217 if (!rv || !sym)
218 {
219 crError("Failed to get size for %p(%s)", pMesaEntry, psFuncName);
220 return;
221 }
222
223#if VBOX_OGL_GLX_USE_CSTUBS
224 {
225 Dl_info dlip1;
226 DRI_ELFSYM* sym1=0;
227 int rv;
228
229 rv = dladdr1(pStart, &dlip1, (void**)&sym1, RTLD_DL_SYMENT);
230 if (!rv || !sym1)
231 {
232 crError("Failed to get size for %p", pStart);
233 return;
234 }
235
236 pEnd = pStart + sym1->st_size;
237# ifndef VBOX_NO_MESA_PATCH_REPORTS
238 crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
239# endif
240 }
241#endif
242
243#ifndef VBOX_NO_MESA_PATCH_REPORTS
244 crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
245 crDebug("Vbox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
246#endif
247
248#ifndef VBOX_OGL_GLX_USE_CSTUBS
249 if (sym->st_size<(pEnd-pStart))
250#endif
251 {
252#ifdef RT_ARCH_AMD64
253 int64_t offset;
254#endif
255 /* Try to insert 5 bytes jmp/jmpq to our stub code */
256
257 if (sym->st_size<5)
258 {
259 /*@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.*/
260 if (!crStrcmp(psFuncName, "glXDestroyContext") || !crStrcmp(psFuncName, "glXFreeContextEXT"))
261 {
262 if (((unsigned char*)dlip.dli_saddr)[0]==0xEB)
263 {
264 /*it's a rel8 jmp, so we're going to patch the place it targets instead of jmp itself*/
265 dlip.dli_saddr = (void*) ((intptr_t)dlip.dli_saddr + ((char*)dlip.dli_saddr)[1] + 2);
266 ignore_size = true;
267 }
268 else
269 {
270 crError("Can't patch size is too small.(%s)", psFuncName);
271 return;
272 }
273 }
274 else if (!crStrcmp(psFuncName, "glXCreateGLXPixmapMESA"))
275 {
276 /*@todo it's just a return 0, which we're fine with for now*/
277 return;
278 }
279 else
280 {
281 crError("Can't patch size is too small.(%s)", psFuncName);
282 return;
283 }
284 }
285
286 shift = (void*)((intptr_t)pStart-((intptr_t)dlip.dli_saddr+5));
287#ifdef RT_ARCH_AMD64
288 offset = (intptr_t)shift;
289 if (offset>INT32_MAX || offset<INT32_MIN)
290 {
291 /*try to insert 64bit abs jmp*/
292 if (sym->st_size>=FAKEDRI_JMP64_PATCH_SIZE || ignore_size)
293 {
294# ifndef VBOX_NO_MESA_PATCH_REPORTS
295 crDebug("Inserting movq/jmp instead");
296# endif
297 /*add 64bit abs jmp*/
298 patch[0] = 0x49; /*movq %r11,imm64*/
299 patch[1] = 0xBB;
300 crMemcpy(&patch[2], &pStart, 8);
301 patch[10] = 0x41; /*jmp *%r11*/
302 patch[11] = 0xFF;
303 patch[12] = 0xE3;
304 pStart = &patch[0];
305 pEnd = &patch[FAKEDRI_JMP64_PATCH_SIZE];
306 }
307 else
308 {
309 FAKEDRI_PatchNode *pNode;
310# ifndef VBOX_NO_MESA_PATCH_REPORTS
311 crDebug("Can't patch offset is too big. Pushing for 2nd pass(%s)", psFuncName);
312# endif
313 /*Add patch node to repatch with chain jmps in 2nd pass*/
314 pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
315 if (!pNode)
316 {
317 crError("Not enough memory.");
318 return;
319 }
320 pNode->psFuncName = psFuncName;
321 pNode->pDstStart = dlip.dli_saddr;
322 pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
323 pNode->pSrcStart = pStart;
324 pNode->pSrcEnd = pEnd;
325 pNode->pNext = g_pRepatchList;
326 g_pRepatchList = pNode;
327 return;
328 }
329 }
330 else
331#endif
332 {
333#ifndef VBOX_NO_MESA_PATCH_REPORTS
334 crDebug("Inserting jmp[q] with shift %p instead", shift);
335#endif
336 patch[0] = 0xE9;
337 crMemcpy(&patch[1], &shift, 4);
338 pStart = &patch[0];
339 pEnd = &patch[5];
340 }
341 }
342
343 vboxApplyPatch(psFuncName, dlip.dli_saddr, pStart, pEnd-pStart);
344
345#ifdef RT_ARCH_AMD64
346 /*Add rest of mesa function body to free list*/
347 if (sym->st_size-(pEnd-pStart)>=FAKEDRI_JMP64_PATCH_SIZE)
348 {
349 FAKEDRI_PatchNode *pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
350 if (pNode)
351 {
352 pNode->psFuncName = psFuncName;
353 pNode->pDstStart = dlip.dli_saddr+(pEnd-pStart);
354 pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
355 pNode->pSrcStart = dlip.dli_saddr;
356 pNode->pSrcEnd = NULL;
357 pNode->pNext = g_pFreeList;
358 g_pFreeList = pNode;
359# ifndef VBOX_NO_MESA_PATCH_REPORTS
360 crDebug("Added free node %s, func start=%p, free start=%p, size=%#lx",
361 psFuncName, pNode->pSrcStart, pNode->pDstStart, pNode->pDstEnd-pNode->pDstStart);
362# endif
363 }
364 }
365#endif
366}
367
368#ifdef RT_ARCH_AMD64
369static void
370vboxRepatchMesaExports(void)
371{
372 FAKEDRI_PatchNode *pFreeNode, *pPatchNode;
373 int64_t offset;
374 char patch[FAKEDRI_JMP64_PATCH_SIZE];
375
376 pPatchNode = g_pRepatchList;
377 while (pPatchNode)
378 {
379# ifndef VBOX_NO_MESA_PATCH_REPORTS
380 crDebug("\nvboxRepatchMesaExports %s", pPatchNode->psFuncName);
381# endif
382 /*find free place in mesa functions, to place 64bit jump to our stub code*/
383 pFreeNode = g_pFreeList;
384 while (pFreeNode)
385 {
386 if (pFreeNode->pDstEnd-pFreeNode->pDstStart>=FAKEDRI_JMP64_PATCH_SIZE)
387 {
388 offset = ((intptr_t)pFreeNode->pDstStart-((intptr_t)pPatchNode->pDstStart+5));
389 if (offset<=INT32_MAX && offset>=INT32_MIN)
390 {
391 break;
392 }
393 }
394 pFreeNode=pFreeNode->pNext;
395 }
396
397 if (!pFreeNode)
398 {
399 crError("Failed to find free space, to place repatch for %s.", pPatchNode->psFuncName);
400 return;
401 }
402
403 /*add 32bit rel jmp, from mesa orginal function to free space in other mesa function*/
404 patch[0] = 0xE9;
405 crMemcpy(&patch[1], &offset, 4);
406# ifndef VBOX_NO_MESA_PATCH_REPORTS
407 crDebug("Adding jmp from mesa %s to mesa %s+%#lx", pPatchNode->psFuncName, pFreeNode->psFuncName,
408 pFreeNode->pDstStart-pFreeNode->pSrcStart);
409# endif
410 vboxApplyPatch(pPatchNode->psFuncName, pPatchNode->pDstStart, &patch[0], 5);
411
412 /*add 64bit abs jmp, from free space to our stub code*/
413 patch[0] = 0x49; /*movq %r11,imm64*/
414 patch[1] = 0xBB;
415 crMemcpy(&patch[2], &pPatchNode->pSrcStart, 8);
416 patch[10] = 0x41; /*jmp *%r11*/
417 patch[11] = 0xFF;
418 patch[12] = 0xE3;
419# ifndef VBOX_NO_MESA_PATCH_REPORTS
420 crDebug("Adding jmp from mesa %s+%#lx to vbox %s", pFreeNode->psFuncName, pFreeNode->pDstStart-pFreeNode->pSrcStart,
421 pPatchNode->psFuncName);
422# endif
423 vboxApplyPatch(pFreeNode->psFuncName, pFreeNode->pDstStart, &patch[0], FAKEDRI_JMP64_PATCH_SIZE);
424 /*mark this space as used*/
425 pFreeNode->pDstStart = pFreeNode->pDstStart+FAKEDRI_JMP64_PATCH_SIZE;
426
427 pPatchNode = pPatchNode->pNext;
428 }
429}
430
431static void
432vboxFakeDriFreeList(FAKEDRI_PatchNode *pList)
433{
434 FAKEDRI_PatchNode *pNode;
435
436 while (pList)
437 {
438 pNode=pList;
439 pList=pNode->pNext;
440 crFree(pNode);
441 }
442}
443#endif
444
445#ifdef VBOX_OGL_GLX_USE_CSTUBS
446static void
447# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, NULL);
448vboxPatchMesaExports()
449#else
450static void
451# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, &vbox_glX##Func##_EndProc);
452vboxPatchMesaExports()
453#endif
454{
455 crDebug("Patching mesa glx entries");
456 #include "fakedri_glxfuncsList.h"
457
458#ifdef RT_ARCH_AMD64
459 vboxRepatchMesaExports();
460 vboxFakeDriFreeList(g_pRepatchList);
461 g_pRepatchList = NULL;
462 vboxFakeDriFreeList(g_pFreeList);
463 g_pFreeList = NULL;
464#endif
465}
466#undef GLXAPI_ENTRY
467
468bool vbox_load_sw_dri()
469{
470 const char *libPaths, *p, *next;;
471 char realDriverName[200];
472 void *handle;
473 int len, i;
474
475 /*code from Mesa-7.2/src/glx/x11/dri_common.c:driOpenDriver*/
476
477 libPaths = NULL;
478 if (geteuid() == getuid()) {
479 /* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
480 libPaths = getenv("LIBGL_DRIVERS_PATH");
481 if (!libPaths)
482 libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
483 }
484 if (libPaths == NULL)
485 libPaths = DRI_DEFAULT_DRIVER_DIR;
486
487 handle = NULL;
488 for (p = libPaths; *p; p = next)
489 {
490 next = strchr(p, ':');
491 if (next == NULL)
492 {
493 len = strlen(p);
494 next = p + len;
495 }
496 else
497 {
498 len = next - p;
499 next++;
500 }
501
502 snprintf(realDriverName, sizeof realDriverName, "%.*s/%s_dri.so", len, p, "swrast");
503 crDebug("trying %s", realDriverName);
504 handle = dlopen(realDriverName, RTLD_NOW | RTLD_LOCAL);
505 if (handle) break;
506 }
507
508 /*end code*/
509
510 if (handle) gppSwDriExternsion = dlsym(handle, "__driDriverExtensions");
511
512 if (!gppSwDriExternsion)
513 {
514 crDebug("%s doesn't export __driDriverExtensions", realDriverName);
515 return false;
516 }
517 crDebug("loaded %s", realDriverName);
518
519 for (i = 0; gppSwDriExternsion[i]; i++)
520 {
521 if (strcmp(gppSwDriExternsion[i]->name, __DRI_CORE) == 0)
522 gpSwDriCoreExternsion = (__DRIcoreExtension *) gppSwDriExternsion[i];
523 if (strcmp(gppSwDriExternsion[i]->name, __DRI_SWRAST) == 0)
524 gpSwDriSwrastExtension = (__DRIswrastExtension *) gppSwDriExternsion[i];
525 }
526
527 return gpSwDriCoreExternsion && gpSwDriSwrastExtension;
528}
529
530void __attribute__ ((constructor)) vbox_install_into_mesa(void)
531{
532 {
533#ifdef _X_ATTRIBUTE_PRINTF
534 void (*pxf86Msg)(MessageType type, const char *format, ...) _X_ATTRIBUTE_PRINTF(2,3);
535#else
536 void (*pxf86Msg)(MessageType type, const char *format, ...) _printf_attribute(2,3);
537#endif
538
539 pxf86Msg = dlsym(RTLD_DEFAULT, "xf86Msg");
540 if (pxf86Msg)
541 {
542 pxf86Msg(X_INFO, "Next line is added to allow vboxvideo_drv.so to appear as whitelisted driver\n");
543 pxf86Msg(X_INFO, "The file referenced, is *NOT* loaded\n");
544 pxf86Msg(X_INFO, "Loading %s/ati_drv.so\n", DRI_XORG_DRV_DIR);
545
546 /* we're failing to proxy software dri driver calls for certain xservers, so just make sure we're unloaded for now */
547 __driDriverExtensions[0] = NULL;
548 return;
549 }
550 }
551
552 if (!stubInit())
553 {
554 crDebug("vboxdriInitScreen: stubInit failed");
555 return;
556 }
557
558 /* Load swrast_dri.so to proxy dri related calls there. */
559 if (!vbox_load_sw_dri())
560 {
561 crDebug("vboxdriInitScreen: vbox_load_sw_dri failed...going to fail badly");
562 return;
563 }
564
565 /* Handle gl api.
566 * In the end application call would look like this:
567 * app call glFoo->(mesa asm dispatch stub)->cr_glFoo(vbox asm dispatch stub)->SPU Foo function(packspuFoo or alike)
568 * Note, we don't need to install extension functions via _glapi_add_dispatch, because we'd override glXGetProcAddress.
569 */
570 /* Mesa's dispatch table is different across library versions, have to modify mesa's table using offset info functions*/
571 vboxPatchMesaGLAPITable();
572
573 /* Handle glx api.
574 * In the end application call would look like this:
575 * app call glxFoo->(mesa asm dispatch stub patched with vbox_glXFoo:jmp glxim[Foo's index])->VBOXGLXTAG(glxFoo)
576 */
577 /* Fill structure used by our assembly stubs */
578 vboxFillGLXAPITable(&glxim);
579 /* Now patch functions exported by libGL.so */
580 vboxPatchMesaExports();
581}
582
583/*
584 * @todo we're missing first glx related call from the client application.
585 * Luckily, this doesn't add much problems, except for some cases.
586 */
587
588/* __DRIcoreExtension */
589
590static __DRIscreen *
591vboxdriCreateNewScreen(int screen, int fd, unsigned int sarea_handle,
592 const __DRIextension **extensions, const __DRIconfig ***driverConfigs,
593 void *loaderPrivate)
594{
595 (void) fd;
596 (void) sarea_handle;
597 SWDRI_SAFERET_SWRAST(createNewScreen, screen, extensions, driverConfigs, loaderPrivate);
598}
599
600static void
601vboxdriDestroyScreen(__DRIscreen *screen)
602{
603 SWDRI_SAFECALL_CORE(destroyScreen, screen);
604}
605
606static const __DRIextension **
607vboxdriGetExtensions(__DRIscreen *screen)
608{
609 SWDRI_SAFERET_CORE(getExtensions, screen);
610}
611
612static int
613vboxdriGetConfigAttrib(const __DRIconfig *config,
614 unsigned int attrib,
615 unsigned int *value)
616{
617 SWDRI_SAFERET_CORE(getConfigAttrib, config, attrib, value);
618}
619
620static int
621vboxdriIndexConfigAttrib(const __DRIconfig *config, int index,
622 unsigned int *attrib, unsigned int *value)
623{
624 SWDRI_SAFERET_CORE(indexConfigAttrib, config, index, attrib, value);
625}
626
627static __DRIdrawable *
628vboxdriCreateNewDrawable(__DRIscreen *screen,
629 const __DRIconfig *config,
630 unsigned int drawable_id,
631 unsigned int head,
632 void *loaderPrivate)
633{
634 (void) drawable_id;
635 (void) head;
636 SWDRI_SAFERET_SWRAST(createNewDrawable, screen, config, loaderPrivate);
637}
638
639static void
640vboxdriDestroyDrawable(__DRIdrawable *drawable)
641{
642 SWDRI_SAFECALL_CORE(destroyDrawable, drawable);
643}
644
645static void
646vboxdriSwapBuffers(__DRIdrawable *drawable)
647{
648 SWDRI_SAFECALL_CORE(swapBuffers, drawable);
649}
650
651static __DRIcontext *
652vboxdriCreateNewContext(__DRIscreen *screen,
653 const __DRIconfig *config,
654 __DRIcontext *shared,
655 void *loaderPrivate)
656{
657 SWDRI_SAFERET_CORE(createNewContext, screen, config, shared, loaderPrivate);
658}
659
660static int
661vboxdriCopyContext(__DRIcontext *dest,
662 __DRIcontext *src,
663 unsigned long mask)
664{
665 SWDRI_SAFERET_CORE(copyContext, dest, src, mask);
666}
667
668static void
669vboxdriDestroyContext(__DRIcontext *context)
670{
671 SWDRI_SAFECALL_CORE(destroyContext, context);
672}
673
674static int
675vboxdriBindContext(__DRIcontext *ctx,
676 __DRIdrawable *pdraw,
677 __DRIdrawable *pread)
678{
679 SWDRI_SAFERET_CORE(bindContext, ctx, pdraw, pread);
680}
681
682static int
683vboxdriUnbindContext(__DRIcontext *ctx)
684{
685 SWDRI_SAFERET_CORE(unbindContext, ctx)
686}
687
688/* __DRIlegacyExtension */
689
690static __DRIscreen *
691vboxdriCreateNewScreen_Legacy(int scrn,
692 const __DRIversion *ddx_version,
693 const __DRIversion *dri_version,
694 const __DRIversion *drm_version,
695 const __DRIframebuffer *frame_buffer,
696 drmAddress pSAREA, int fd,
697 const __DRIextension **extensions,
698 const __DRIconfig ***driver_modes,
699 void *loaderPrivate)
700{
701 (void) ddx_version;
702 (void) dri_version;
703 (void) frame_buffer;
704 (void) pSAREA;
705 (void) fd;
706 SWDRI_SAFERET_SWRAST(createNewScreen, scrn, extensions, driver_modes, loaderPrivate);
707}
708
709static __DRIdrawable *
710vboxdriCreateNewDrawable_Legacy(__DRIscreen *psp, const __DRIconfig *config,
711 drm_drawable_t hwDrawable, int renderType,
712 const int *attrs, void *data)
713{
714 (void) hwDrawable;
715 (void) renderType;
716 (void) attrs;
717 (void) data;
718 SWDRI_SAFERET_SWRAST(createNewDrawable, psp, config, data);
719}
720
721static __DRIcontext *
722vboxdriCreateNewContext_Legacy(__DRIscreen *psp, const __DRIconfig *config,
723 int render_type, __DRIcontext *shared,
724 drm_context_t hwContext, void *data)
725{
726 (void) render_type;
727 (void) hwContext;
728 return vboxdriCreateNewContext(psp, config, shared, data);
729}
730
731
732static const __DRIlegacyExtension vboxdriLegacyExtension = {
733 { __DRI_LEGACY, __DRI_LEGACY_VERSION },
734 vboxdriCreateNewScreen_Legacy,
735 vboxdriCreateNewDrawable_Legacy,
736 vboxdriCreateNewContext_Legacy
737};
738
739static const __DRIcoreExtension vboxdriCoreExtension = {
740 { __DRI_CORE, __DRI_CORE_VERSION },
741 vboxdriCreateNewScreen, /* driCreateNewScreen */
742 vboxdriDestroyScreen,
743 vboxdriGetExtensions,
744 vboxdriGetConfigAttrib,
745 vboxdriIndexConfigAttrib,
746 vboxdriCreateNewDrawable, /* driCreateNewDrawable */
747 vboxdriDestroyDrawable,
748 vboxdriSwapBuffers,
749 vboxdriCreateNewContext,
750 vboxdriCopyContext,
751 vboxdriDestroyContext,
752 vboxdriBindContext,
753 vboxdriUnbindContext
754};
755
756/* This structure is used by dri_util from mesa, don't rename it! */
757DECLEXPORT(const __DRIextension *) __driDriverExtensions[] = {
758 &vboxdriLegacyExtension.base,
759 &vboxdriCoreExtension.base,
760 NULL
761};
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use