/* $XFree86: xc/programs/Xserver/Xext/xvmc.c,v 1.8 2003/07/16 01:38:31 dawes Exp $ */

#define NEED_REPLIES
#define NEED_EVENTS
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif

#include <X11/X.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
#include "resource.h"
#include "scrnintstr.h"
#include "extnsionst.h"
#include "servermd.h"
#include <X11/Xfuncproto.h>
#include "xvdix.h"
#include <X11/extensions/XvMC.h>
#include <X11/extensions/Xvproto.h>
#include <X11/extensions/XvMCproto.h>
#include "xvmcext.h"

#ifdef HAS_XVMCSHM
#ifndef Lynx
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#else
#include <ipc.h>
#include <shm.h>
#endif /* Lynx */
#endif /* HAS_XVMCSHM */
   


#define DR_CLIENT_DRIVER_NAME_SIZE 48
#define DR_BUSID_SIZE 48

int XvMCScreenIndex = -1;

unsigned long XvMCGeneration = 0;

int XvMCReqCode;
int XvMCEventBase;
int XvMCErrorBase;

unsigned long XvMCRTContext;
unsigned long XvMCRTSurface;
unsigned long XvMCRTSubpicture;

typedef struct {
   int num_adaptors;
   XvMCAdaptorPtr adaptors;
   CloseScreenProcPtr	CloseScreen;
   char clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE];
   char busID[DR_BUSID_SIZE];
   int major;
   int minor;
   int patchLevel;
} XvMCScreenRec, *XvMCScreenPtr; 

#define XVMC_GET_PRIVATE(pScreen) \
   (XvMCScreenPtr)((pScreen)->devPrivates[XvMCScreenIndex].ptr)


static int
XvMCDestroyContextRes(pointer data, XID id)
{
   XvMCContextPtr pContext = (XvMCContextPtr)data;
   
   pContext->refcnt--;

   if(!pContext->refcnt) {
  	 XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen);
	(*pScreenPriv->adaptors[pContext->adapt_num].DestroyContext)(pContext);
	xfree(pContext);
   }	   

   return Success;
}

static int
XvMCDestroySurfaceRes(pointer data, XID id)
{
   XvMCSurfacePtr pSurface = (XvMCSurfacePtr)data;
   XvMCContextPtr pContext = pSurface->context;
   XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen);

   (*pScreenPriv->adaptors[pContext->adapt_num].DestroySurface)(pSurface); 
   xfree(pSurface);

   XvMCDestroyContextRes((pointer)pContext, pContext->context_id);

   return Success;
}


static int
XvMCDestroySubpictureRes(pointer data, XID id)
{
   XvMCSubpicturePtr pSubpict = (XvMCSubpicturePtr)data;
   XvMCContextPtr pContext = pSubpict->context;
   XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen);

   (*pScreenPriv->adaptors[pContext->adapt_num].DestroySubpicture)(pSubpict); 
   xfree(pSubpict);

   XvMCDestroyContextRes((pointer)pContext, pContext->context_id);

   return Success;
}

static void
XvMCResetProc (ExtensionEntry *extEntry)
{
}


static int 
ProcXvMCQueryVersion(ClientPtr client)
{
    xvmcQueryVersionReply rep;
    /* REQUEST(xvmcQueryVersionReq); */
    REQUEST_SIZE_MATCH(xvmcQueryVersionReq);
    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length = 0;
    rep.major = XvMCVersion;
    rep.minor = XvMCRevision;
    WriteToClient(client, sizeof(xvmcQueryVersionReply), (char*)&rep);
    return Success;
}


