Home | History | Annotate | Download | only in xvmc
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Younes Manton.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include <assert.h>
     29 
     30 #include <X11/Xlibint.h>
     31 #include <X11/extensions/XvMClib.h>
     32 
     33 #include "pipe/p_screen.h"
     34 #include "pipe/p_video_codec.h"
     35 #include "pipe/p_video_state.h"
     36 #include "pipe/p_state.h"
     37 
     38 #include "util/u_memory.h"
     39 
     40 #include "vl/vl_csc.h"
     41 #include "vl/vl_winsys.h"
     42 
     43 #include "xvmc_private.h"
     44 
     45 static Status Validate(Display *dpy, XvPortID port, int surface_type_id,
     46                        unsigned int width, unsigned int height, int flags,
     47                        bool *found_port, int *screen, int *chroma_format,
     48                        int *mc_type, int *surface_flags,
     49                        unsigned short *subpic_max_w,
     50                        unsigned short *subpic_max_h)
     51 {
     52    bool found_surface = false;
     53    XvAdaptorInfo *adaptor_info;
     54    unsigned int num_adaptors;
     55    int num_types;
     56    unsigned int max_width = 0, max_height = 0;
     57    Status ret;
     58 
     59    assert(dpy);
     60    assert(found_port);
     61    assert(screen);
     62    assert(chroma_format);
     63    assert(mc_type);
     64    assert(surface_flags);
     65    assert(subpic_max_w);
     66    assert(subpic_max_h);
     67 
     68    *found_port = false;
     69 
     70    for (int i = 0; i < XScreenCount(dpy); ++i) {
     71       ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info);
     72       if (ret != Success)
     73          return ret;
     74 
     75       for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) {
     76          for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) {
     77             XvMCSurfaceInfo *surface_info;
     78 
     79             if (adaptor_info[j].base_id + k != port)
     80                continue;
     81 
     82             *found_port = true;
     83 
     84             surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types);
     85             if (!surface_info) {
     86                XvFreeAdaptorInfo(adaptor_info);
     87                return BadAlloc;
     88             }
     89 
     90             for (int l = 0; l < num_types && !found_surface; ++l) {
     91                if (surface_info[l].surface_type_id != surface_type_id)
     92                   continue;
     93 
     94                found_surface = true;
     95                max_width = surface_info[l].max_width;
     96                max_height = surface_info[l].max_height;
     97                *chroma_format = surface_info[l].chroma_format;
     98                *mc_type = surface_info[l].mc_type;
     99                *surface_flags = surface_info[l].flags;
    100                *subpic_max_w = surface_info[l].subpicture_max_width;
    101                *subpic_max_h = surface_info[l].subpicture_max_height;
    102                *screen = i;
    103 
    104                XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \
    105                                     "[XvMC]   screen=%u, port=%u\n" \
    106                                     "[XvMC]   id=0x%08X\n" \
    107                                     "[XvMC]   max width=%u, max height=%u\n" \
    108                                     "[XvMC]   chroma format=0x%08X\n" \
    109                                     "[XvMC]   acceleration level=0x%08X\n" \
    110                                     "[XvMC]   flags=0x%08X\n" \
    111                                     "[XvMC]   subpicture max width=%u, max height=%u\n",
    112                                     i, port, surface_type_id, max_width, max_height, *chroma_format,
    113                                     *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h);
    114             }
    115 
    116             free(surface_info);
    117          }
    118       }
    119 
    120       XvFreeAdaptorInfo(adaptor_info);
    121    }
    122 
    123    if (!*found_port) {
    124       XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n");
    125       return XvBadPort;
    126    }
    127    if (!found_surface) {
    128       XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n");
    129       return BadMatch;
    130    }
    131    if (width > max_width || height > max_height) {
    132       XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n",
    133                width, height, max_width, max_height);
    134       return BadValue;
    135    }
    136    if (flags != XVMC_DIRECT && flags != 0) {
    137       XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags);
    138       return BadValue;
    139    }
    140 
    141    return Success;
    142 }
    143 
    144 static enum pipe_video_profile ProfileToPipe(int xvmc_profile)
    145 {
    146    if (xvmc_profile & XVMC_MPEG_1)
    147       assert(0);
    148    if (xvmc_profile & XVMC_MPEG_2)
    149       return PIPE_VIDEO_PROFILE_MPEG2_MAIN;
    150    if (xvmc_profile & XVMC_H263)
    151       assert(0);
    152    if (xvmc_profile & XVMC_MPEG_4)
    153       assert(0);
    154 
    155    assert(0);
    156 
    157    XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile);
    158 
    159    return -1;
    160 }
    161 
    162 static enum pipe_video_chroma_format FormatToPipe(int xvmc_format)
    163 {
    164    switch (xvmc_format) {
    165       case XVMC_CHROMA_FORMAT_420:
    166          return PIPE_VIDEO_CHROMA_FORMAT_420;
    167       case XVMC_CHROMA_FORMAT_422:
    168          return PIPE_VIDEO_CHROMA_FORMAT_422;
    169       case XVMC_CHROMA_FORMAT_444:
    170          return PIPE_VIDEO_CHROMA_FORMAT_444;
    171       default:
    172          assert(0);
    173    }
    174 
    175    XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format);
    176 
    177    return -1;
    178 }
    179 
    180 PUBLIC
    181 Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id,
    182                          int width, int height, int flags, XvMCContext *context)
    183 {
    184    bool found_port;
    185    int scrn = 0;
    186    int chroma_format = 0;
    187    int mc_type = 0;
    188    int surface_flags = 0;
    189    unsigned short subpic_max_w = 0;
    190    unsigned short subpic_max_h = 0;
    191    Status ret;
    192    struct vl_screen *vscreen;
    193    struct pipe_context *pipe;
    194    struct pipe_video_codec templat = {0};
    195    XvMCContextPrivate *context_priv;
    196    vl_csc_matrix csc;
    197 
    198    XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context);
    199 
    200    assert(dpy);
    201 
    202    if (!context)
    203       return XvMCBadContext;
    204 
    205    ret = Validate(dpy, port, surface_type_id, width, height, flags,
    206                   &found_port, &scrn, &chroma_format, &mc_type, &surface_flags,
    207                   &subpic_max_w, &subpic_max_h);
    208 
    209    /* Success and XvBadPort have the same value */
    210    if (ret != Success || !found_port)
    211       return ret;
    212 
    213    /* XXX: Current limits */
    214    if (chroma_format != XVMC_CHROMA_FORMAT_420) {
    215       XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n");
    216       return BadImplementation;
    217    }
    218    if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) {
    219       XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n");
    220       return BadImplementation;
    221    }
    222    if (surface_flags & XVMC_INTRA_UNSIGNED) {
    223       XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n");
    224       return BadImplementation;
    225    }
    226 
    227    context_priv = CALLOC(1, sizeof(XvMCContextPrivate));
    228    if (!context_priv)
    229       return BadAlloc;
    230 
    231    /* TODO: Reuse screen if process creates another context */
    232    vscreen = vl_dri3_screen_create(dpy, scrn);
    233    if (!vscreen)
    234       vscreen = vl_dri2_screen_create(dpy, scrn);
    235 
    236    if (!vscreen) {
    237       XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n");
    238       FREE(context_priv);
    239       return BadAlloc;
    240    }
    241 
    242    pipe = vscreen->pscreen->context_create(vscreen->pscreen, NULL, 0);
    243    if (!pipe) {
    244       XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n");
    245       vscreen->destroy(vscreen);
    246       FREE(context_priv);
    247       return BadAlloc;
    248    }
    249 
    250    templat.profile = ProfileToPipe(mc_type);
    251    templat.entrypoint = (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC;
    252    templat.chroma_format = FormatToPipe(chroma_format);
    253    templat.width = width;
    254    templat.height = height;
    255    templat.max_references = 2;
    256    templat.expect_chunked_decode = true;
    257 
    258    context_priv->decoder = pipe->create_video_codec(pipe, &templat);
    259 
    260    if (!context_priv->decoder) {
    261       XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n");
    262       pipe->destroy(pipe);
    263       vscreen->destroy(vscreen);
    264       FREE(context_priv);
    265       return BadAlloc;
    266    }
    267 
    268    if (!vl_compositor_init(&context_priv->compositor, pipe)) {
    269       XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n");
    270       context_priv->decoder->destroy(context_priv->decoder);
    271       pipe->destroy(pipe);
    272       vscreen->destroy(vscreen);
    273       FREE(context_priv);
    274       return BadAlloc;
    275    }
    276 
    277    if (!vl_compositor_init_state(&context_priv->cstate, pipe)) {
    278       XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n");
    279       vl_compositor_cleanup(&context_priv->compositor);
    280       context_priv->decoder->destroy(context_priv->decoder);
    281       pipe->destroy(pipe);
    282       vscreen->destroy(vscreen);
    283       FREE(context_priv);
    284       return BadAlloc;
    285    }
    286 
    287 
    288    context_priv->color_standard =
    289       debug_get_bool_option("G3DVL_NO_CSC", FALSE) ?
    290       VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601;
    291    context_priv->procamp = vl_default_procamp;
    292 
    293    vl_csc_get_matrix
    294    (
    295       context_priv->color_standard,
    296       &context_priv->procamp, true, &csc
    297    );
    298    vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc, 1.0f, 0.0f);
    299 
    300    context_priv->vscreen = vscreen;
    301    context_priv->pipe = pipe;
    302    context_priv->subpicture_max_width = subpic_max_w;
    303    context_priv->subpicture_max_height = subpic_max_h;
    304 
    305    context->context_id = XAllocID(dpy);
    306    context->surface_type_id = surface_type_id;
    307    context->width = width;
    308    context->height = height;
    309    context->flags = flags;
    310    context->port = port;
    311    context->privData = context_priv;
    312 
    313    SyncHandle();
    314 
    315    XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context);
    316 
    317    return Success;
    318 }
    319 
    320 PUBLIC
    321 Status XvMCDestroyContext(Display *dpy, XvMCContext *context)
    322 {
    323    XvMCContextPrivate *context_priv;
    324 
    325    XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying context %p.\n", context);
    326 
    327    assert(dpy);
    328 
    329    if (!context || !context->privData)
    330       return XvMCBadContext;
    331 
    332    context_priv = context->privData;
    333    context_priv->decoder->destroy(context_priv->decoder);
    334    vl_compositor_cleanup_state(&context_priv->cstate);
    335    vl_compositor_cleanup(&context_priv->compositor);
    336    context_priv->pipe->destroy(context_priv->pipe);
    337    context_priv->vscreen->destroy(context_priv->vscreen);
    338    FREE(context_priv);
    339    context->privData = NULL;
    340 
    341    XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p destroyed.\n", context);
    342 
    343    return Success;
    344 }
    345