~ubuntu-branches/ubuntu/precise/virtualbox/precise-updates

« back to all changes in this revision

Viewing changes to .pc/31-multiarch-dri-path.patch/src/VBox/Additions/common/crOpenGL/fakedri_drv.c

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-07-04 13:02:31 UTC
  • mfrom: (3.1.1 sid)
  • Revision ID: james.westby@ubuntu.com-20110704130231-l843es6wqhx614n7
Tags: 4.0.10-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Add the Modaliases control field manually for maximum backportability.

Show diffs side-by-side

added added

removed removed

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