static int 
ProcXvMCListSurfaceTypes(ClientPtr client)
{
    XvPortPtr pPort;
    int i;
    XvMCScreenPtr pScreenPriv;
    xvmcListSurfaceTypesReply rep;
    xvmcSurfaceInfo info;
    XvMCAdaptorPtr adaptor = NULL;
    XvMCSurfaceInfoPtr surface;
    REQUEST(xvmcListSurfaceTypesReq);
    REQUEST_SIZE_MATCH(xvmcListSurfaceTypesReq);

    if(!(pPort = LOOKUP_PORT(stuff->port, client))) {
        client->errorValue = stuff->port;
        return _XvBadPort;
    }

    if(XvMCScreenIndex >= 0) { /* any adaptors at all */
       ScreenPtr pScreen = pPort->pAdaptor->pScreen;
       if((pScreenPriv = XVMC_GET_PRIVATE(pScreen))) {  /* any this screen */
          for(i = 0; i < pScreenPriv->num_adaptors; i++) {
             if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) {
               adaptor = &(pScreenPriv->adaptors[i]);
               break;
             }
          }
       }
    }

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.num = (adaptor) ? adaptor->num_surfaces : 0;
    rep.length = rep.num * sizeof(xvmcSurfaceInfo) >> 2;
 
    WriteToClient(client, sizeof(xvmcListSurfaceTypesReply), (char*)&rep);

    for(i = 0; i < rep.num; i++) {
	surface = adaptor->surfaces[i];
	info.surface_type_id = surface->surface_type_id;
	info.chroma_format = surface->chroma_format;
	info.max_width = surface->max_width;
	info.max_height = surface->max_height;
	info.subpicture_max_width = surface->subpicture_max_width;
	info.subpicture_max_height = surface->subpicture_max_height;
	info.mc_type = surface->mc_type;
	info.flags = surface->flags;
	WriteToClient(client, sizeof(xvmcSurfaceInfo), (char*)&info);
    }

    return Success;
}

static int 
ProcXvMCCreateContext(ClientPtr client)
{
    XvPortPtr pPort;
    CARD32 *data = NULL;
    int dwords = 0; 
    int i, result, adapt_num = -1;
    ScreenPtr pScreen;
    XvMCContextPtr pContext;
    XvMCScreenPtr pScreenPriv;
    XvMCAdaptorPtr adaptor = NULL;
    XvMCSurfaceInfoPtr surface = NULL;
    xvmcCreateContextReply rep;
    REQUEST(xvmcCreateContextReq);
    REQUEST_SIZE_MATCH(xvmcCreateContextReq);

    if(!(pPort = LOOKUP_PORT(stuff->port, client))) {
	client->errorValue = stuff->port;
	return _XvBadPort;
    }

    pScreen = pPort->pAdaptor->pScreen;

    if(XvMCScreenIndex < 0) /* no XvMC adaptors */
       return BadMatch;
 
    if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) /* none this screen */
       return BadMatch;

    for(i = 0; i < pScreenPriv->num_adaptors; i++) {
	if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) {
	    adaptor = &(pScreenPriv->adaptors[i]);
	    adapt_num = i; 
	    break;
	}
    }

    if(adapt_num < 0) /* none this port */
	return BadMatch;	

    for(i = 0; i < adaptor->num_surfaces; i++) {
        if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) {
            surface = adaptor->surfaces[i];
            break;
        }
    }

    /* adaptor doesn't support this suface_type_id */
    if(!surface) return BadMatch;


    if((stuff->width > surface->max_width) ||
       (stuff->height > surface->max_height))
        return BadValue;

    if(!(pContext = xalloc(sizeof(XvMCContextRec)))) {
	return BadAlloc;
    }


    pContext->pScreen = pScreen;
    pContext->adapt_num = adapt_num;
    pContext->context_id = stuff->context_id;
    pContext->surface_type_id = stuff->surface_type_id;
    pContext->width = stuff->width;
    pContext->height = stuff->height;
    pContext->flags = stuff->flags;
    pContext->refcnt = 1;

    result = (*adaptor->CreateContext)(pPort, pContext, &dwords, &data);

    if(result != Success) {
	xfree(pContext);
	return result;
    }

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.width_actual = pContext->width; 
    rep.height_actual = pContext->height; 
    rep.flags_return = pContext->flags; 
    rep.length = dwords;

    WriteToClient(client, sizeof(xvmcCreateContextReply), (char*)&rep);
    if(dwords)
      WriteToClient(client, dwords << 2, (char*)data); 
    AddResource(pContext->context_id, XvMCRTContext, pContext);

    if(data)
	xfree(data);

    return Success;
}

static int 
ProcXvMCDestroyContext(ClientPtr client)
{
    REQUEST(xvmcDestroyContextReq);
    REQUEST_SIZE_MATCH(xvmcDestroyContextReq);

    if(!LookupIDByType(stuff->context_id, XvMCRTContext))
	return (XvMCBadContext + XvMCErrorBase);

    FreeResource(stuff->context_id, RT_NONE); 

    return Success;
}

