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