xenocara/xserver/Xext/xvmc.c

783 lines
20 KiB
C

#define NEED_REPLIES
#define NEED_EVENTS
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <string.h>
#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
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/shm.h>
#endif /* HAS_XVMCSHM */
#define DR_CLIENT_DRIVER_NAME_SIZE 48
#define DR_BUSID_SIZE 48
static int XvMCScreenKeyIndex;
static DevPrivateKey XvMCScreenKey;
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)(dixLookupPrivate(&(pScreen)->devPrivates, XvMCScreenKey))
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 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(XvMCScreenKey) { /* 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(XvMCScreenKey == NULL) /* 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(XvMCScreenKey == NULL) /* 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) {
volatile CARD32 *patternC = patternP;
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(void)
{
ExtensionEntry *extEntry;
if(XvMCScreenKey == NULL) /* 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,
NULL, 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;
XvMCScreenKey = &XvMCScreenKeyIndex;
if(!(pScreenPriv = (XvMCScreenPtr)xalloc(sizeof(XvMCScreenRec))))
return BadAlloc;
dixSetPrivate(&pScreen->devPrivates, XvMCScreenKey, 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(XvMCScreenKey == NULL) 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;
}