static int 
ProcXvMCCreateSurface(ClientPtr client)
{
    CARD32 *data = NULL;
    int dwords = 0;
    int result;
    XvMCContextPtr pContext;
    XvMCSurfacePtr pSurface;
    XvMCScreenPtr pScreenPriv;
    xvmcCreateSurfaceReply rep;
    REQUEST(xvmcCreateSurfaceReq);
    REQUEST_SIZE_MATCH(xvmcCreateSurfaceReq);

    if(!(pContext = LookupIDByType(stuff->context_id, XvMCRTContext)))
        return (XvMCBadContext + XvMCErrorBase);

    pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen);

    if(!(pSurface = xalloc(sizeof(XvMCSurfaceRec)))) 
        return BadAlloc;

    pSurface->surface_id = stuff->surface_id;
    pSurface->surface_type_id = pContext->surface_type_id;
    pSurface->context = pContext;

    result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSurface)(
                pSurface, &dwords, &data);

    if(result != Success) {
        xfree(pSurface);
        return result;
    }

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.length = dwords;

    WriteToClient(client, sizeof(xvmcCreateSurfaceReply), (char*)&rep);
    if(dwords)
      WriteToClient(client, dwords << 2, (char*)data);
    AddResource(pSurface->surface_id, XvMCRTSurface, pSurface);

    if(data)
        xfree(data);

    pContext->refcnt++;

    return Success;
}

static int 
ProcXvMCDestroySurface(ClientPtr client)
{
    REQUEST(xvmcDestroySurfaceReq);
    REQUEST_SIZE_MATCH(xvmcDestroySurfaceReq);

    if(!LookupIDByType(stuff->surface_id, XvMCRTSurface))
        return (XvMCBadSurface + XvMCErrorBase);

    FreeResource(stuff->surface_id, RT_NONE);

    return Success;
}

static int 
ProcXvMCCreateSubpicture(ClientPtr client)
{
    Bool image_supported = FALSE;
    CARD32 *data = NULL;
    int i, result, dwords = 0;
    XvMCContextPtr pContext;
    XvMCSubpicturePtr pSubpicture;
    XvMCScreenPtr pScreenPriv;
    xvmcCreateSubpictureReply rep;
    XvMCAdaptorPtr adaptor;
    XvMCSurfaceInfoPtr surface = NULL;
    REQUEST(xvmcCreateSubpictureReq);
    REQUEST_SIZE_MATCH(xvmcCreateSubpictureReq);

    if(!(pContext = LookupIDByType(stuff->context_id, XvMCRTContext)))
        return (XvMCBadContext + XvMCErrorBase);

    pScreenPriv = XVMC_GET_PRIVATE(pContext->pScreen);

    adaptor = &(pScreenPriv->adaptors[pContext->adapt_num]); 

    /* find which surface this context supports */
    for(i = 0; i < adaptor->num_surfaces; i++) {
	if(adaptor->surfaces[i]->surface_type_id == pContext->surface_type_id){
	   surface = adaptor->surfaces[i];
	   break;
	}
    } 

    if(!surface) return BadMatch;

    /* make sure this surface supports that xvimage format */
    if(!surface->compatible_subpictures) return BadMatch;

    for(i = 0; i < surface->compatible_subpictures->num_xvimages; i++) {
      if(surface->compatible_subpictures->xvimage_ids[i] == stuff->xvimage_id) {
	   image_supported = TRUE;
	   break;
      }
    }

    if(!image_supported) return BadMatch;

    /* make sure the size is OK */
    if((stuff->width > surface->subpicture_max_width) ||
       (stuff->height > surface->subpicture_max_height))
	return BadValue;

    if(!(pSubpicture = xalloc(sizeof(XvMCSubpictureRec))))
        return BadAlloc;

    pSubpicture->subpicture_id = stuff->subpicture_id;
    pSubpicture->xvimage_id = stuff->xvimage_id;
    pSubpicture->width = stuff->width;
    pSubpicture->height = stuff->height;
    pSubpicture->num_palette_entries = 0; /* overwritten by DDX */
    pSubpicture->entry_bytes = 0;         /* overwritten by DDX */
    pSubpicture->component_order[0] = 0;  /* overwritten by DDX */
    pSubpicture->component_order[1] = 0;
    pSubpicture->component_order[2] = 0;
    pSubpicture->component_order[3] = 0;
    pSubpicture->context = pContext;
   
    result = (*pScreenPriv->adaptors[pContext->adapt_num].CreateSubpicture)(
                pSubpicture, &dwords, &data);

    if(result != Success) {
        xfree(pSubpicture);
        return result;
    }

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.width_actual = pSubpicture->width;
    rep.height_actual = pSubpicture->height;
    rep.num_palette_entries = pSubpicture->num_palette_entries;
    rep.entry_bytes = pSubpicture->entry_bytes;
    rep.component_order[0] = pSubpicture->component_order[0];
    rep.component_order[1] = pSubpicture->component_order[1];
    rep.component_order[2] = pSubpicture->component_order[2];
    rep.component_order[3] = pSubpicture->component_order[3];
    rep.length = dwords;

    WriteToClient(client, sizeof(xvmcCreateSubpictureReply), (char*)&rep);
    if(dwords)
      WriteToClient(client, dwords << 2, (char*)data);
    AddResource(pSubpicture->subpicture_id, XvMCRTSubpicture, pSubpicture);

    if(data)
        xfree(data);

    pContext->refcnt++;

    return Success;
}

