17ec681f3Smrg/************************************************************************** 27ec681f3Smrg * 37ec681f3Smrg * Copyright 2009 Younes Manton. 47ec681f3Smrg * All Rights Reserved. 57ec681f3Smrg * 67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a 77ec681f3Smrg * copy of this software and associated documentation files (the 87ec681f3Smrg * "Software"), to deal in the Software without restriction, including 97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish, 107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to 117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to 127ec681f3Smrg * the following conditions: 137ec681f3Smrg * 147ec681f3Smrg * The above copyright notice and this permission notice (including the 157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions 167ec681f3Smrg * of the Software. 177ec681f3Smrg * 187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 257ec681f3Smrg * 267ec681f3Smrg **************************************************************************/ 277ec681f3Smrg 287ec681f3Smrg#include <assert.h> 297ec681f3Smrg 307ec681f3Smrg#include <X11/Xlibint.h> 317ec681f3Smrg#include <X11/extensions/XvMClib.h> 327ec681f3Smrg 337ec681f3Smrg#include "pipe/p_screen.h" 347ec681f3Smrg#include "pipe/p_video_codec.h" 357ec681f3Smrg#include "pipe/p_video_state.h" 367ec681f3Smrg#include "pipe/p_state.h" 377ec681f3Smrg 387ec681f3Smrg#include "util/u_memory.h" 397ec681f3Smrg 407ec681f3Smrg#include "vl/vl_csc.h" 417ec681f3Smrg#include "vl/vl_winsys.h" 427ec681f3Smrg 437ec681f3Smrg#include "xvmc_private.h" 447ec681f3Smrg 457ec681f3Smrgstatic Status Validate(Display *dpy, XvPortID port, int surface_type_id, 467ec681f3Smrg unsigned int width, unsigned int height, int flags, 477ec681f3Smrg bool *found_port, int *screen, int *chroma_format, 487ec681f3Smrg int *mc_type, int *surface_flags, 497ec681f3Smrg unsigned short *subpic_max_w, 507ec681f3Smrg unsigned short *subpic_max_h) 517ec681f3Smrg{ 527ec681f3Smrg bool found_surface = false; 537ec681f3Smrg XvAdaptorInfo *adaptor_info; 547ec681f3Smrg unsigned int num_adaptors; 557ec681f3Smrg int num_types; 567ec681f3Smrg unsigned int max_width = 0, max_height = 0; 577ec681f3Smrg Status ret; 587ec681f3Smrg 597ec681f3Smrg assert(dpy); 607ec681f3Smrg assert(found_port); 617ec681f3Smrg assert(screen); 627ec681f3Smrg assert(chroma_format); 637ec681f3Smrg assert(mc_type); 647ec681f3Smrg assert(surface_flags); 657ec681f3Smrg assert(subpic_max_w); 667ec681f3Smrg assert(subpic_max_h); 677ec681f3Smrg 687ec681f3Smrg *found_port = false; 697ec681f3Smrg 707ec681f3Smrg for (int i = 0; i < XScreenCount(dpy); ++i) { 717ec681f3Smrg ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); 727ec681f3Smrg if (ret != Success) 737ec681f3Smrg return ret; 747ec681f3Smrg 757ec681f3Smrg for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) { 767ec681f3Smrg for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) { 777ec681f3Smrg XvMCSurfaceInfo *surface_info; 787ec681f3Smrg 797ec681f3Smrg if (adaptor_info[j].base_id + k != port) 807ec681f3Smrg continue; 817ec681f3Smrg 827ec681f3Smrg *found_port = true; 837ec681f3Smrg 847ec681f3Smrg surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); 857ec681f3Smrg if (!surface_info) { 867ec681f3Smrg XvFreeAdaptorInfo(adaptor_info); 877ec681f3Smrg return BadAlloc; 887ec681f3Smrg } 897ec681f3Smrg 907ec681f3Smrg for (int l = 0; l < num_types && !found_surface; ++l) { 917ec681f3Smrg if (surface_info[l].surface_type_id != surface_type_id) 927ec681f3Smrg continue; 937ec681f3Smrg 947ec681f3Smrg found_surface = true; 957ec681f3Smrg max_width = surface_info[l].max_width; 967ec681f3Smrg max_height = surface_info[l].max_height; 977ec681f3Smrg *chroma_format = surface_info[l].chroma_format; 987ec681f3Smrg *mc_type = surface_info[l].mc_type; 997ec681f3Smrg *surface_flags = surface_info[l].flags; 1007ec681f3Smrg *subpic_max_w = surface_info[l].subpicture_max_width; 1017ec681f3Smrg *subpic_max_h = surface_info[l].subpicture_max_height; 1027ec681f3Smrg *screen = i; 1037ec681f3Smrg 1047ec681f3Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \ 1057ec681f3Smrg "[XvMC] screen=%u, port=%u\n" \ 1067ec681f3Smrg "[XvMC] id=0x%08X\n" \ 1077ec681f3Smrg "[XvMC] max width=%u, max height=%u\n" \ 1087ec681f3Smrg "[XvMC] chroma format=0x%08X\n" \ 1097ec681f3Smrg "[XvMC] acceleration level=0x%08X\n" \ 1107ec681f3Smrg "[XvMC] flags=0x%08X\n" \ 1117ec681f3Smrg "[XvMC] subpicture max width=%u, max height=%u\n", 1127ec681f3Smrg i, port, surface_type_id, max_width, max_height, *chroma_format, 1137ec681f3Smrg *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h); 1147ec681f3Smrg } 1157ec681f3Smrg 1167ec681f3Smrg free(surface_info); 1177ec681f3Smrg } 1187ec681f3Smrg } 1197ec681f3Smrg 1207ec681f3Smrg XvFreeAdaptorInfo(adaptor_info); 1217ec681f3Smrg } 1227ec681f3Smrg 1237ec681f3Smrg if (!*found_port) { 1247ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n"); 1257ec681f3Smrg return XvBadPort; 1267ec681f3Smrg } 1277ec681f3Smrg if (!found_surface) { 1287ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n"); 1297ec681f3Smrg return BadMatch; 1307ec681f3Smrg } 1317ec681f3Smrg if (width > max_width || height > max_height) { 1327ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n", 1337ec681f3Smrg width, height, max_width, max_height); 1347ec681f3Smrg return BadValue; 1357ec681f3Smrg } 1367ec681f3Smrg if (flags != XVMC_DIRECT && flags != 0) { 1377ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags); 1387ec681f3Smrg return BadValue; 1397ec681f3Smrg } 1407ec681f3Smrg 1417ec681f3Smrg return Success; 1427ec681f3Smrg} 1437ec681f3Smrg 1447ec681f3Smrgstatic enum pipe_video_profile ProfileToPipe(int xvmc_profile) 1457ec681f3Smrg{ 1467ec681f3Smrg if (xvmc_profile & XVMC_MPEG_1) 1477ec681f3Smrg assert(0); 1487ec681f3Smrg if (xvmc_profile & XVMC_MPEG_2) 1497ec681f3Smrg return PIPE_VIDEO_PROFILE_MPEG2_MAIN; 1507ec681f3Smrg if (xvmc_profile & XVMC_H263) 1517ec681f3Smrg assert(0); 1527ec681f3Smrg if (xvmc_profile & XVMC_MPEG_4) 1537ec681f3Smrg assert(0); 1547ec681f3Smrg 1557ec681f3Smrg assert(0); 1567ec681f3Smrg 1577ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile); 1587ec681f3Smrg 1597ec681f3Smrg return -1; 1607ec681f3Smrg} 1617ec681f3Smrg 1627ec681f3Smrgstatic enum pipe_video_chroma_format FormatToPipe(int xvmc_format) 1637ec681f3Smrg{ 1647ec681f3Smrg switch (xvmc_format) { 1657ec681f3Smrg case XVMC_CHROMA_FORMAT_420: 1667ec681f3Smrg return PIPE_VIDEO_CHROMA_FORMAT_420; 1677ec681f3Smrg case XVMC_CHROMA_FORMAT_422: 1687ec681f3Smrg return PIPE_VIDEO_CHROMA_FORMAT_422; 1697ec681f3Smrg case XVMC_CHROMA_FORMAT_444: 1707ec681f3Smrg return PIPE_VIDEO_CHROMA_FORMAT_444; 1717ec681f3Smrg default: 1727ec681f3Smrg assert(0); 1737ec681f3Smrg } 1747ec681f3Smrg 1757ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format); 1767ec681f3Smrg 1777ec681f3Smrg return -1; 1787ec681f3Smrg} 1797ec681f3Smrg 1807ec681f3SmrgPUBLIC 1817ec681f3SmrgStatus XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, 1827ec681f3Smrg int width, int height, int flags, XvMCContext *context) 1837ec681f3Smrg{ 1847ec681f3Smrg bool found_port; 1857ec681f3Smrg int scrn = 0; 1867ec681f3Smrg int chroma_format = 0; 1877ec681f3Smrg int mc_type = 0; 1887ec681f3Smrg int surface_flags = 0; 1897ec681f3Smrg unsigned short subpic_max_w = 0; 1907ec681f3Smrg unsigned short subpic_max_h = 0; 1917ec681f3Smrg Status ret; 1927ec681f3Smrg struct vl_screen *vscreen; 1937ec681f3Smrg struct pipe_context *pipe; 1947ec681f3Smrg struct pipe_video_codec templat = {0}; 1957ec681f3Smrg XvMCContextPrivate *context_priv; 1967ec681f3Smrg vl_csc_matrix csc; 1977ec681f3Smrg 1987ec681f3Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); 1997ec681f3Smrg 2007ec681f3Smrg assert(dpy); 2017ec681f3Smrg 2027ec681f3Smrg if (!context) 2037ec681f3Smrg return XvMCBadContext; 2047ec681f3Smrg 2057ec681f3Smrg ret = Validate(dpy, port, surface_type_id, width, height, flags, 2067ec681f3Smrg &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, 2077ec681f3Smrg &subpic_max_w, &subpic_max_h); 2087ec681f3Smrg 2097ec681f3Smrg /* Success and XvBadPort have the same value */ 2107ec681f3Smrg if (ret != Success || !found_port) 2117ec681f3Smrg return ret; 2127ec681f3Smrg 2137ec681f3Smrg /* XXX: Current limits */ 2147ec681f3Smrg if (chroma_format != XVMC_CHROMA_FORMAT_420) { 2157ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); 2167ec681f3Smrg return BadImplementation; 2177ec681f3Smrg } 2187ec681f3Smrg if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { 2197ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); 2207ec681f3Smrg return BadImplementation; 2217ec681f3Smrg } 2227ec681f3Smrg if (surface_flags & XVMC_INTRA_UNSIGNED) { 2237ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); 2247ec681f3Smrg return BadImplementation; 2257ec681f3Smrg } 2267ec681f3Smrg 2277ec681f3Smrg context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); 2287ec681f3Smrg if (!context_priv) 2297ec681f3Smrg return BadAlloc; 2307ec681f3Smrg 2317ec681f3Smrg /* TODO: Reuse screen if process creates another context */ 2327ec681f3Smrg vscreen = vl_dri3_screen_create(dpy, scrn); 2337ec681f3Smrg if (!vscreen) 2347ec681f3Smrg vscreen = vl_dri2_screen_create(dpy, scrn); 2357ec681f3Smrg 2367ec681f3Smrg if (!vscreen) { 2377ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); 2387ec681f3Smrg FREE(context_priv); 2397ec681f3Smrg return BadAlloc; 2407ec681f3Smrg } 2417ec681f3Smrg 2427ec681f3Smrg pipe = vscreen->pscreen->context_create(vscreen->pscreen, NULL, 0); 2437ec681f3Smrg if (!pipe) { 2447ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); 2457ec681f3Smrg vscreen->destroy(vscreen); 2467ec681f3Smrg FREE(context_priv); 2477ec681f3Smrg return BadAlloc; 2487ec681f3Smrg } 2497ec681f3Smrg 2507ec681f3Smrg templat.profile = ProfileToPipe(mc_type); 2517ec681f3Smrg templat.entrypoint = (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC; 2527ec681f3Smrg templat.chroma_format = FormatToPipe(chroma_format); 2537ec681f3Smrg templat.width = width; 2547ec681f3Smrg templat.height = height; 2557ec681f3Smrg templat.max_references = 2; 2567ec681f3Smrg templat.expect_chunked_decode = true; 2577ec681f3Smrg 2587ec681f3Smrg context_priv->decoder = pipe->create_video_codec(pipe, &templat); 2597ec681f3Smrg 2607ec681f3Smrg if (!context_priv->decoder) { 2617ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); 2627ec681f3Smrg pipe->destroy(pipe); 2637ec681f3Smrg vscreen->destroy(vscreen); 2647ec681f3Smrg FREE(context_priv); 2657ec681f3Smrg return BadAlloc; 2667ec681f3Smrg } 2677ec681f3Smrg 2687ec681f3Smrg if (!vl_compositor_init(&context_priv->compositor, pipe)) { 2697ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); 2707ec681f3Smrg context_priv->decoder->destroy(context_priv->decoder); 2717ec681f3Smrg pipe->destroy(pipe); 2727ec681f3Smrg vscreen->destroy(vscreen); 2737ec681f3Smrg FREE(context_priv); 2747ec681f3Smrg return BadAlloc; 2757ec681f3Smrg } 2767ec681f3Smrg 2777ec681f3Smrg if (!vl_compositor_init_state(&context_priv->cstate, pipe)) { 2787ec681f3Smrg XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n"); 2797ec681f3Smrg vl_compositor_cleanup(&context_priv->compositor); 2807ec681f3Smrg context_priv->decoder->destroy(context_priv->decoder); 2817ec681f3Smrg pipe->destroy(pipe); 2827ec681f3Smrg vscreen->destroy(vscreen); 2837ec681f3Smrg FREE(context_priv); 2847ec681f3Smrg return BadAlloc; 2857ec681f3Smrg } 2867ec681f3Smrg 2877ec681f3Smrg 2887ec681f3Smrg context_priv->color_standard = 2897ec681f3Smrg debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? 2907ec681f3Smrg VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; 2917ec681f3Smrg context_priv->procamp = vl_default_procamp; 2927ec681f3Smrg 2937ec681f3Smrg vl_csc_get_matrix 2947ec681f3Smrg ( 2957ec681f3Smrg context_priv->color_standard, 2967ec681f3Smrg &context_priv->procamp, true, &csc 2977ec681f3Smrg ); 2987ec681f3Smrg vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc, 1.0f, 0.0f); 2997ec681f3Smrg 3007ec681f3Smrg context_priv->vscreen = vscreen; 3017ec681f3Smrg context_priv->pipe = pipe; 3027ec681f3Smrg context_priv->subpicture_max_width = subpic_max_w; 3037ec681f3Smrg context_priv->subpicture_max_height = subpic_max_h; 3047ec681f3Smrg 3057ec681f3Smrg context->context_id = XAllocID(dpy); 3067ec681f3Smrg context->surface_type_id = surface_type_id; 3077ec681f3Smrg context->width = width; 3087ec681f3Smrg context->height = height; 3097ec681f3Smrg context->flags = flags; 3107ec681f3Smrg context->port = port; 3117ec681f3Smrg context->privData = context_priv; 3127ec681f3Smrg 3137ec681f3Smrg SyncHandle(); 3147ec681f3Smrg 3157ec681f3Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); 3167ec681f3Smrg 3177ec681f3Smrg return Success; 3187ec681f3Smrg} 3197ec681f3Smrg 3207ec681f3SmrgPUBLIC 3217ec681f3SmrgStatus XvMCDestroyContext(Display *dpy, XvMCContext *context) 3227ec681f3Smrg{ 3237ec681f3Smrg XvMCContextPrivate *context_priv; 3247ec681f3Smrg 3257ec681f3Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context); 3267ec681f3Smrg 3277ec681f3Smrg assert(dpy); 3287ec681f3Smrg 3297ec681f3Smrg if (!context || !context->privData) 3307ec681f3Smrg return XvMCBadContext; 3317ec681f3Smrg 3327ec681f3Smrg context_priv = context->privData; 3337ec681f3Smrg context_priv->decoder->destroy(context_priv->decoder); 3347ec681f3Smrg vl_compositor_cleanup_state(&context_priv->cstate); 3357ec681f3Smrg vl_compositor_cleanup(&context_priv->compositor); 3367ec681f3Smrg context_priv->pipe->destroy(context_priv->pipe); 3377ec681f3Smrg context_priv->vscreen->destroy(context_priv->vscreen); 3387ec681f3Smrg FREE(context_priv); 3397ec681f3Smrg context->privData = NULL; 3407ec681f3Smrg 3417ec681f3Smrg XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context); 3427ec681f3Smrg 3437ec681f3Smrg return Success; 3447ec681f3Smrg} 345