Home | History | Annotate | Download | only in x11
      1 /*
      2  * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the
      6  * "Software"), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sub license, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the
     13  * next paragraph) shall be included in all copies or substantial portions
     14  * of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     19  * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
     20  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     21  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     22  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  *
     24  * Authors:
     25  *    Shengquan Yuan  <shengquan.yuan (at) intel.com>
     26  *    Zhaohan Ren  <zhaohan.ren (at) intel.com>
     27  *
     28  */
     29 
     30 #include <X11/Xutil.h>
     31 #include <X11/extensions/Xrandr.h>
     32 #include <X11/extensions/dpms.h>
     33 #include <va/va_dricommon.h>
     34 #include <va/va_backend.h>
     35 #include "psb_output.h"
     36 #include "psb_surface.h"
     37 #include "psb_buffer.h"
     38 #include "psb_x11.h"
     39 #include "psb_surface_ext.h"
     40 #include "psb_drv_debug.h"
     41 
     42 #include <stdio.h>
     43 #include <string.h>
     44 #include <stdarg.h>
     45 #include "psb_surface_ext.h"
     46 #include <wsbm/wsbm_manager.h>
     47 
     48 #define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
     49 #define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
     50 
     51 #define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))
     52 #define BUFFER(id)  ((object_buffer_p) object_heap_lookup( &driver_data->buffer_heap, id ))
     53 #define IMAGE(id)  ((object_image_p) object_heap_lookup( &driver_data->image_heap, id ))
     54 #define SUBPIC(id)  ((object_subpic_p) object_heap_lookup( &driver_data->subpic_heap, id ))
     55 #define CONTEXT(id) ((object_context_p) object_heap_lookup( &driver_data->context_heap, id ))
     56 
     57 
     58 void psb_x11_freeWindowClipBoxList(psb_x11_clip_list_t * pHead);
     59 
     60 
     61 //X error trap
     62 static int x11_error_code = 0;
     63 static int (*old_error_handler)(Display *, XErrorEvent *);
     64 
     65 static struct timeval inter_period = {0};
     66 static void psb_doframerate(int fps)
     67 {
     68     struct timeval time_deta;
     69 
     70     inter_period.tv_usec += 1000000 / fps;
     71 
     72     /*recording how long it passed*/
     73     if (inter_period.tv_usec >= 1000000) {
     74         inter_period.tv_usec -= 1000000;
     75         inter_period.tv_sec++;
     76     }
     77 
     78     gettimeofday(&time_deta, (struct timezone *)NULL);
     79 
     80     time_deta.tv_usec = inter_period.tv_usec - time_deta.tv_usec;
     81     time_deta.tv_sec  = inter_period.tv_sec  - time_deta.tv_sec;
     82 
     83     if (time_deta.tv_usec < 0) {
     84         time_deta.tv_usec += 1000000;
     85         time_deta.tv_sec--;
     86     }
     87 
     88     if (time_deta.tv_sec < 0 || (time_deta.tv_sec == 0 && time_deta.tv_usec <= 0))
     89         return;
     90 
     91     select(0, NULL, NULL, NULL, &time_deta);
     92 }
     93 
     94 static uint32_t mask2shift(uint32_t mask)
     95 {
     96     uint32_t shift = 0;
     97     while ((mask & 0x1) == 0) {
     98         mask = mask >> 1;
     99         shift++;
    100     }
    101     return shift;
    102 }
    103 
    104 static VAStatus psb_putsurface_x11(
    105     VADriverContextP ctx,
    106     VASurfaceID surface,
    107     Drawable draw, /* X Drawable */
    108     short srcx,
    109     short srcy,
    110     unsigned short srcw,
    111     unsigned short srch,
    112     short destx,
    113     short desty,
    114     unsigned short destw,
    115     unsigned short desth,
    116     unsigned int flags /* de-interlacing flags */
    117 )
    118 {
    119     INIT_DRIVER_DATA;
    120     GC gc;
    121     XImage *ximg = NULL;
    122     Visual *visual;
    123     unsigned short width, height;
    124     int depth;
    125     int x = 0, y = 0;
    126     VAStatus vaStatus = VA_STATUS_SUCCESS;
    127     void *surface_data = NULL;
    128     int ret;
    129 
    130     uint32_t rmask = 0;
    131     uint32_t gmask = 0;
    132     uint32_t bmask = 0;
    133 
    134     uint32_t rshift = 0;
    135     uint32_t gshift = 0;
    136     uint32_t bshift = 0;
    137 
    138 
    139     if (srcw <= destw)
    140         width = srcw;
    141     else
    142         width = destw;
    143 
    144     if (srch <= desth)
    145         height = srch;
    146     else
    147         height = desth;
    148 
    149     object_surface_p obj_surface = SURFACE(surface);
    150     if (NULL == obj_surface) {
    151         vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
    152         DEBUG_FAILURE;
    153         return vaStatus;
    154     }
    155 
    156     psb_surface_p psb_surface = obj_surface->psb_surface;
    157 
    158     drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: src	  w x h = %d x %d\n", srcw, srch);
    159     drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: dest 	  w x h = %d x %d\n", destw, desth);
    160     drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: clipped w x h = %d x %d\n", width, height);
    161 
    162     visual = DefaultVisual((Display *)ctx->native_dpy, ctx->x11_screen);
    163     gc = XCreateGC((Display *)ctx->native_dpy, draw, 0, NULL);
    164     depth = DefaultDepth((Display *)ctx->native_dpy, ctx->x11_screen);
    165 
    166     if (TrueColor != visual->class) {
    167         drv_debug_msg(VIDEO_DEBUG_ERROR, "PutSurface: Default visual of X display must be TrueColor.\n");
    168         vaStatus = VA_STATUS_ERROR_UNKNOWN;
    169         goto out;
    170     }
    171 
    172     ret = psb_buffer_map(&psb_surface->buf, &surface_data);
    173     if (ret) {
    174         vaStatus = VA_STATUS_ERROR_UNKNOWN;
    175         goto out;
    176     }
    177 
    178     rmask = visual->red_mask;
    179     gmask = visual->green_mask;
    180     bmask = visual->blue_mask;
    181 
    182     rshift = mask2shift(rmask);
    183     gshift = mask2shift(gmask);
    184     bshift = mask2shift(bmask);
    185 
    186     drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: Pixel masks: R = %08x G = %08x B = %08x\n", rmask, gmask, bmask);
    187     drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: Pixel shifts: R = %d G = %d B = %d\n", rshift, gshift, bshift);
    188 
    189     ximg = XCreateImage((Display *)ctx->native_dpy, visual, depth, ZPixmap, 0, NULL, width, height, 32, 0);
    190 
    191     if (ximg->byte_order == MSBFirst)
    192         drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: XImage pixels has MSBFirst, %d bits / pixel\n", ximg->bits_per_pixel);
    193     else
    194         drv_debug_msg(VIDEO_DEBUG_GENERAL, "PutSurface: XImage pixels has LSBFirst, %d bits / pixel\n", ximg->bits_per_pixel);
    195 
    196     if (ximg->bits_per_pixel != 32) {
    197         drv_debug_msg(VIDEO_DEBUG_ERROR, "PutSurface: Display uses %d bits/pixel which is not supported\n");
    198         vaStatus = VA_STATUS_ERROR_UNKNOWN;
    199         goto out;
    200     }
    201 
    202     void yuv2pixel(uint32_t * pixel, int y, int u, int v) {
    203         int r, g, b;
    204         /* Warning, magic values ahead */
    205         r = y + ((351 * (v - 128)) >> 8);
    206         g = y - (((179 * (v - 128)) + (86 * (u - 128))) >> 8);
    207         b = y + ((444 * (u - 128)) >> 8);
    208 
    209         if (r > 255) r = 255;
    210         if (g > 255) g = 255;
    211         if (b > 255) b = 255;
    212         if (r < 0) r = 0;
    213         if (g < 0) g = 0;
    214         if (b < 0) b = 0;
    215 
    216         *pixel = ((r << rshift) & rmask) | ((g << gshift) & gmask) | ((b << bshift) & bmask);
    217     }
    218     ximg->data = (char *) malloc(ximg->bytes_per_line * height);
    219     if (NULL == ximg->data) {
    220         vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
    221         goto out;
    222     }
    223 
    224     uint8_t *src_y = surface_data + psb_surface->stride * srcy;
    225     uint8_t *src_uv = surface_data + psb_surface->stride * (obj_surface->height + srcy / 2);
    226 
    227     for (y = srcy; y < (srcy + height); y += 2) {
    228         uint32_t *dest_even = (uint32_t *)(ximg->data + y * ximg->bytes_per_line);
    229         uint32_t *dest_odd = (uint32_t *)(ximg->data + (y + 1) * ximg->bytes_per_line);
    230         for (x = srcx; x < (srcx + width); x += 2) {
    231             /* Y1 Y2 */
    232             /* Y3 Y4 */
    233             int y1 = *(src_y + x);
    234             int y2 = *(src_y + x + 1);
    235             int y3 = *(src_y + x + psb_surface->stride);
    236             int y4 = *(src_y + x + psb_surface->stride + 1);
    237 
    238             /* U V */
    239             int u = *(src_uv + x);
    240             int v = *(src_uv + x + 1);
    241 
    242             yuv2pixel(dest_even++, y1, u, v);
    243             yuv2pixel(dest_even++, y2, u, v);
    244 
    245             yuv2pixel(dest_odd++, y3, u, v);
    246             yuv2pixel(dest_odd++, y4, u, v);
    247         }
    248         src_y += psb_surface->stride * 2;
    249         src_uv += psb_surface->stride;
    250     }
    251 
    252     XPutImage((Display *)ctx->native_dpy, draw, gc, ximg, 0, 0, destx, desty, width, height);
    253     XFlush((Display *)ctx->native_dpy);
    254 
    255 out:
    256     if (NULL != ximg)
    257         XDestroyImage(ximg);
    258     if (NULL != surface_data)
    259         psb_buffer_unmap(&psb_surface->buf);
    260 
    261     XFreeGC((Display *)ctx->native_dpy, gc);
    262 
    263     return vaStatus;
    264 }
    265 
    266 void *psb_x11_output_init(VADriverContextP ctx)
    267 {
    268     INIT_DRIVER_DATA;
    269     psb_x11_output_p output = calloc(1, sizeof(psb_x11_output_s));
    270 
    271     if (output == NULL) {
    272         drv_debug_msg(VIDEO_DEBUG_ERROR, "Can't malloc memory\n");
    273         return NULL;
    274     }
    275 
    276     if (getenv("PSB_VIDEO_EXTEND_FULLSCREEN"))
    277         driver_data->extend_fullscreen = 1;
    278 
    279     if (getenv("PSB_VIDEO_PUTSURFACE_X11")) {
    280         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface force to SW rendering\n");
    281         driver_data->output_method = PSB_PUTSURFACE_X11;
    282 
    283         return output;
    284     }
    285 
    286     psb_init_xvideo(ctx, output);
    287 
    288     output->output_drawable = 0;
    289     output->extend_drawable = 0;
    290     output->pClipBoxList = NULL;
    291     output->ui32NumClipBoxList = 0;
    292     output->frame_count = 0;
    293     output->bIsVisible = 0;
    294 
    295     /* always init CTEXTURE and COVERLAY */
    296     driver_data->coverlay = 1;
    297     driver_data->color_key = 0x11;
    298     driver_data->ctexture = 1;
    299 
    300     driver_data->xrandr_dirty = 0;
    301     driver_data->xrandr_update = 0;
    302 
    303     if (getenv("PSB_VIDEO_EXTEND_FULLSCREEN")) {
    304         driver_data->extend_fullscreen = 1;
    305     }
    306 
    307     driver_data->xrandr_thread_id = 0;
    308     if (getenv("PSB_VIDEO_NOTRD") || IS_MRST(driver_data)) {
    309         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force not to start psb xrandr thread.\n");
    310         driver_data->use_xrandr_thread = 0;
    311     } else {
    312         drv_debug_msg(VIDEO_DEBUG_GENERAL, "By default, use psb xrandr thread.\n");
    313         driver_data->use_xrandr_thread = 1;
    314     }
    315 
    316     if (IS_MFLD(driver_data) && /* force MFLD to use COVERLAY */
    317         (driver_data->output_method == PSB_PUTSURFACE_OVERLAY)) {
    318         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Use client overlay mode for post-processing\n");
    319 
    320         driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
    321     }
    322 
    323     if (getenv("PSB_VIDEO_TEXTURE") && output->textured_portID) {
    324         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface force to use Textured Xvideo\n");
    325         driver_data->output_method = PSB_PUTSURFACE_FORCE_TEXTURE;
    326     }
    327 
    328     if (getenv("PSB_VIDEO_OVERLAY") && output->overlay_portID) {
    329         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface force to use Overlay Xvideo\n");
    330         driver_data->output_method = PSB_PUTSURFACE_FORCE_OVERLAY;
    331     }
    332 
    333     if (getenv("PSB_VIDEO_CTEXTURE")) {
    334         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface force to use Client Texture\n");
    335         driver_data->output_method = PSB_PUTSURFACE_FORCE_CTEXTURE;
    336     }
    337 
    338     if (getenv("PSB_VIDEO_COVERLAY")) {
    339         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface force to use Client Overlay\n");
    340 
    341         driver_data->coverlay = 1;
    342         driver_data->output_method = PSB_PUTSURFACE_FORCE_COVERLAY;
    343     }
    344 
    345     return output;
    346 }
    347 
    348 static int
    349 error_handler(Display *dpy, XErrorEvent *error)
    350 {
    351     x11_error_code = error->error_code;
    352     return 0;
    353 }
    354 
    355 void psb_x11_output_deinit(VADriverContextP ctx)
    356 {
    357 #ifdef _FOR_FPGA_
    358     if (getenv("PSB_VIDEO_PUTSURFACE_X11"))
    359         return;
    360     else
    361         psb_deinit_xvideo(ctx);
    362 #else
    363     INIT_DRIVER_DATA;
    364     INIT_OUTPUT_PRIV;
    365     struct dri_state *dri_state = (struct dri_state *)ctx->dri_state;
    366 
    367     psb_x11_freeWindowClipBoxList(output->pClipBoxList);
    368     output->pClipBoxList = NULL;
    369 
    370     if (output->extend_drawable) {
    371         XDestroyWindow(ctx->native_dpy, output->extend_drawable);
    372         output->extend_drawable = 0;
    373     }
    374 
    375     psb_deinit_xvideo(ctx);
    376 
    377     /* close dri fd and release all drawable buffer */
    378     if (driver_data->ctexture == 1)
    379         (*dri_state->close)(ctx);
    380 #endif
    381 }
    382 
    383 static void
    384 x11_trap_errors(void)
    385 {
    386     x11_error_code = 0;
    387     old_error_handler = XSetErrorHandler(error_handler);
    388 }
    389 
    390 static int
    391 x11_untrap_errors(void)
    392 {
    393     XSetErrorHandler(old_error_handler);
    394     return x11_error_code;
    395 }
    396 
    397 static int
    398 is_window(Display *dpy, Drawable drawable)
    399 {
    400     XWindowAttributes wattr;
    401 
    402     x11_trap_errors();
    403     XGetWindowAttributes(dpy, drawable, &wattr);
    404     return x11_untrap_errors() == 0;
    405 }
    406 
    407 static int pnw_check_output_method(VADriverContextP ctx, object_surface_p obj_surface, int width, int height, int destw, int desth, Drawable draw)
    408 {
    409     INIT_DRIVER_DATA;
    410     INIT_OUTPUT_PRIV;
    411 
    412     if (driver_data->output_method == PSB_PUTSURFACE_FORCE_TEXTURE ||
    413         driver_data->output_method == PSB_PUTSURFACE_FORCE_OVERLAY ||
    414         driver_data->output_method == PSB_PUTSURFACE_FORCE_CTEXTURE ||
    415         driver_data->output_method == PSB_PUTSURFACE_FORCE_COVERLAY) {
    416         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Force to use %08x for PutSurface\n", driver_data->output_method);
    417         return 0;
    418     }
    419 
    420     driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
    421 
    422     if (driver_data->overlay_auto_paint_color_key)
    423         driver_data->output_method = PSB_PUTSURFACE_COVERLAY;
    424 
    425     /* Avoid call is_window()/XGetWindowAttributes() every frame */
    426     if (output->output_drawable_save != draw) {
    427         output->output_drawable_save = draw;
    428         if (!is_window(ctx->native_dpy, draw))
    429             output->is_pixmap = 1;
    430         else
    431             output->is_pixmap = 0;
    432     }
    433 
    434     /*FIXME: overlay path can't handle subpicture scaling. when surface size > dest box, fallback to texblit.*/
    435     if ((output->is_pixmap == 1)
    436         || (IS_MRST(driver_data) && obj_surface->subpic_count > 0)
    437         || (obj_surface->subpic_count && ((width > destw) || (height > desth)))
    438         || (width >= 2048)
    439         || (height >= 2048)
    440        ) {
    441         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Putsurface fall back to use Client Texture\n");
    442 
    443         driver_data->output_method = PSB_PUTSURFACE_CTEXTURE;
    444     }
    445 
    446     if (IS_MFLD(driver_data) &&
    447         (driver_data->xrandr_dirty & PSB_NEW_ROTATION)) {
    448         psb_RecalcRotate(ctx);
    449         driver_data->xrandr_dirty &= ~PSB_NEW_ROTATION;
    450     }
    451 
    452     return 0;
    453 }
    454 
    455 VAStatus psb_PutSurface(
    456     VADriverContextP ctx,
    457     VASurfaceID surface,
    458     void *drawable, /* X Drawable */
    459     short srcx,
    460     short srcy,
    461     unsigned short srcw,
    462     unsigned short srch,
    463     short destx,
    464     short desty,
    465     unsigned short destw,
    466     unsigned short desth,
    467     VARectangle *cliprects, /* client supplied clip list */
    468     unsigned int number_cliprects, /* number of clip rects in the clip list */
    469     unsigned int flags /* de-interlacing flags */
    470 )
    471 {
    472     INIT_DRIVER_DATA;
    473     object_surface_p obj_surface;
    474     VAStatus vaStatus = VA_STATUS_SUCCESS;
    475     Drawable draw = (Drawable)drawable;
    476     obj_surface = SURFACE(surface);
    477 
    478     if (NULL == obj_surface) {
    479         vaStatus = VA_STATUS_ERROR_INVALID_SURFACE;
    480         DEBUG_FAILURE;
    481         return vaStatus;
    482     }
    483 
    484     if (driver_data->dummy_putsurface) {
    485         drv_debug_msg(VIDEO_DEBUG_GENERAL, "vaPutSurface: dummy mode, return directly\n");
    486         return VA_STATUS_SUCCESS;
    487     }
    488 
    489     if (driver_data->output_method == PSB_PUTSURFACE_X11) {
    490         psb_putsurface_x11(ctx, surface, draw, srcx, srcy, srcw, srch,
    491                            destx, desty, destw, desth, flags);
    492         return VA_STATUS_SUCCESS;
    493     }
    494 
    495     if (driver_data->fixed_fps > 0) {
    496         if ((inter_period.tv_sec == 0) && (inter_period.tv_usec == 0))
    497             gettimeofday(&inter_period, (struct timezone *)NULL);
    498 
    499         psb_doframerate(driver_data->fixed_fps);
    500     }
    501 
    502     pnw_check_output_method(ctx, obj_surface, srcw, srch, destw, desth, draw);
    503 
    504     pthread_mutex_lock(&driver_data->output_mutex);
    505 
    506     if ((driver_data->output_method == PSB_PUTSURFACE_CTEXTURE) ||
    507         (driver_data->output_method == PSB_PUTSURFACE_FORCE_CTEXTURE)) {
    508         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using client Texture for PutSurface\n");
    509         psb_putsurface_ctexture(ctx, surface, draw,
    510                                 srcx, srcy, srcw, srch,
    511                                 destx, desty, destw, desth,
    512                                 flags);
    513     } else if ((driver_data->output_method == PSB_PUTSURFACE_COVERLAY) ||
    514                (driver_data->output_method == PSB_PUTSURFACE_FORCE_COVERLAY)) {
    515         drv_debug_msg(VIDEO_DEBUG_GENERAL, "Using client Overlay for PutSurface\n");
    516 
    517         srcw = srcw <= 1920 ? srcw : 1920;
    518         /* init overlay*/
    519         if (!driver_data->coverlay_init) {
    520             psb_coverlay_init(ctx);
    521             driver_data->coverlay_init = 1;
    522         }
    523 
    524         psb_putsurface_coverlay(
    525             ctx, surface, draw,
    526             srcx, srcy, srcw, srch,
    527             destx, desty, destw, desth,
    528             cliprects, number_cliprects, flags);
    529     } else
    530         psb_putsurface_xvideo(
    531             ctx, surface, draw,
    532             srcx, srcy, srcw, srch,
    533             destx, desty, destw, desth,
    534             cliprects, number_cliprects, flags);
    535     pthread_mutex_unlock(&driver_data->output_mutex);
    536 
    537     driver_data->frame_count++;
    538 
    539     return VA_STATUS_SUCCESS;
    540 }
    541