static int 
ProcXvMCDestroySubpicture(ClientPtr client)
{
    REQUEST(xvmcDestroySubpictureReq);
    REQUEST_SIZE_MATCH(xvmcDestroySubpictureReq);

    if(!LookupIDByType(stuff->subpicture_id, XvMCRTSubpicture))
        return (XvMCBadSubpicture + XvMCErrorBase);

    FreeResource(stuff->subpicture_id, RT_NONE);

    return Success;
}


static int
ProcXvMCListSubpictureTypes(ClientPtr client)
{
    XvPortPtr pPort;
    xvmcListSubpictureTypesReply rep;
    XvMCScreenPtr pScreenPriv;
    ScreenPtr pScreen;
    XvMCAdaptorPtr adaptor = NULL;
    XvMCSurfaceInfoPtr surface = NULL;
    xvImageFormatInfo info;
    XvImagePtr pImage;
    int i, j;
    REQUEST(xvmcListSubpictureTypesReq);
    REQUEST_SIZE_MATCH(xvmcListSubpictureTypesReq);

    if(!(pPort = LOOKUP_PORT(stuff->port, client))) {
        client->errorValue = stuff->port;
        return _XvBadPort;
    }

    pScreen = pPort->pAdaptor->pScreen;

    if(XvMCScreenIndex < 0) /* No XvMC adaptors */
        return BadMatch;

    if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen)))
        return BadMatch;   /* None this screen */

    for(i = 0; i < pScreenPriv->num_adaptors; i++) {
        if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) {
            adaptor = &(pScreenPriv->adaptors[i]);
            break;
        }
    }

    if(!adaptor) return BadMatch;

    for(i = 0; i < adaptor->num_surfaces; i++) {
        if(adaptor->surfaces[i]->surface_type_id == stuff->surface_type_id) {
            surface = adaptor->surfaces[i];
            break;
        }
    }

    if(!surface) return BadMatch;

    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.num = 0;
    if(surface->compatible_subpictures) 
	rep.num = surface->compatible_subpictures->num_xvimages;

    rep.length = rep.num * sizeof(xvImageFormatInfo) >> 2;

    WriteToClient(client, sizeof(xvmcListSubpictureTypesReply), (char*)&rep);

    for(i = 0; i < rep.num; i++) {
	pImage = NULL;
	for(j = 0; j < adaptor->num_subpictures; j++) {
	    if(surface->compatible_subpictures->xvimage_ids[i] ==
	       adaptor->subpictures[j]->id)
	    {
		pImage = adaptor->subpictures[j];
	        break;
	    }
	}
	if(!pImage) return BadImplementation;

        info.id = pImage->id;      
	info.type = pImage->type;  
        info.byte_order = pImage->byte_order; 
        memcpy(&info.guid, pImage->guid, 16);      
        info.bpp = pImage->bits_per_pixel;         
        info.num_planes = pImage->num_planes;      
        info.depth = pImage->depth;        
        info.red_mask = pImage->red_mask;  
        info.green_mask = pImage->green_mask;      
        info.blue_mask = pImage->blue_mask;        
        info.format = pImage->format;      
        info.y_sample_bits = pImage->y_sample_bits;        
        info.u_sample_bits = pImage->u_sample_bits;        
        info.v_sample_bits = pImage->v_sample_bits;        
        info.horz_y_period = pImage->horz_y_period;        
        info.horz_u_period = pImage->horz_u_period;        
        info.horz_v_period = pImage->horz_v_period;        
        info.vert_y_period = pImage->vert_y_period;        
        info.vert_u_period = pImage->vert_u_period;        
        info.vert_v_period = pImage->vert_v_period;        
        memcpy(&info.comp_order, pImage->component_order, 32);     
        info.scanline_order = pImage->scanline_order;
	WriteToClient(client, sizeof(xvImageFormatInfo), (char*)&info);
    }

    return Success;
}

