/* $XFree86: xc/programs/Xserver/Xext/xvmc.c,v 1.7 2001/11/18 23:55:48 mvojkovi Exp $ */ #define NEED_REPLIES #define NEED_EVENTS #include "X.h" #include "Xproto.h" #include "misc.h" #include "os.h" #include "dixstruct.h" #include "resource.h" #include "scrnintstr.h" #include "extnsionst.h" #include "servermd.h" #include "Xfuncproto.h" #include "xvdix.h" #include "XvMC.h" #include "Xvproto.h" #include "XvMCproto.h" #include "xvmcext.h" 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; } 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; } int (*ProcXvMCVector[xvmcNumRequest])(ClientPtr) = { ProcXvMCQueryVersion, ProcXvMCListSurfaceTypes, ProcXvMCCreateContext, ProcXvMCDestroyContext, ProcXvMCCreateSurface, ProcXvMCDestroySurface, ProcXvMCCreateSubpicture, ProcXvMCDestroySubpicture, ProcXvMCListSubpictureTypes }; 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; 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; }