diff options
Diffstat (limited to 'src/gallium/state_trackers/xorg/xvmc/context.c')
-rw-r--r-- | src/gallium/state_trackers/xorg/xvmc/context.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/gallium/state_trackers/xorg/xvmc/context.c b/src/gallium/state_trackers/xorg/xvmc/context.c new file mode 100644 index 0000000000..33f47838f5 --- /dev/null +++ b/src/gallium/state_trackers/xorg/xvmc/context.c @@ -0,0 +1,203 @@ +#include <assert.h> +#include <X11/Xlibint.h> +#include <X11/extensions/XvMClib.h> +#include <pipe/p_screen.h> +#include <pipe/p_video_context.h> +#include <pipe/p_video_state.h> +#include <pipe/p_state.h> +#include <vl_winsys.h> +#include <util/u_memory.h> +#include "xvmc_private.h" + +static Status Validate(Display *dpy, XvPortID port, int surface_type_id, + unsigned int width, unsigned int height, int flags, + bool *found_port, int *screen, int *chroma_format, int *mc_type) +{ + bool found_surface = false; + XvAdaptorInfo *adaptor_info; + unsigned int num_adaptors; + int num_types; + unsigned int max_width, max_height; + Status ret; + + assert(dpy); + assert(found_port); + assert(screen); + assert(chroma_format); + assert(mc_type); + + *found_port = false; + + for (unsigned int i = 0; i < XScreenCount(dpy); ++i) + { + ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); + if (ret != Success) + return ret; + + for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) + { + for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) + { + XvMCSurfaceInfo *surface_info; + + if (adaptor_info[j].base_id + k != port) + continue; + + *found_port = true; + + surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); + if (!surface_info) + { + XvFreeAdaptorInfo(adaptor_info); + return BadAlloc; + } + + for (unsigned int l = 0; l < num_types && !found_surface; ++l) + { + if (surface_info[l].surface_type_id != surface_type_id) + continue; + + found_surface = true; + max_width = surface_info[l].max_width; + max_height = surface_info[l].max_height; + *chroma_format = surface_info[l].chroma_format; + *mc_type = surface_info[l].mc_type; + *screen = i; + } + + XFree(surface_info); + } + } + + XvFreeAdaptorInfo(adaptor_info); + } + + if (!*found_port) + return XvBadPort; + if (!found_surface) + return BadMatch; + if (width > max_width || height > max_height) + return BadValue; + if (flags != XVMC_DIRECT && flags != 0) + return BadValue; + + return Success; +} + +static enum pipe_video_profile ProfileToPipe(int xvmc_profile) +{ + if (xvmc_profile & XVMC_MPEG_1) + assert(0); + if (xvmc_profile & XVMC_MPEG_2) + return PIPE_VIDEO_PROFILE_MPEG2_MAIN; + if (xvmc_profile & XVMC_H263) + assert(0); + if (xvmc_profile & XVMC_MPEG_4) + assert(0); + + assert(0); + + return -1; +} + +static enum pipe_video_chroma_format FormatToPipe(int xvmc_format) +{ + switch (xvmc_format) + { + case XVMC_CHROMA_FORMAT_420: + return PIPE_VIDEO_CHROMA_FORMAT_420; + case XVMC_CHROMA_FORMAT_422: + return PIPE_VIDEO_CHROMA_FORMAT_422; + case XVMC_CHROMA_FORMAT_444: + return PIPE_VIDEO_CHROMA_FORMAT_444; + default: + assert(0); + } + + return -1; +} + +Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, + int width, int height, int flags, XvMCContext *context) +{ + bool found_port; + int scrn; + int chroma_format; + int mc_type; + Status ret; + struct pipe_screen *screen; + struct pipe_video_context *vpipe; + XvMCContextPrivate *context_priv; + + assert(dpy); + + if (!context) + return XvMCBadContext; + + ret = Validate(dpy, port, surface_type_id, width, height, flags, + &found_port, &scrn, &chroma_format, &mc_type); + + /* Success and XvBadPort have the same value */ + if (ret != Success || !found_port) + return ret; + + context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); + if (!context_priv) + return BadAlloc; + + /* TODO: Reuse screen if process creates another context */ + screen = vl_screen_create(dpy, scrn); + + if (!screen) + { + FREE(context_priv); + return BadAlloc; + } + + vpipe = vl_video_create(screen, ProfileToPipe(mc_type), + FormatToPipe(chroma_format), width, height); + + if (!vpipe) + { + screen->destroy(screen); + FREE(context_priv); + return BadAlloc; + } + + context_priv->vpipe = vpipe; + + context->context_id = XAllocID(dpy); + context->surface_type_id = surface_type_id; + context->width = width; + context->height = height; + context->flags = flags; + context->port = port; + context->privData = context_priv; + + SyncHandle(); + + return Success; +} + +Status XvMCDestroyContext(Display *dpy, XvMCContext *context) +{ + struct pipe_screen *screen; + struct pipe_video_context *vpipe; + XvMCContextPrivate *context_priv; + + assert(dpy); + + if (!context || !context->privData) + return XvMCBadContext; + + context_priv = context->privData; + vpipe = context_priv->vpipe; + pipe_surface_reference(&context_priv->backbuffer, NULL); + screen = vpipe->screen; + vpipe->destroy(vpipe); + screen->destroy(screen); + FREE(context_priv); + context->privData = NULL; + + return Success; +} |