428261197a
Tested by ajacoutot@, krw@, shadchin@ and jasper@ on various configurations including multihead with both zaphod and xrandr.
651 lines
16 KiB
C
651 lines
16 KiB
C
/*
|
|
* Copyright © 2008 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Soft-
|
|
* ware"), to deal in the Software without restriction, including without
|
|
* limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, provided that the above copyright
|
|
* notice(s) and this permission notice appear in all copies of the Soft-
|
|
* ware and that both the above copyright notice(s) and this permission
|
|
* notice appear in supporting documentation.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
|
|
* ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY
|
|
* RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN
|
|
* THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSE-
|
|
* QUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
|
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFOR-
|
|
* MANCE OF THIS SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of a copyright holder shall
|
|
* not be used in advertising or otherwise to promote the sale, use or
|
|
* other dealings in this Software without prior written authorization of
|
|
* the copyright holder.
|
|
*
|
|
* Authors:
|
|
* Kristian Høgsberg (krh@redhat.com)
|
|
*/
|
|
|
|
#ifdef HAVE_XORG_CONFIG_H
|
|
#include <xorg-config.h>
|
|
#endif
|
|
|
|
#include <X11/X.h>
|
|
#include <X11/Xproto.h>
|
|
#include <X11/extensions/dri2proto.h>
|
|
#include <X11/extensions/xfixeswire.h>
|
|
#include "dixstruct.h"
|
|
#include "scrnintstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "extnsionst.h"
|
|
#include "xfixes.h"
|
|
#include "dri2.h"
|
|
#include "protocol-versions.h"
|
|
|
|
/* The only xf86 include */
|
|
#include "xf86Module.h"
|
|
|
|
static ExtensionEntry *dri2Extension;
|
|
|
|
static Bool
|
|
validDrawable(ClientPtr client, XID drawable, Mask access_mode,
|
|
DrawablePtr *pDrawable, int *status)
|
|
{
|
|
*status = dixLookupDrawable(pDrawable, drawable, client,
|
|
M_DRAWABLE_WINDOW | M_DRAWABLE_PIXMAP,
|
|
access_mode);
|
|
if (*status != Success) {
|
|
client->errorValue = drawable;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2QueryVersion(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2QueryVersionReq);
|
|
xDRI2QueryVersionReply rep;
|
|
int n;
|
|
|
|
if (client->swapped)
|
|
swaps(&stuff->length, n);
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2QueryVersionReq);
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.majorVersion = dri2_major;
|
|
rep.minorVersion = dri2_minor;
|
|
|
|
if (client->swapped) {
|
|
swaps(&rep.sequenceNumber, n);
|
|
swapl(&rep.length, n);
|
|
swapl(&rep.majorVersion, n);
|
|
swapl(&rep.minorVersion, n);
|
|
}
|
|
|
|
WriteToClient(client, sizeof(xDRI2QueryVersionReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2Connect(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2ConnectReq);
|
|
xDRI2ConnectReply rep;
|
|
DrawablePtr pDraw;
|
|
int fd, status;
|
|
const char *driverName;
|
|
const char *deviceName;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2ConnectReq);
|
|
if (!validDrawable(client, stuff->window, DixGetAttrAccess,
|
|
&pDraw, &status))
|
|
return status;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.driverNameLength = 0;
|
|
rep.deviceNameLength = 0;
|
|
|
|
if (!DRI2Connect(pDraw->pScreen,
|
|
stuff->driverType, &fd, &driverName, &deviceName))
|
|
goto fail;
|
|
|
|
rep.driverNameLength = strlen(driverName);
|
|
rep.deviceNameLength = strlen(deviceName);
|
|
rep.length = (rep.driverNameLength + 3) / 4 +
|
|
(rep.deviceNameLength + 3) / 4;
|
|
|
|
fail:
|
|
WriteToClient(client, sizeof(xDRI2ConnectReply), &rep);
|
|
WriteToClient(client, rep.driverNameLength, driverName);
|
|
WriteToClient(client, rep.deviceNameLength, deviceName);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2Authenticate(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2AuthenticateReq);
|
|
xDRI2AuthenticateReply rep;
|
|
DrawablePtr pDraw;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2AuthenticateReq);
|
|
if (!validDrawable(client, stuff->window, DixGetAttrAccess,
|
|
&pDraw, &status))
|
|
return status;
|
|
|
|
rep.type = X_Reply;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.length = 0;
|
|
rep.authenticated = DRI2Authenticate(pDraw->pScreen, stuff->magic);
|
|
WriteToClient(client, sizeof(xDRI2AuthenticateReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
DRI2InvalidateBuffersEvent(DrawablePtr pDraw, void *priv)
|
|
{
|
|
xDRI2InvalidateBuffers event;
|
|
ClientPtr client = priv;
|
|
|
|
event.type = DRI2EventBase + DRI2_InvalidateBuffers;
|
|
event.drawable = pDraw->id;
|
|
|
|
WriteEventsToClient(client, 1, (xEvent *)&event);
|
|
}
|
|
|
|
static int
|
|
ProcDRI2CreateDrawable(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2CreateDrawableReq);
|
|
DrawablePtr pDrawable;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2CreateDrawableReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixAddAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
status = DRI2CreateDrawable(client, pDrawable, stuff->drawable,
|
|
DRI2InvalidateBuffersEvent, client);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2DestroyDrawable(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2DestroyDrawableReq);
|
|
DrawablePtr pDrawable;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2DestroyDrawableReq);
|
|
if (!validDrawable(client, stuff->drawable, DixRemoveAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
return Success;
|
|
}
|
|
|
|
|
|
static int
|
|
send_buffers_reply(ClientPtr client, DrawablePtr pDrawable,
|
|
DRI2BufferPtr *buffers, int count, int width, int height)
|
|
{
|
|
xDRI2GetBuffersReply rep;
|
|
int skip = 0;
|
|
int i;
|
|
|
|
if (buffers == NULL)
|
|
return BadAlloc;
|
|
|
|
if (pDrawable->type == DRAWABLE_WINDOW) {
|
|
for (i = 0; i < count; i++) {
|
|
/* Do not send the real front buffer of a window to the client.
|
|
*/
|
|
if (buffers[i]->attachment == DRI2BufferFrontLeft) {
|
|
skip++;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = (count - skip) * sizeof(xDRI2Buffer) / 4;
|
|
rep.sequenceNumber = client->sequence;
|
|
rep.width = width;
|
|
rep.height = height;
|
|
rep.count = count - skip;
|
|
WriteToClient(client, sizeof(xDRI2GetBuffersReply), &rep);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
xDRI2Buffer buffer;
|
|
|
|
/* Do not send the real front buffer of a window to the client.
|
|
*/
|
|
if ((pDrawable->type == DRAWABLE_WINDOW)
|
|
&& (buffers[i]->attachment == DRI2BufferFrontLeft)) {
|
|
continue;
|
|
}
|
|
|
|
buffer.attachment = buffers[i]->attachment;
|
|
buffer.name = buffers[i]->name;
|
|
buffer.pitch = buffers[i]->pitch;
|
|
buffer.cpp = buffers[i]->cpp;
|
|
buffer.flags = buffers[i]->flags;
|
|
WriteToClient(client, sizeof(xDRI2Buffer), &buffer);
|
|
}
|
|
return Success;
|
|
}
|
|
|
|
|
|
static int
|
|
ProcDRI2GetBuffers(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2GetBuffersReq);
|
|
DrawablePtr pDrawable;
|
|
DRI2BufferPtr *buffers;
|
|
int status, width, height, count;
|
|
unsigned int *attachments;
|
|
|
|
REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * 4);
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
if (DRI2ThrottleClient(client, pDrawable))
|
|
return Success;
|
|
|
|
attachments = (unsigned int *) &stuff[1];
|
|
buffers = DRI2GetBuffers(pDrawable, &width, &height,
|
|
attachments, stuff->count, &count);
|
|
|
|
|
|
return send_buffers_reply(client, pDrawable, buffers, count, width, height);
|
|
|
|
}
|
|
|
|
static int
|
|
ProcDRI2GetBuffersWithFormat(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2GetBuffersReq);
|
|
DrawablePtr pDrawable;
|
|
DRI2BufferPtr *buffers;
|
|
int status, width, height, count;
|
|
unsigned int *attachments;
|
|
|
|
REQUEST_FIXED_SIZE(xDRI2GetBuffersReq, stuff->count * (2 * 4));
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
if (DRI2ThrottleClient(client, pDrawable))
|
|
return Success;
|
|
|
|
attachments = (unsigned int *) &stuff[1];
|
|
buffers = DRI2GetBuffersWithFormat(pDrawable, &width, &height,
|
|
attachments, stuff->count, &count);
|
|
|
|
return send_buffers_reply(client, pDrawable, buffers, count, width, height);
|
|
}
|
|
|
|
static int
|
|
ProcDRI2CopyRegion(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2CopyRegionReq);
|
|
xDRI2CopyRegionReply rep;
|
|
DrawablePtr pDrawable;
|
|
int status;
|
|
RegionPtr pRegion;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2CopyRegionReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixWriteAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
VERIFY_REGION(pRegion, stuff->region, client, DixReadAccess);
|
|
|
|
status = DRI2CopyRegion(pDrawable, pRegion, stuff->dest, stuff->src);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
/* CopyRegion needs to be a round trip to make sure the X server
|
|
* queues the swap buffer rendering commands before the DRI client
|
|
* continues rendering. The reply has a bitmask to signal the
|
|
* presense of optional return values as well, but we're not using
|
|
* that yet.
|
|
*/
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
|
|
WriteToClient(client, sizeof(xDRI2CopyRegionReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
load_swap_reply(xDRI2SwapBuffersReply *rep, CARD64 sbc)
|
|
{
|
|
rep->swap_hi = sbc >> 32;
|
|
rep->swap_lo = sbc & 0xffffffff;
|
|
}
|
|
|
|
static CARD64
|
|
vals_to_card64(CARD32 lo, CARD32 hi)
|
|
{
|
|
return (CARD64)hi << 32 | lo;
|
|
}
|
|
|
|
static void
|
|
DRI2SwapEvent(ClientPtr client, void *data, int type, CARD64 ust, CARD64 msc,
|
|
CARD64 sbc)
|
|
{
|
|
xDRI2BufferSwapComplete event;
|
|
DrawablePtr pDrawable = data;
|
|
|
|
event.type = DRI2EventBase + DRI2_BufferSwapComplete;
|
|
event.event_type = type;
|
|
event.drawable = pDrawable->id;
|
|
event.ust_hi = (CARD64)ust >> 32;
|
|
event.ust_lo = ust & 0xffffffff;
|
|
event.msc_hi = (CARD64)msc >> 32;
|
|
event.msc_lo = msc & 0xffffffff;
|
|
event.sbc_hi = (CARD64)sbc >> 32;
|
|
event.sbc_lo = sbc & 0xffffffff;
|
|
|
|
WriteEventsToClient(client, 1, (xEvent *)&event);
|
|
}
|
|
|
|
static int
|
|
ProcDRI2SwapBuffers(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2SwapBuffersReq);
|
|
xDRI2SwapBuffersReply rep;
|
|
DrawablePtr pDrawable;
|
|
CARD64 target_msc, divisor, remainder, swap_target;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2SwapBuffersReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable,
|
|
DixReadAccess | DixWriteAccess, &pDrawable, &status))
|
|
return status;
|
|
|
|
/*
|
|
* Ensures an out of control client can't exhaust our swap queue, and
|
|
* also orders swaps.
|
|
*/
|
|
if (DRI2ThrottleClient(client, pDrawable))
|
|
return Success;
|
|
|
|
target_msc = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
|
|
divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
|
|
remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
|
|
|
|
status = DRI2SwapBuffers(client, pDrawable, target_msc, divisor, remainder,
|
|
&swap_target, DRI2SwapEvent, pDrawable);
|
|
if (status != Success)
|
|
return BadDrawable;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
load_swap_reply(&rep, swap_target);
|
|
|
|
WriteToClient(client, sizeof(xDRI2SwapBuffersReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static void
|
|
load_msc_reply(xDRI2MSCReply *rep, CARD64 ust, CARD64 msc, CARD64 sbc)
|
|
{
|
|
rep->ust_hi = ust >> 32;
|
|
rep->ust_lo = ust & 0xffffffff;
|
|
rep->msc_hi = msc >> 32;
|
|
rep->msc_lo = msc & 0xffffffff;
|
|
rep->sbc_hi = sbc >> 32;
|
|
rep->sbc_lo = sbc & 0xffffffff;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2GetMSC(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2GetMSCReq);
|
|
xDRI2MSCReply rep;
|
|
DrawablePtr pDrawable;
|
|
CARD64 ust, msc, sbc;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2GetMSCReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
|
|
&status))
|
|
return status;
|
|
|
|
status = DRI2GetMSC(pDrawable, &ust, &msc, &sbc);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
load_msc_reply(&rep, ust, msc, sbc);
|
|
|
|
WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2WaitMSC(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2WaitMSCReq);
|
|
DrawablePtr pDrawable;
|
|
CARD64 target, divisor, remainder;
|
|
int status;
|
|
|
|
/* FIXME: in restart case, client may be gone at this point */
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2WaitMSCReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
|
|
&status))
|
|
return status;
|
|
|
|
target = vals_to_card64(stuff->target_msc_lo, stuff->target_msc_hi);
|
|
divisor = vals_to_card64(stuff->divisor_lo, stuff->divisor_hi);
|
|
remainder = vals_to_card64(stuff->remainder_lo, stuff->remainder_hi);
|
|
|
|
status = DRI2WaitMSC(client, pDrawable, target, divisor, remainder);
|
|
if (status != Success)
|
|
return status;
|
|
|
|
return Success;
|
|
}
|
|
|
|
int
|
|
ProcDRI2WaitMSCReply(ClientPtr client, CARD64 ust, CARD64 msc, CARD64 sbc)
|
|
{
|
|
xDRI2MSCReply rep;
|
|
|
|
rep.type = X_Reply;
|
|
rep.length = 0;
|
|
rep.sequenceNumber = client->sequence;
|
|
load_msc_reply(&rep, ust, msc, sbc);
|
|
|
|
WriteToClient(client, sizeof(xDRI2MSCReply), &rep);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2SwapInterval(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2SwapIntervalReq);
|
|
DrawablePtr pDrawable;
|
|
int status;
|
|
|
|
/* FIXME: in restart case, client may be gone at this point */
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2SwapIntervalReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess | DixWriteAccess,
|
|
&pDrawable, &status))
|
|
return status;
|
|
|
|
DRI2SwapInterval(pDrawable, stuff->interval);
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2WaitSBC(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2WaitSBCReq);
|
|
DrawablePtr pDrawable;
|
|
CARD64 target;
|
|
int status;
|
|
|
|
REQUEST_SIZE_MATCH(xDRI2WaitSBCReq);
|
|
|
|
if (!validDrawable(client, stuff->drawable, DixReadAccess, &pDrawable,
|
|
&status))
|
|
return status;
|
|
|
|
target = vals_to_card64(stuff->target_sbc_lo, stuff->target_sbc_hi);
|
|
status = DRI2WaitSBC(client, pDrawable, target);
|
|
|
|
return status;
|
|
}
|
|
|
|
static int
|
|
ProcDRI2Dispatch (ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
|
|
switch (stuff->data) {
|
|
case X_DRI2QueryVersion:
|
|
return ProcDRI2QueryVersion(client);
|
|
}
|
|
|
|
if (!LocalClient(client))
|
|
return BadRequest;
|
|
|
|
switch (stuff->data) {
|
|
case X_DRI2Connect:
|
|
return ProcDRI2Connect(client);
|
|
case X_DRI2Authenticate:
|
|
return ProcDRI2Authenticate(client);
|
|
case X_DRI2CreateDrawable:
|
|
return ProcDRI2CreateDrawable(client);
|
|
case X_DRI2DestroyDrawable:
|
|
return ProcDRI2DestroyDrawable(client);
|
|
case X_DRI2GetBuffers:
|
|
return ProcDRI2GetBuffers(client);
|
|
case X_DRI2CopyRegion:
|
|
return ProcDRI2CopyRegion(client);
|
|
case X_DRI2GetBuffersWithFormat:
|
|
return ProcDRI2GetBuffersWithFormat(client);
|
|
case X_DRI2SwapBuffers:
|
|
return ProcDRI2SwapBuffers(client);
|
|
case X_DRI2GetMSC:
|
|
return ProcDRI2GetMSC(client);
|
|
case X_DRI2WaitMSC:
|
|
return ProcDRI2WaitMSC(client);
|
|
case X_DRI2WaitSBC:
|
|
return ProcDRI2WaitSBC(client);
|
|
case X_DRI2SwapInterval:
|
|
return ProcDRI2SwapInterval(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
static int
|
|
SProcDRI2Connect(ClientPtr client)
|
|
{
|
|
REQUEST(xDRI2ConnectReq);
|
|
xDRI2ConnectReply rep;
|
|
int n;
|
|
|
|
/* If the client is swapped, it's not local. Talk to the hand. */
|
|
|
|
swaps(&stuff->length, n);
|
|
if (sizeof(*stuff) / 4 != client->req_len)
|
|
return BadLength;
|
|
|
|
rep.sequenceNumber = client->sequence;
|
|
swaps(&rep.sequenceNumber, n);
|
|
rep.length = 0;
|
|
rep.driverNameLength = 0;
|
|
rep.deviceNameLength = 0;
|
|
|
|
return Success;
|
|
}
|
|
|
|
static int
|
|
SProcDRI2Dispatch (ClientPtr client)
|
|
{
|
|
REQUEST(xReq);
|
|
|
|
/*
|
|
* Only local clients are allowed DRI access, but remote clients
|
|
* still need these requests to find out cleanly.
|
|
*/
|
|
switch (stuff->data)
|
|
{
|
|
case X_DRI2QueryVersion:
|
|
return ProcDRI2QueryVersion(client);
|
|
case X_DRI2Connect:
|
|
return SProcDRI2Connect(client);
|
|
default:
|
|
return BadRequest;
|
|
}
|
|
}
|
|
|
|
int DRI2EventBase;
|
|
|
|
static void
|
|
DRI2ExtensionInit(void)
|
|
{
|
|
dri2Extension = AddExtension(DRI2_NAME,
|
|
DRI2NumberEvents,
|
|
DRI2NumberErrors,
|
|
ProcDRI2Dispatch,
|
|
SProcDRI2Dispatch,
|
|
NULL,
|
|
StandardMinorOpcode);
|
|
|
|
DRI2EventBase = dri2Extension->eventBase;
|
|
}
|
|
|
|
extern Bool noDRI2Extension;
|
|
|
|
_X_HIDDEN ExtensionModule dri2ExtensionModule = {
|
|
DRI2ExtensionInit,
|
|
DRI2_NAME,
|
|
&noDRI2Extension,
|
|
NULL,
|
|
NULL
|
|
};
|