static int
ProcXvMCGetDRInfo(ClientPtr client)
{
    xvmcGetDRInfoReply rep;
    XvPortPtr pPort;
    ScreenPtr pScreen;
    XvMCScreenPtr pScreenPriv;

#ifdef HAS_XVMCSHM
    volatile CARD32 *patternP;
#endif

    REQUEST(xvmcGetDRInfoReq);
    REQUEST_SIZE_MATCH(xvmcGetDRInfoReq);


    if(!(pPort = LOOKUP_PORT(stuff->port, client))) {
	client->errorValue = stuff->port;
	return _XvBadPort;
    }

    pScreen = pPort->pAdaptor->pScreen;
    pScreenPriv = XVMC_GET_PRIVATE(pScreen);
    
    rep.type = X_Reply;
    rep.sequenceNumber = client->sequence;
    rep.major = pScreenPriv->major;
    rep.minor = pScreenPriv->minor;
    rep.patchLevel = pScreenPriv->patchLevel;
    rep.nameLen = (strlen(pScreenPriv->clientDriverName) + 4) >> 2;
    rep.busIDLen = (strlen(pScreenPriv->busID) + 4) >> 2;

    rep.length = rep.nameLen + rep.busIDLen;
    rep.nameLen <<=2;
    rep.busIDLen <<=2;

    /*
     * Read back to the client what she has put in the shared memory
     * segment she prepared for us.
     */

    rep.isLocal = 1;
#ifdef HAS_XVMCSHM
    patternP = (CARD32 *)shmat( stuff->shmKey, NULL, SHM_RDONLY );
    if ( -1 != (long) patternP) {
        register volatile CARD32 *patternC = patternP;
	register int i;
	CARD32 magic = stuff->magic;
	
	rep.isLocal = 1;
	i = 1024 / sizeof(CARD32);
	
	while ( i-- ) {
	    if (*patternC++ != magic) {
		rep.isLocal = 0;
		break;
	    }
	    magic = ~magic;
	}
	shmdt( (char *)patternP ); 
    }
#endif /* HAS_XVMCSHM */
    
    WriteToClient(client, sizeof(xvmcGetDRInfoReply), 
		  (char*)&rep);
    if (rep.length) {      
	WriteToClient(client, rep.nameLen, 
		      pScreenPriv->clientDriverName);
	WriteToClient(client, rep.busIDLen, 
		      pScreenPriv->busID);
    }	
    return Success;
}


int (*ProcXvMCVector[xvmcNumRequest])(ClientPtr) = {
  ProcXvMCQueryVersion,
  ProcXvMCListSurfaceTypes,
  ProcXvMCCreateContext,
  ProcXvMCDestroyContext,
  ProcXvMCCreateSurface,
  ProcXvMCDestroySurface,
  ProcXvMCCreateSubpicture,
  ProcXvMCDestroySubpicture,
  ProcXvMCListSubpictureTypes,
  ProcXvMCGetDRInfo
};

static int
ProcXvMCDispatch (ClientPtr client)
{
    REQUEST(xReq);
    
    if(stuff->data < xvmcNumRequest)
	return (*ProcXvMCVector[stuff->data])(client);
    else
	return BadRequest;
}

