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