gallium: Update the dri2 state tracker to support dri1.

Signed-off-by: Thomas Hellstrom <thellstrom-at-vmware-dot-com>
This commit is contained in:
Thomas Hellstrom
2009-04-28 11:49:39 +02:00
parent a70c4f352e
commit ca1f5f7e6c
6 changed files with 506 additions and 54 deletions

View File

@@ -32,9 +32,8 @@
#include "dri_screen.h"
#include "dri_drawable.h"
#include "state_tracker/drm_api.h"
#include "state_tracker/dri1_api.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_context.h"
#include "pipe/p_context.h"
@@ -44,6 +43,7 @@
#include "util/u_memory.h"
GLboolean
dri_create_context(const __GLcontextModes *visual,
__DRIcontextPrivate *cPriv,
@@ -65,6 +65,9 @@ dri_create_context(const __GLcontextModes *visual,
cPriv->driverPrivate = ctx;
ctx->cPriv = cPriv;
ctx->sPriv = sPriv;
ctx->lock = screen->drmLock;
ctx->d_stamp = -1;
ctx->r_stamp = -1;
driParseConfigFiles(&ctx->optionCache,
&screen->optionCache,
@@ -126,13 +129,22 @@ dri_destroy_context(__DRIcontextPrivate *cPriv)
GLboolean
dri_unbind_context(__DRIcontextPrivate *cPriv)
{
struct dri_context *ctx = dri_context(cPriv);
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
/* XXX make_current(NULL)? */
if (cPriv) {
struct dri_context *ctx = dri_context(cPriv);
if (--ctx->bind_count == 0) {
GET_CURRENT_CONTEXT(curGLCtx);
if (ctx->st == curGLCtx->st) {
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
st_make_current(NULL, NULL, NULL);
}
}
}
return GL_TRUE;
}
GLboolean
dri_make_current(__DRIcontextPrivate *cPriv,
__DRIdrawablePrivate *driDrawPriv,
@@ -143,23 +155,32 @@ dri_make_current(__DRIcontextPrivate *cPriv,
struct dri_screen *screen = dri_screen(cPriv->driScreenPriv);
struct dri_drawable *draw = dri_drawable(driDrawPriv);
struct dri_drawable *read = dri_drawable(driReadPriv);
GET_CURRENT_CONTEXT(oldGLCtx);
if (oldGLCtx && oldGLCtx->st != ctx->st)
st_flush(oldGLCtx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
++ctx->bind_count;
/* This is for situations in which we need a rendering context but
* there may not be any currently bound.
*/
screen->dummyContext = ctx;
st_make_current(ctx->st,
draw->stfb,
read->stfb);
/* used in dri_flush_frontbuffer */
ctx->dPriv = driDrawPriv;
ctx->rPriv = driReadPriv;
if (driDrawPriv)
dri_get_buffers(driDrawPriv);
if (driDrawPriv != driReadPriv && driReadPriv)
dri_get_buffers(driReadPriv);
st_make_current(ctx->st, draw->stfb, read->stfb);
if (__dri1_api_hooks) {
dri1_update_drawables(ctx, draw, read);
} else {
if (driDrawPriv)
dri_get_buffers(driDrawPriv);
if (driDrawPriv != driReadPriv && driReadPriv)
dri_get_buffers(driReadPriv);
}
} else {
st_make_current(NULL, NULL, NULL);
}
@@ -167,4 +188,44 @@ dri_make_current(__DRIcontextPrivate *cPriv,
return GL_TRUE;
}
static void
st_dri_lock(struct pipe_context *pipe)
{
dri_lock((struct dri_context *) pipe->priv);
}
static void
st_dri_unlock(struct pipe_context *pipe)
{
dri_unlock((struct dri_context *) pipe->priv);
}
static boolean
st_dri_is_locked(struct pipe_context *pipe)
{
return ((struct dri_context *) pipe->priv)->isLocked;
}
static boolean
st_dri_lost_lock(struct pipe_context *pipe)
{
return ((struct dri_context *) pipe->priv)->wsLostLock;
}
static void
st_dri_clear_lost_lock(struct pipe_context *pipe)
{
((struct dri_context *) pipe->priv)->wsLostLock = FALSE;
}
struct dri1_api_lock_funcs dri1_lf =
{
.lock = st_dri_lock,
.unlock = st_dri_unlock,
.is_locked = st_dri_is_locked,
.is_lock_lost = st_dri_lost_lock,
.clear_lost_lock = st_dri_clear_lost_lock
};
/* vim: set sw=3 ts=8 sts=3 expandtab: */

View File

@@ -42,32 +42,64 @@ struct pipe_fence;
struct st_context;
struct dri_drawable;
struct dri_context
{
/* dri */
__DRIscreenPrivate *sPriv;
__DRIcontextPrivate *cPriv;
__DRIdrawablePrivate *dPriv;
__DRIdrawablePrivate *rPriv;
driOptionCache optionCache;
unsigned int d_stamp;
unsigned int r_stamp;
drmLock *lock;
boolean isLocked;
boolean stLostLock;
boolean wsLostLock;
unsigned int bind_count;
/* gallium */
struct st_context *st;
struct pipe_context *pipe;
};
static INLINE struct dri_context *
dri_context(__DRIcontextPrivate *driContextPriv)
{
return (struct dri_context *) driContextPriv->driverPrivate;
}
static INLINE void
dri_lock(struct dri_context *ctx)
{
drm_context_t hw_context = ctx->cPriv->hHWContext;
char ret = 0;
DRM_CAS(ctx->lock, hw_context, DRM_LOCK_HELD | hw_context, ret);
if (ret) {
drmGetLock(ctx->sPriv->fd, hw_context, 0);
ctx->stLostLock = TRUE;
ctx->wsLostLock = TRUE;
}
ctx->isLocked = TRUE;
}
static INLINE void
dri_unlock(struct dri_context *ctx)
{
ctx->isLocked = FALSE;
DRM_UNLOCK(ctx->sPriv->fd, ctx->lock, ctx->cPriv->hHWContext);
}
/***********************************************************************
* dri_context.c
*/
extern struct dri1_api_lock_funcs dri1_lf;
void
dri_destroy_context(__DRIcontextPrivate * driContextPriv);

View File

@@ -37,6 +37,7 @@
#include "pipe/p_screen.h"
#include "pipe/p_inlines.h"
#include "state_tracker/drm_api.h"
#include "state_tracker/dri1_api.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_context.h"
#include "state_tracker/st_cb_fbo.h"
@@ -207,22 +208,6 @@ dri_flush_frontbuffer(struct pipe_screen *screen,
}
void
dri_swap_buffers(__DRIdrawablePrivate * dPriv)
{
/* not needed for dri2 */
assert(0);
}
void
dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
{
/* not needed for dri2 */
assert(0);
}
/**
* This is called when we need to set up GL rendering to a new X window.
*/
@@ -305,21 +290,322 @@ dri_create_buffer(__DRIscreenPrivate *sPriv,
drawable->attachments[i++] = __DRI_BUFFER_STENCIL;
drawable->num_attachments = i;
drawable->desired_fences = 2;
return GL_TRUE;
fail:
FREE(drawable);
return GL_FALSE;
}
static struct pipe_fence_handle *
dri_swap_fences_pop_front(struct dri_drawable *draw)
{
struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
struct pipe_fence_handle *fence = NULL;
if (draw->cur_fences >= draw->desired_fences) {
screen->fence_reference(screen, &fence, draw->swap_fences[draw->tail]);
screen->fence_reference(screen, &draw->swap_fences[draw->tail++], NULL);
--draw->cur_fences;
draw->tail &= DRI_SWAP_FENCES_MASK;
}
return fence;
}
static void
dri_swap_fences_push_back(struct dri_drawable *draw,
struct pipe_fence_handle *fence)
{
struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
if (!fence)
return;
if (draw->cur_fences < DRI_SWAP_FENCES_MAX) {
draw->cur_fences++;
screen->fence_reference(screen, &draw->swap_fences[draw->head++], fence);
draw->head &= DRI_SWAP_FENCES_MASK;
}
}
void
dri_destroy_buffer(__DRIdrawablePrivate *dPriv)
{
struct dri_drawable *drawable = dri_drawable(dPriv);
struct pipe_fence_handle *fence;
struct pipe_screen *screen = dri_screen(drawable->sPriv)->pipe_screen;
st_unreference_framebuffer(drawable->stfb);
drawable->desired_fences = 0;
while(drawable->cur_fences) {
fence = dri_swap_fences_pop_front(drawable);
screen->fence_reference(screen, &fence, NULL);
}
FREE(drawable);
}
static void
dri1_update_drawables_locked(struct dri_context *ctx,
__DRIdrawablePrivate *driDrawPriv,
__DRIdrawablePrivate *driReadPriv)
{
if (ctx->stLostLock) {
ctx->stLostLock = FALSE;
if (driDrawPriv == driReadPriv)
DRI_VALIDATE_DRAWABLE_INFO(ctx->sPriv, driDrawPriv);
else
DRI_VALIDATE_TWO_DRAWABLES_INFO(ctx->sPriv, driDrawPriv, driReadPriv);
}
}
/**
* This ensures all contexts which binds to a drawable picks up the
* drawable change and signals new buffer state.
* Calling st_resize_framebuffer for each context may seem like overkill,
* but no new buffers will actually be allocated if the dimensions doesn't
* change.
*/
static void
dri1_propagate_drawable_change(struct dri_context *ctx)
{
__DRIdrawablePrivate *dPriv = ctx->dPriv;
__DRIdrawablePrivate *rPriv = ctx->rPriv;
boolean flushed = FALSE;
if (dPriv && ctx->d_stamp != dPriv->lastStamp) {
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
flushed = TRUE;
ctx->d_stamp = dPriv->lastStamp;
st_resize_framebuffer(dri_drawable(dPriv)->stfb, dPriv->w, dPriv->h);
}
if (rPriv && dPriv != rPriv && ctx->r_stamp != rPriv->lastStamp) {
if (!flushed)
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
ctx->r_stamp = rPriv->lastStamp;
st_resize_framebuffer(dri_drawable(rPriv)->stfb, rPriv->w, rPriv->h);
} else if (rPriv && dPriv == rPriv) {
ctx->r_stamp = ctx->d_stamp;
}
}
void
dri1_update_drawables(struct dri_context *ctx,
struct dri_drawable *draw,
struct dri_drawable *read)
{
dri_lock(ctx);
dri1_update_drawables_locked(ctx, draw->dPriv, read->dPriv);
dri_unlock(ctx);
dri1_propagate_drawable_change(ctx);
}
static INLINE boolean
dri1_intersect_src_bbox(struct drm_clip_rect *dst,
int dst_x,
int dst_y,
const struct drm_clip_rect *src,
const struct drm_clip_rect *bbox)
{
int xy1;
int xy2;
xy1 = ((int) src->x1 > (int) bbox->x1 + dst_x) ? src->x1 :
(int) bbox->x1 + dst_x;
xy2 = ((int) src->x2 < (int) bbox->x2 + dst_x) ? src->x2 :
(int) bbox->x2 + dst_x;
if (xy1 >= xy2 || xy1 < 0)
return FALSE;
dst->x1 = xy1;
dst->x2 = xy2;
xy1 = ((int) src->y1 > (int) bbox->y1 + dst_x) ? src->y1 :
(int) bbox->y1 + dst_x;
xy2 = ((int) src->y2 < (int) bbox->y2 + dst_x) ? src->y2 :
(int) bbox->y2 + dst_x;
if (xy1 >= xy2 || xy1 < 0)
return FALSE;
dst->y1 = xy1;
dst->y2 = xy2;
return TRUE;
}
static void
dri1_swap_copy(struct dri_context *ctx,
struct pipe_surface *dst,
struct pipe_surface *src,
__DRIdrawablePrivate *dPriv,
const struct drm_clip_rect *bbox)
{
struct pipe_context *pipe = ctx->pipe;
struct drm_clip_rect clip;
struct drm_clip_rect *cur;
int i;
cur = dPriv->pClipRects;
for (i=0; i<dPriv->numClipRects; ++i) {
if (dri1_intersect_src_bbox(&clip, dPriv->x, dPriv->y, cur++, bbox))
pipe->surface_copy(pipe, dst, clip.x1, clip.y1,
src,
(int) clip.x1 - dPriv->x,
(int) clip.y1 - dPriv->y,
clip.x2 - clip.x1,
clip.y2 - clip.y1);
}
}
static void
dri1_copy_to_front(struct dri_context *ctx,
struct pipe_surface *surf,
__DRIdrawablePrivate *dPriv,
const struct drm_clip_rect *sub_box,
struct pipe_fence_handle **fence)
{
struct pipe_context *pipe = ctx->pipe;
boolean save_lost_lock;
uint cur_w;
uint cur_h;
struct drm_clip_rect bbox;
boolean visible = TRUE;
*fence = NULL;
dri_lock(ctx);
save_lost_lock = ctx->stLostLock;
dri1_update_drawables_locked(ctx, dPriv, dPriv);
st_get_framebuffer_dimensions(dri_drawable(dPriv)->stfb, &cur_w, &cur_h);
bbox.x1 = 0;
bbox.x2 = cur_w;
bbox.y1 = 0;
bbox.y2 = cur_h;
if (sub_box)
visible = dri1_intersect_src_bbox(&bbox, 0, 0, &bbox, sub_box);
if (visible && __dri1_api_hooks->present_locked) {
__dri1_api_hooks->present_locked(pipe,
surf,
dPriv->pClipRects,
dPriv->numClipRects,
dPriv->x,
dPriv->y,
&bbox,
fence);
} else if (visible && __dri1_api_hooks->front_srf_locked) {
struct pipe_surface *front =
__dri1_api_hooks->front_srf_locked(pipe);
if (front)
dri1_swap_copy(ctx, front, surf, dPriv, &bbox);
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, fence);
}
ctx->stLostLock = save_lost_lock;
/**
* FIXME: Revisit this: Update drawables on copy_sub_buffer ?
*/
if (!sub_box)
dri1_update_drawables_locked(ctx, ctx->dPriv, ctx->rPriv);
dri_unlock(ctx);
dri1_propagate_drawable_change(ctx);
}
void
dri1_flush_frontbuffer(struct pipe_screen *screen,
struct pipe_surface *surf,
void *context_private)
{
struct dri_context *ctx = (struct dri_context *)context_private;
struct pipe_fence_handle *dummy_fence;
dri1_copy_to_front(ctx, surf, ctx->dPriv, NULL, &dummy_fence);
/**
* FIXME: Do we need swap throttling here?
*/
}
void
dri_swap_buffers(__DRIdrawablePrivate * dPriv)
{
struct dri_context *ctx;
struct pipe_surface *back_surf;
struct dri_drawable *draw = dri_drawable(dPriv);
struct pipe_screen *screen = dri_screen(draw->sPriv)->pipe_screen;
struct pipe_fence_handle *fence;
GET_CURRENT_CONTEXT(glCtx);
assert(__dri1_api_hooks != NULL);
if (!glCtx)
return; /* For now */
ctx = (struct dri_context *) glCtx->st->pipe->priv;
st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
if (back_surf) {
st_notify_swapbuffers(draw->stfb);
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
fence = dri_swap_fences_pop_front(draw);
if (fence) {
(void) screen->fence_finish(screen, fence, 0);
screen->fence_reference(screen, &fence, NULL);
}
dri1_copy_to_front(ctx, back_surf, dPriv, NULL, &fence);
dri_swap_fences_push_back(draw, fence);
screen->fence_reference(screen, &fence, NULL);
}
}
void
dri_copy_sub_buffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h)
{
struct drm_clip_rect sub_bbox;
struct dri_context *ctx;
struct pipe_surface *back_surf;
struct dri_drawable *draw = dri_drawable(dPriv);
struct pipe_fence_handle *dummy_fence;
GET_CURRENT_CONTEXT(glCtx);
assert(__dri1_api_hooks != NULL);
if (!glCtx)
return;
ctx = (struct dri_context *) glCtx->st->pipe->priv;
sub_bbox.x1 = x;
sub_bbox.x2 = x + w;
sub_bbox.y1 = y;
sub_bbox.y2 = y + h;
st_get_framebuffer_surface(draw->stfb, ST_SURFACE_BACK_LEFT, &back_surf);
if (back_surf) {
st_flush(ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL);
dri1_copy_to_front(ctx, back_surf, dPriv, &sub_bbox, &dummy_fence);
}
}
/* vim: set sw=3 ts=8 sts=3 expandtab: */

View File

@@ -31,9 +31,11 @@
#include "pipe/p_compiler.h"
struct pipe_surface;
struct pipe_fence;
struct pipe_fence_handle;
struct st_framebuffer;
#define DRI_SWAP_FENCES_MAX 8
#define DRI_SWAP_FENCES_MASK 7
struct dri_drawable
{
@@ -46,6 +48,11 @@ struct dri_drawable
/* gallium */
struct st_framebuffer *stfb;
struct pipe_fence_handle *swap_fences[DRI_SWAP_FENCES_MAX];
unsigned int head;
unsigned int tail;
unsigned int desired_fences;
unsigned int cur_fences;
};
@@ -84,6 +91,15 @@ dri_get_buffers(__DRIdrawablePrivate * dPriv);
void
dri_destroy_buffer(__DRIdrawablePrivate *dPriv);
void
dri1_update_drawables(struct dri_context *ctx,
struct dri_drawable *draw,
struct dri_drawable *read);
void
dri1_flush_frontbuffer(struct pipe_screen *screen,
struct pipe_surface *surf,
void *context_private);
#endif
/* vim: set sw=3 ts=8 sts=3 expandtab: */

View File

@@ -40,7 +40,9 @@
#include "pipe/p_context.h"
#include "pipe/p_screen.h"
#include "pipe/p_inlines.h"
#include "pipe/p_format.h"
#include "state_tracker/drm_api.h"
#include "state_tracker/dri1_api.h"
#include "state_tracker/st_public.h"
#include "state_tracker/st_cb_fbo.h"
@@ -57,7 +59,6 @@ PUBLIC const char __driConfigOptions[] =
const uint __driNConfigOptions = 3;
static const __DRIextension *dri_screen_extensions[] = {
&driReadDrawableExtension,
&driCopySubBufferExtension.base,
@@ -67,6 +68,8 @@ static const __DRIextension *dri_screen_extensions[] = {
NULL
};
struct dri1_api *__dri1_api_hooks = NULL;
static const __DRIconfig **
dri_fill_in_modes(__DRIscreenPrivate *psp,
unsigned pixel_bits, unsigned depth_bits,
@@ -139,7 +142,7 @@ dri_fill_in_modes(__DRIscreenPrivate *psp,
/**
* Get information about previous buffer swaps.
*/
int
static int
dri_get_swap_info(__DRIdrawablePrivate * dPriv,
__DRIswapInfo * sInfo)
{
@@ -151,13 +154,69 @@ dri_get_swap_info(__DRIdrawablePrivate * dPriv,
return 0;
}
static INLINE void
dri_copy_version(struct dri1_api_version *dst,
const struct __DRIversionRec *src)
{
dst->major = src->major;
dst->minor = src->minor;
dst->patch_level = src->patch;
}
/**
* NULL stub for old dri loaders
*/
const __DRIconfig **
static const __DRIconfig **
dri_init_screen(__DRIscreenPrivate *sPriv)
{
struct dri_screen *screen;
const __DRIconfig **configs;
struct dri1_create_screen_arg arg;
dri_init_extensions(NULL);
screen = CALLOC_STRUCT(dri_screen);
if (!screen)
return NULL;
screen->sPriv = sPriv;
screen->fd = sPriv->fd;
screen->drmLock = (drmLock *) &sPriv->pSAREA->lock;
sPriv->private = (void *) screen;
sPriv->extensions = dri_screen_extensions;
arg.base.mode = DRM_CREATE_DRI1;
arg.lf = &dri1_lf;
arg.ddx_info = sPriv->pDevPriv;
arg.ddx_info_size = sPriv->devPrivSize;
arg.sarea = sPriv->pSAREA;
dri_copy_version(&arg.ddx_version, &sPriv->ddx_version);
dri_copy_version(&arg.dri_version, &sPriv->dri_version);
dri_copy_version(&arg.drm_version, &sPriv->drm_version);
arg.api = NULL;
screen->pipe_screen = drm_api_hooks.create_screen
(screen->fd, &arg.base);
if (!screen->pipe_screen || !arg.api) {
debug_printf("%s: failed to create dri1 screen\n", __FUNCTION__);
goto out_no_screen;
}
__dri1_api_hooks = arg.api;
screen->pipe_screen->flush_frontbuffer = dri1_flush_frontbuffer;
driParseOptionInfo(&screen->optionCache,
__driConfigOptions,
__driNConfigOptions);
configs = dri_fill_in_modes(sPriv, sPriv->fbBPP, 24, 8, 1);
if (!configs)
goto out_no_configs;
return configs;
out_no_configs:
screen->pipe_screen->destroy(screen->pipe_screen);
out_no_screen:
FREE(screen);
return NULL;
}
@@ -167,10 +226,11 @@ dri_init_screen(__DRIscreenPrivate *sPriv)
*
* Returns the __GLcontextModes supported by this driver.
*/
const __DRIconfig **
static const __DRIconfig **
dri_init_screen2(__DRIscreenPrivate *sPriv)
{
struct dri_screen *screen;
struct drm_create_screen_arg arg;
/* Set up dispatch table to cope with all known extensions */
dri_init_extensions(NULL);
@@ -183,9 +243,9 @@ dri_init_screen2(__DRIscreenPrivate *sPriv)
screen->fd = sPriv->fd;
sPriv->private = (void *) screen;
sPriv->extensions = dri_screen_extensions;
arg.mode = DRM_CREATE_NORMAL;
screen->pipe_screen = drm_api_hooks.create_screen(screen->fd, NULL);
screen->pipe_screen = drm_api_hooks.create_screen(screen->fd, &arg);
if (!screen->pipe_screen) {
debug_printf("%s: failed to create pipe_screen\n", __FUNCTION__);
goto fail;
@@ -208,7 +268,7 @@ fail:
}
void
static void
dri_destroy_screen(__DRIscreenPrivate * sPriv)
{
struct dri_screen *screen = dri_screen(sPriv);
@@ -220,19 +280,20 @@ dri_destroy_screen(__DRIscreenPrivate * sPriv)
PUBLIC const struct __DriverAPIRec driDriverAPI = {
.InitScreen = dri_init_screen, /* not supported but exported */
.InitScreen = dri_init_screen,
.DestroyScreen = dri_destroy_screen,
.CreateContext = dri_create_context,
.DestroyContext = dri_destroy_context,
.CreateBuffer = dri_create_buffer,
.DestroyBuffer = dri_destroy_buffer,
.SwapBuffers = dri_swap_buffers, /* not supported but exported */
.SwapBuffers = dri_swap_buffers,
.MakeCurrent = dri_make_current,
.UnbindContext = dri_unbind_context,
.GetSwapInfo = dri_get_swap_info,
.GetDrawableMSC = driDrawableGetMSC32,
.WaitForMSC = driWaitForMSC32,
.CopySubBuffer = dri_copy_sub_buffer, /* not supported but exported */
.CopySubBuffer = dri_copy_sub_buffer,
.InitScreen = dri_init_screen,
.InitScreen2 = dri_init_screen2,
};

View File

@@ -37,6 +37,8 @@
#include "pipe/p_compiler.h"
#include "state_tracker/dri1_api.h"
struct dri_screen
{
/* dri */
@@ -55,6 +57,7 @@ struct dri_screen
/* drm */
int fd;
drmLock *drmLock;
/* gallium */
struct pipe_winsys *pipe_winsys;
@@ -73,15 +76,8 @@ dri_screen(__DRIscreenPrivate *sPriv)
/***********************************************************************
* dri_screen.c
*/
const __DRIconfig **
dri_init_screen2(__DRIscreenPrivate *sPriv);
void
dri_destroy_screen(__DRIscreenPrivate * sPriv);
int
dri_get_swap_info(__DRIdrawablePrivate * dPriv,
__DRIswapInfo * sInfo);
extern struct dri1_api *__dri1_api_hooks;
#endif