static int
SProcXvMCDispatch (ClientPtr client)
{
    /* We only support local */
    return BadImplementation;
}

void 
XvMCExtensionInit()
{
   ExtensionEntry *extEntry;

   if(XvMCScreenIndex < 0) /* nobody supports it */
	return; 

   if(!(XvMCRTContext = CreateNewResourceType(XvMCDestroyContextRes)))
	return;

   if(!(XvMCRTSurface = CreateNewResourceType(XvMCDestroySurfaceRes)))
	return;

   if(!(XvMCRTSubpicture = CreateNewResourceType(XvMCDestroySubpictureRes)))
	return;

   extEntry = AddExtension(XvMCName, XvMCNumEvents, XvMCNumErrors, 
                              ProcXvMCDispatch, SProcXvMCDispatch,
                              XvMCResetProc, StandardMinorOpcode);

   if(!extEntry) return;
  
   XvMCReqCode = extEntry->base;
   XvMCEventBase = extEntry->eventBase;
   XvMCErrorBase = extEntry->errorBase;
}

static Bool
XvMCCloseScreen (int i, ScreenPtr pScreen)
{
    XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen);

    pScreen->CloseScreen = pScreenPriv->CloseScreen;

    xfree(pScreenPriv);

    return (*pScreen->CloseScreen)(i, pScreen);
}


int
XvMCScreenInit(ScreenPtr pScreen, int num, XvMCAdaptorPtr pAdapt)
{
   XvMCScreenPtr pScreenPriv;

   if(XvMCGeneration != serverGeneration) {
	if((XvMCScreenIndex = AllocateScreenPrivateIndex()) < 0)
	   return BadAlloc;

	XvMCGeneration = serverGeneration;
   }

   if(!(pScreenPriv = (XvMCScreenPtr)xalloc(sizeof(XvMCScreenRec))))
	return BadAlloc;

   pScreen->devPrivates[XvMCScreenIndex].ptr = (pointer)pScreenPriv;

   pScreenPriv->CloseScreen = pScreen->CloseScreen;
   pScreen->CloseScreen = XvMCCloseScreen;

   pScreenPriv->num_adaptors = num;
   pScreenPriv->adaptors = pAdapt;
   pScreenPriv->clientDriverName[0] = 0;
   pScreenPriv->busID[0] = 0;
   pScreenPriv->major = 0;
   pScreenPriv->minor = 0;
   pScreenPriv->patchLevel = 0;

   return Success;
}

XvImagePtr XvMCFindXvImage(XvPortPtr pPort, CARD32 id)
{
    XvImagePtr pImage = NULL;
    ScreenPtr pScreen = pPort->pAdaptor->pScreen;
    XvMCScreenPtr pScreenPriv;
    XvMCAdaptorPtr adaptor = NULL;
    int i;

    if(XvMCScreenIndex < 0) return NULL;

    if(!(pScreenPriv = XVMC_GET_PRIVATE(pScreen))) 
        return NULL;

    for(i = 0; i < pScreenPriv->num_adaptors; i++) {
       if(pPort->pAdaptor == pScreenPriv->adaptors[i].xv_adaptor) {
          adaptor = &(pScreenPriv->adaptors[i]);
          break;
       }
    }

    if(!adaptor) return NULL;

    for(i = 0; i < adaptor->num_subpictures; i++) {
        if(adaptor->subpictures[i]->id == id) {
            pImage = adaptor->subpictures[i];
            break;
        }
    }

    return pImage;
}

int
xf86XvMCRegisterDRInfo(ScreenPtr pScreen, char *name,
		       char *busID, int major, int minor,
		       int patchLevel)
{
    XvMCScreenPtr pScreenPriv = XVMC_GET_PRIVATE(pScreen);
    strncpy(pScreenPriv->clientDriverName, name,
	    DR_CLIENT_DRIVER_NAME_SIZE);
    strncpy(pScreenPriv->busID, busID, DR_BUSID_SIZE);
    pScreenPriv->major = major;
    pScreenPriv->minor = minor;
    pScreenPriv->patchLevel = patchLevel;
    pScreenPriv->clientDriverName[DR_CLIENT_DRIVER_NAME_SIZE-1] = 0;
    pScreenPriv->busID[DR_BUSID_SIZE-1] = 0;
    return Success;
}