fakedri_drv.c revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @file
* VBox OpenGL DRI driver functions
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* you can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
#define _GNU_SOURCE 1
#include "cr_error.h"
#include "cr_gl.h"
#include "cr_mem.h"
#include "stub.h"
#include "fakedri_drv.h"
#include "dri_glx.h"
#include "iprt/mem.h"
#include "iprt/err.h"
#include <dlfcn.h>
#include <elf.h>
#include <unistd.h>
/** X server message type definitions. */
typedef enum {
X_PROBED, /* Value was probed */
X_CONFIG, /* Value was given in the config file */
X_DEFAULT, /* Value is a default */
X_CMDLINE, /* Value was given on the command line */
X_NOTICE, /* Notice */
X_ERROR, /* Error message */
X_WARNING, /* Warning message */
X_INFO, /* Informational message */
X_NONE, /* No prefix */
X_NOT_IMPLEMENTED, /* Not implemented */
X_UNKNOWN = -1 /* unknown -- this must always be last */
} MessageType;
#define VBOX_NO_MESA_PATCH_REPORTS
//#define DEBUG_DRI_CALLS
//@todo this could be different...
#ifdef RT_ARCH_AMD64
# define DRI_DEFAULT_DRIVER_DIR "/usr/lib64/dri:/usr/lib/dri:/usr/lib/x86_64-linux-gnu/dri"
# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
#else
# define DRI_DEFAULT_DRIVER_DIR "/usr/lib/dri:/usr/lib/i386-linux-gnu/dri"
# define DRI_XORG_DRV_DIR "/usr/lib/xorg/modules/drivers/"
#endif
#ifdef DEBUG_DRI_CALLS
#define SWDRI_SHOWNAME(pext, func) \
crDebug("SWDRI: sc %s->%s", #pext, #func)
#else
#define SWDRI_SHOWNAME(pext, func)
#endif
#define SWDRI_SAFECALL(pext, func, ...) \
SWDRI_SHOWNAME(pext, func); \
if (pext && pext->func){ \
(*pext->func)(__VA_ARGS__); \
} else { \
crDebug("swcore_call NULL for "#func); \
}
#define SWDRI_SAFERET(pext, func, ...) \
SWDRI_SHOWNAME(pext, func); \
if (pext && pext->func){ \
return (*pext->func)(__VA_ARGS__); \
} else { \
crDebug("swcore_call NULL for "#func); \
return 0; \
}
#define SWDRI_SAFERET_CORE(func, ...) SWDRI_SAFERET(gpSwDriCoreExternsion, func, __VA_ARGS__)
#define SWDRI_SAFECALL_CORE(func, ...) SWDRI_SAFECALL(gpSwDriCoreExternsion, func, __VA_ARGS__)
#define SWDRI_SAFERET_SWRAST(func, ...) SWDRI_SAFERET(gpSwDriSwrastExtension, func, __VA_ARGS__)
#define SWDRI_SAFECALL_SWRAST(func, ...) SWDRI_SAFECALL(gpSwDriSwrastExtension, func, __VA_ARGS__)
#ifndef PAGESIZE
#define PAGESIZE 4096
#endif
#ifdef RT_ARCH_AMD64
# define DRI_ELFSYM Elf64_Sym
#else
# define DRI_ELFSYM Elf32_Sym
#endif
#ifdef RT_ARCH_AMD64
typedef struct _FAKEDRI_PatchNode
{
const char* psFuncName;
void *pDstStart, *pDstEnd;
const void *pSrcStart, *pSrcEnd;
struct _FAKEDRI_PatchNode *pNext;
} FAKEDRI_PatchNode;
static FAKEDRI_PatchNode *g_pFreeList=NULL, *g_pRepatchList=NULL;
#endif
static struct _glapi_table* vbox_glapi_table = NULL;
fakedri_glxapi_table glxim;
static const __DRIextension **gppSwDriExternsion = NULL;
static const __DRIcoreExtension *gpSwDriCoreExternsion = NULL;
static const __DRIswrastExtension *gpSwDriSwrastExtension = NULL;
extern const __DRIextension * __driDriverExtensions[];
#define VBOX_SET_MESA_FUNC(table, name, func) \
if (_glapi_get_proc_offset(name)>=0) SET_by_offset(table, _glapi_get_proc_offset(name), func); \
else crWarning("%s not found in mesa table", name)
#define GLAPI_ENTRY(Func) VBOX_SET_MESA_FUNC(vbox_glapi_table, "gl"#Func, cr_gl##Func);
static void
vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd);
static void
vboxPatchMesaGLAPITable()
{
void *pGLTable;
pGLTable = (void *)_glapi_get_dispatch();
vbox_glapi_table = crAlloc(_glapi_get_dispatch_table_size() * sizeof (void *));
if (!vbox_glapi_table)
{
crError("Not enough memory to allocate dispatch table");
}
crMemcpy(vbox_glapi_table, pGLTable, _glapi_get_dispatch_table_size() * sizeof (void *));
#include "fakedri_glfuncsList.h"
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glBlendEquationSeparateEXT", cr_glBlendEquationSeparate);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glSampleMaskSGIS", cr_glSampleMaskEXT);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glSamplePatternSGIS", cr_glSamplePatternEXT);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2dMESA", cr_glWindowPos2d);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2dvMESA", cr_glWindowPos2dv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2fMESA", cr_glWindowPos2f);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2fvMESA", cr_glWindowPos2fv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2iMESA", cr_glWindowPos2i);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2ivMESA", cr_glWindowPos2iv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2sMESA", cr_glWindowPos2s);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos2svMESA", cr_glWindowPos2sv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3dMESA", cr_glWindowPos3d);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3dvMESA", cr_glWindowPos3dv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3fMESA", cr_glWindowPos3f);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3fvMESA", cr_glWindowPos3fv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3iMESA", cr_glWindowPos3i);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3ivMESA", cr_glWindowPos3iv);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3sMESA", cr_glWindowPos3s);
VBOX_SET_MESA_FUNC(vbox_glapi_table, "glWindowPos3svMESA", cr_glWindowPos3sv);
_glapi_set_dispatch(vbox_glapi_table);
};
#undef GLAPI_ENTRY
#define GLXAPI_ENTRY(Func) pGLXTable->Func = VBOXGLXTAG(glX##Func);
static void
vboxFillGLXAPITable(fakedri_glxapi_table *pGLXTable)
{
#include "fakedri_glxfuncsList.h"
}
#undef GLXAPI_ENTRY
static void
vboxApplyPatch(const char* psFuncName, void *pDst, const void *pSrc, unsigned long size)
{
void *alPatch;
int rv;
/* Get aligned start address we're going to patch*/
alPatch = (void*) ((uintptr_t)pDst & ~(uintptr_t)(PAGESIZE-1));
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("MProtecting: %p, %li", alPatch, pDst-alPatch+size);
#endif
/* Get write access to mesa functions */
rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_WRITE|RTMEM_PROT_EXEC);
if (RT_FAILURE(rv))
{
crError("mprotect failed with %x (%s)", rv, psFuncName);
}
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Writing %li bytes to %p from %p", size, pDst, pSrc);
#endif
crMemcpy(pDst, pSrc, size);
/*@todo Restore the protection, probably have to check what was it before us...*/
rv = RTMemProtect(alPatch, pDst-alPatch+size, RTMEM_PROT_READ|RTMEM_PROT_EXEC);
if (RT_FAILURE(rv))
{
crError("mprotect2 failed with %x (%s)", rv, psFuncName);
}
}
#define FAKEDRI_JMP64_PATCH_SIZE 13
static void
vboxPatchMesaExport(const char* psFuncName, const void *pStart, const void *pEnd)
{
Dl_info dlip;
DRI_ELFSYM* sym=0;
int rv;
void *alPatch;
void *pMesaEntry;
char patch[FAKEDRI_JMP64_PATCH_SIZE];
void *shift;
int ignore_size=false;
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("\nvboxPatchMesaExport: %s", psFuncName);
#endif
pMesaEntry = dlsym(RTLD_DEFAULT, psFuncName);
if (!pMesaEntry)
{
crDebug("%s not defined in current scope, are we being loaded by mesa's libGL.so?", psFuncName);
return;
}
rv = dladdr1(pMesaEntry, &dlip, (void**)&sym, RTLD_DL_SYMENT);
if (!rv || !sym)
{
crError("Failed to get size for %p(%s)", pMesaEntry, psFuncName);
return;
}
#if VBOX_OGL_GLX_USE_CSTUBS
{
Dl_info dlip1;
DRI_ELFSYM* sym1=0;
int rv;
rv = dladdr1(pStart, &dlip1, (void**)&sym1, RTLD_DL_SYMENT);
if (!rv || !sym1)
{
crError("Failed to get size for vbox %p", pStart);
return;
}
pEnd = pStart + sym1->st_size;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("VBox Entry: %p, start: %p(%s:%s), size: %li", pStart, dlip1.dli_saddr, dlip1.dli_fname, dlip1.dli_sname, sym1->st_size);
# endif
}
#endif
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Mesa Entry: %p, start: %p(%s:%s), size: %li", pMesaEntry, dlip.dli_saddr, dlip.dli_fname, dlip.dli_sname, sym->st_size);
crDebug("Vbox code: start: %p, end %p, size: %li", pStart, pEnd, pEnd-pStart);
#endif
#ifndef VBOX_OGL_GLX_USE_CSTUBS
if (sym->st_size<(pEnd-pStart))
#endif
{
#ifdef RT_ARCH_AMD64
int64_t offset;
#endif
/* Try to insert 5 bytes jmp/jmpq to our stub code */
if (sym->st_size<5)
{
/*@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.*/
if (!crStrcmp(psFuncName, "glXDestroyContext") || !crStrcmp(psFuncName, "glXFreeContextEXT"))
{
if (((unsigned char*)dlip.dli_saddr)[0]==0xEB)
{
/*it's a rel8 jmp, so we're going to patch the place it targets instead of jmp itself*/
dlip.dli_saddr = (void*) ((intptr_t)dlip.dli_saddr + ((char*)dlip.dli_saddr)[1] + 2);
ignore_size = true;
}
else
{
crError("Can't patch size is too small.(%s)", psFuncName);
return;
}
}
else if (!crStrcmp(psFuncName, "glXCreateGLXPixmapMESA"))
{
/*@todo it's just a return 0, which we're fine with for now*/
return;
}
else
{
crError("Can't patch size is too small.(%s)", psFuncName);
return;
}
}
shift = (void*)((intptr_t)pStart-((intptr_t)dlip.dli_saddr+5));
#ifdef RT_ARCH_AMD64
offset = (intptr_t)shift;
if (offset>INT32_MAX || offset<INT32_MIN)
{
/*try to insert 64bit abs jmp*/
if (sym->st_size>=FAKEDRI_JMP64_PATCH_SIZE || ignore_size)
{
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Inserting movq/jmp instead");
# endif
/*add 64bit abs jmp*/
patch[0] = 0x49; /*movq %r11,imm64*/
patch[1] = 0xBB;
crMemcpy(&patch[2], &pStart, 8);
patch[10] = 0x41; /*jmp *%r11*/
patch[11] = 0xFF;
patch[12] = 0xE3;
pStart = &patch[0];
pEnd = &patch[FAKEDRI_JMP64_PATCH_SIZE];
}
else
{
FAKEDRI_PatchNode *pNode;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Can't patch offset is too big. Pushing for 2nd pass(%s)", psFuncName);
# endif
/*Add patch node to repatch with chain jmps in 2nd pass*/
pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
if (!pNode)
{
crError("Not enough memory.");
return;
}
pNode->psFuncName = psFuncName;
pNode->pDstStart = dlip.dli_saddr;
pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
pNode->pSrcStart = pStart;
pNode->pSrcEnd = pEnd;
pNode->pNext = g_pRepatchList;
g_pRepatchList = pNode;
return;
}
}
else
#endif
{
#ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Inserting jmp[q] with shift %p instead", shift);
#endif
patch[0] = 0xE9;
crMemcpy(&patch[1], &shift, 4);
pStart = &patch[0];
pEnd = &patch[5];
}
}
vboxApplyPatch(psFuncName, dlip.dli_saddr, pStart, pEnd-pStart);
#ifdef RT_ARCH_AMD64
/*Add rest of mesa function body to free list*/
if (sym->st_size-(pEnd-pStart)>=FAKEDRI_JMP64_PATCH_SIZE)
{
FAKEDRI_PatchNode *pNode = (FAKEDRI_PatchNode *)crAlloc(sizeof(FAKEDRI_PatchNode));
if (pNode)
{
pNode->psFuncName = psFuncName;
pNode->pDstStart = dlip.dli_saddr+(pEnd-pStart);
pNode->pDstEnd = dlip.dli_saddr+sym->st_size;
pNode->pSrcStart = dlip.dli_saddr;
pNode->pSrcEnd = NULL;
pNode->pNext = g_pFreeList;
g_pFreeList = pNode;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Added free node %s, func start=%p, free start=%p, size=%#lx",
psFuncName, pNode->pSrcStart, pNode->pDstStart, pNode->pDstEnd-pNode->pDstStart);
# endif
}
}
#endif
}
#ifdef RT_ARCH_AMD64
static void
vboxRepatchMesaExports(void)
{
FAKEDRI_PatchNode *pFreeNode, *pPatchNode;
int64_t offset;
char patch[FAKEDRI_JMP64_PATCH_SIZE];
pPatchNode = g_pRepatchList;
while (pPatchNode)
{
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("\nvboxRepatchMesaExports %s", pPatchNode->psFuncName);
# endif
/*find free place in mesa functions, to place 64bit jump to our stub code*/
pFreeNode = g_pFreeList;
while (pFreeNode)
{
if (pFreeNode->pDstEnd-pFreeNode->pDstStart>=FAKEDRI_JMP64_PATCH_SIZE)
{
offset = ((intptr_t)pFreeNode->pDstStart-((intptr_t)pPatchNode->pDstStart+5));
if (offset<=INT32_MAX && offset>=INT32_MIN)
{
break;
}
}
pFreeNode=pFreeNode->pNext;
}
if (!pFreeNode)
{
crError("Failed to find free space, to place repatch for %s.", pPatchNode->psFuncName);
return;
}
/*add 32bit rel jmp, from mesa orginal function to free space in other mesa function*/
patch[0] = 0xE9;
crMemcpy(&patch[1], &offset, 4);
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Adding jmp from mesa %s to mesa %s+%#lx", pPatchNode->psFuncName, pFreeNode->psFuncName,
pFreeNode->pDstStart-pFreeNode->pSrcStart);
# endif
vboxApplyPatch(pPatchNode->psFuncName, pPatchNode->pDstStart, &patch[0], 5);
/*add 64bit abs jmp, from free space to our stub code*/
patch[0] = 0x49; /*movq %r11,imm64*/
patch[1] = 0xBB;
crMemcpy(&patch[2], &pPatchNode->pSrcStart, 8);
patch[10] = 0x41; /*jmp *%r11*/
patch[11] = 0xFF;
patch[12] = 0xE3;
# ifndef VBOX_NO_MESA_PATCH_REPORTS
crDebug("Adding jmp from mesa %s+%#lx to vbox %s", pFreeNode->psFuncName, pFreeNode->pDstStart-pFreeNode->pSrcStart,
pPatchNode->psFuncName);
# endif
vboxApplyPatch(pFreeNode->psFuncName, pFreeNode->pDstStart, &patch[0], FAKEDRI_JMP64_PATCH_SIZE);
/*mark this space as used*/
pFreeNode->pDstStart = pFreeNode->pDstStart+FAKEDRI_JMP64_PATCH_SIZE;
pPatchNode = pPatchNode->pNext;
}
}
static void
vboxFakeDriFreeList(FAKEDRI_PatchNode *pList)
{
FAKEDRI_PatchNode *pNode;
while (pList)
{
pNode=pList;
pList=pNode->pNext;
crFree(pNode);
}
}
#endif
#ifdef VBOX_OGL_GLX_USE_CSTUBS
static void
# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, NULL);
vboxPatchMesaExports()
#else
static void
# define GLXAPI_ENTRY(Func) vboxPatchMesaExport("glX"#Func, &vbox_glX##Func, &vbox_glX##Func##_EndProc);
vboxPatchMesaExports()
#endif
{
crDebug("Patching mesa glx entries");
#include "fakedri_glxfuncsList.h"
#ifdef RT_ARCH_AMD64
vboxRepatchMesaExports();
vboxFakeDriFreeList(g_pRepatchList);
g_pRepatchList = NULL;
vboxFakeDriFreeList(g_pFreeList);
g_pFreeList = NULL;
#endif
}
#undef GLXAPI_ENTRY
bool vbox_load_sw_dri()
{
const char *libPaths, *p, *next;;
char realDriverName[200];
void *handle;
int len, i;
/*code from Mesa-7.2/src/glx/x11/dri_common.c:driOpenDriver*/
libPaths = NULL;
if (geteuid() == getuid()) {
/* don't allow setuid apps to use LIBGL_DRIVERS_PATH */
libPaths = getenv("LIBGL_DRIVERS_PATH");
if (!libPaths)
libPaths = getenv("LIBGL_DRIVERS_DIR"); /* deprecated */
}
if (libPaths == NULL)
libPaths = DRI_DEFAULT_DRIVER_DIR;
handle = NULL;
for (p = libPaths; *p; p = next)
{
next = strchr(p, ':');
if (next == NULL)
{
len = strlen(p);
next = p + len;
}
else
{
len = next - p;
next++;
}
snprintf(realDriverName, sizeof realDriverName, "%.*s/%s_dri.so", len, p, "swrast");
crDebug("trying %s", realDriverName);
handle = dlopen(realDriverName, RTLD_NOW | RTLD_LOCAL);
if (handle) break;
}
/*end code*/
if (handle) gppSwDriExternsion = dlsym(handle, "__driDriverExtensions");
if (!gppSwDriExternsion)
{
crDebug("%s doesn't export __driDriverExtensions", realDriverName);
return false;
}
crDebug("loaded %s", realDriverName);
for (i = 0; gppSwDriExternsion[i]; i++)
{
if (strcmp(gppSwDriExternsion[i]->name, __DRI_CORE) == 0)
gpSwDriCoreExternsion = (__DRIcoreExtension *) gppSwDriExternsion[i];
if (strcmp(gppSwDriExternsion[i]->name, __DRI_SWRAST) == 0)
gpSwDriSwrastExtension = (__DRIswrastExtension *) gppSwDriExternsion[i];
}
return gpSwDriCoreExternsion && gpSwDriSwrastExtension;
}
void __attribute__ ((constructor)) vbox_install_into_mesa(void)
{
{
#ifdef _X_ATTRIBUTE_PRINTF
void (*pxf86Msg)(MessageType type, const char *format, ...) _X_ATTRIBUTE_PRINTF(2,3);
#else
void (*pxf86Msg)(MessageType type, const char *format, ...) _printf_attribute(2,3);
#endif
pxf86Msg = dlsym(RTLD_DEFAULT, "xf86Msg");
if (pxf86Msg)
{
pxf86Msg(X_INFO, "Next line is added to allow vboxvideo_drv.so to appear as whitelisted driver\n");
pxf86Msg(X_INFO, "The file referenced, is *NOT* loaded\n");
pxf86Msg(X_INFO, "Loading %s/ati_drv.so\n", DRI_XORG_DRV_DIR);
/* we're failing to proxy software dri driver calls for certain xservers, so just make sure we're unloaded for now */
__driDriverExtensions[0] = NULL;
return;
}
}
if (!stubInit())
{
crDebug("vboxdriInitScreen: stubInit failed");
return;
}
/* Load swrast_dri.so to proxy dri related calls there. */
if (!vbox_load_sw_dri())
{
crDebug("vboxdriInitScreen: vbox_load_sw_dri failed...going to fail badly");
return;
}
/* Handle gl api.
* In the end application call would look like this:
* app call glFoo->(mesa asm dispatch stub)->cr_glFoo(vbox asm dispatch stub)->SPU Foo function(packspuFoo or alike)
* Note, we don't need to install extension functions via _glapi_add_dispatch, because we'd override glXGetProcAddress.
*/
/* Mesa's dispatch table is different across library versions, have to modify mesa's table using offset info functions*/
vboxPatchMesaGLAPITable();
/* Handle glx api.
* In the end application call would look like this:
* app call glxFoo->(mesa asm dispatch stub patched with vbox_glXFoo:jmp glxim[Foo's index])->VBOXGLXTAG(glxFoo)
*/
/* Fill structure used by our assembly stubs */
vboxFillGLXAPITable(&glxim);
/* Now patch functions exported by libGL.so */
vboxPatchMesaExports();
}
/*
* @todo we're missing first glx related call from the client application.
* Luckily, this doesn't add much problems, except for some cases.
*/
/* __DRIcoreExtension */
static __DRIscreen *
vboxdriCreateNewScreen(int screen, int fd, unsigned int sarea_handle,
const __DRIextension **extensions, const __DRIconfig ***driverConfigs,
void *loaderPrivate)
{
(void) fd;
(void) sarea_handle;
SWDRI_SAFERET_SWRAST(createNewScreen, screen, extensions, driverConfigs, loaderPrivate);
}
static void
vboxdriDestroyScreen(__DRIscreen *screen)
{
SWDRI_SAFECALL_CORE(destroyScreen, screen);
}
static const __DRIextension **
vboxdriGetExtensions(__DRIscreen *screen)
{
SWDRI_SAFERET_CORE(getExtensions, screen);
}
static int
vboxdriGetConfigAttrib(const __DRIconfig *config,
unsigned int attrib,
unsigned int *value)
{
SWDRI_SAFERET_CORE(getConfigAttrib, config, attrib, value);
}
static int
vboxdriIndexConfigAttrib(const __DRIconfig *config, int index,
unsigned int *attrib, unsigned int *value)
{
SWDRI_SAFERET_CORE(indexConfigAttrib, config, index, attrib, value);
}
static __DRIdrawable *
vboxdriCreateNewDrawable(__DRIscreen *screen,
const __DRIconfig *config,
unsigned int drawable_id,
unsigned int head,
void *loaderPrivate)
{
(void) drawable_id;
(void) head;
SWDRI_SAFERET_SWRAST(createNewDrawable, screen, config, loaderPrivate);
}
static void
vboxdriDestroyDrawable(__DRIdrawable *drawable)
{
SWDRI_SAFECALL_CORE(destroyDrawable, drawable);
}
static void
vboxdriSwapBuffers(__DRIdrawable *drawable)
{
SWDRI_SAFECALL_CORE(swapBuffers, drawable);
}
static __DRIcontext *
vboxdriCreateNewContext(__DRIscreen *screen,
const __DRIconfig *config,
__DRIcontext *shared,
void *loaderPrivate)
{
SWDRI_SAFERET_CORE(createNewContext, screen, config, shared, loaderPrivate);
}
static int
vboxdriCopyContext(__DRIcontext *dest,
__DRIcontext *src,
unsigned long mask)
{
SWDRI_SAFERET_CORE(copyContext, dest, src, mask);
}
static void
vboxdriDestroyContext(__DRIcontext *context)
{
SWDRI_SAFECALL_CORE(destroyContext, context);
}
static int
vboxdriBindContext(__DRIcontext *ctx,
__DRIdrawable *pdraw,
__DRIdrawable *pread)
{
SWDRI_SAFERET_CORE(bindContext, ctx, pdraw, pread);
}
static int
vboxdriUnbindContext(__DRIcontext *ctx)
{
SWDRI_SAFERET_CORE(unbindContext, ctx)
}
/* __DRIlegacyExtension */
static __DRIscreen *
vboxdriCreateNewScreen_Legacy(int scrn,
const __DRIversion *ddx_version,
const __DRIversion *dri_version,
const __DRIversion *drm_version,
const __DRIframebuffer *frame_buffer,
drmAddress pSAREA, int fd,
const __DRIextension **extensions,
const __DRIconfig ***driver_modes,
void *loaderPrivate)
{
(void) ddx_version;
(void) dri_version;
(void) frame_buffer;
(void) pSAREA;
(void) fd;
SWDRI_SAFERET_SWRAST(createNewScreen, scrn, extensions, driver_modes, loaderPrivate);
}
static __DRIdrawable *
vboxdriCreateNewDrawable_Legacy(__DRIscreen *psp, const __DRIconfig *config,
drm_drawable_t hwDrawable, int renderType,
const int *attrs, void *data)
{
(void) hwDrawable;
(void) renderType;
(void) attrs;
(void) data;
SWDRI_SAFERET_SWRAST(createNewDrawable, psp, config, data);
}
static __DRIcontext *
vboxdriCreateNewContext_Legacy(__DRIscreen *psp, const __DRIconfig *config,
int render_type, __DRIcontext *shared,
drm_context_t hwContext, void *data)
{
(void) render_type;
(void) hwContext;
return vboxdriCreateNewContext(psp, config, shared, data);
}
static const __DRIlegacyExtension vboxdriLegacyExtension = {
{ __DRI_LEGACY, __DRI_LEGACY_VERSION },
vboxdriCreateNewScreen_Legacy,
vboxdriCreateNewDrawable_Legacy,
vboxdriCreateNewContext_Legacy
};
static const __DRIcoreExtension vboxdriCoreExtension = {
{ __DRI_CORE, __DRI_CORE_VERSION },
vboxdriCreateNewScreen, /* driCreateNewScreen */
vboxdriDestroyScreen,
vboxdriGetExtensions,
vboxdriGetConfigAttrib,
vboxdriIndexConfigAttrib,
vboxdriCreateNewDrawable, /* driCreateNewDrawable */
vboxdriDestroyDrawable,
vboxdriSwapBuffers,
vboxdriCreateNewContext,
vboxdriCopyContext,
vboxdriDestroyContext,
vboxdriBindContext,
vboxdriUnbindContext
};
/* This structure is used by dri_util from mesa, don't rename it! */
DECLEXPORT(const __DRIextension *) __driDriverExtensions[] = {
&vboxdriLegacyExtension.base,
&vboxdriCoreExtension.base,
NULL
};