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@intel.com>
26 * Zhaohan Ren <zhaohan.ren@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};
psb_doframerate(int fps)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
mask2shift(uint32_t mask)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
psb_putsurface_x11(VADriverContextP ctx,VASurfaceID surface,Drawable draw,short srcx,short srcy,unsigned short srcw,unsigned short srch,short destx,short desty,unsigned short destw,unsigned short desth,unsigned int flags)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
psb_x11_output_init(VADriverContextP ctx)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
error_handler(Display * dpy,XErrorEvent * error)349 error_handler(Display *dpy, XErrorEvent *error)
350 {
351 x11_error_code = error->error_code;
352 return 0;
353 }
354
psb_x11_output_deinit(VADriverContextP ctx)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
x11_trap_errors(void)384 x11_trap_errors(void)
385 {
386 x11_error_code = 0;
387 old_error_handler = XSetErrorHandler(error_handler);
388 }
389
390 static int
x11_untrap_errors(void)391 x11_untrap_errors(void)
392 {
393 XSetErrorHandler(old_error_handler);
394 return x11_error_code;
395 }
396
397 static int
is_window(Display * dpy,Drawable drawable)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
pnw_check_output_method(VADriverContextP ctx,object_surface_p obj_surface,int width,int height,int destw,int desth,Drawable draw)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
psb_PutSurface(VADriverContextP ctx,VASurfaceID surface,void * drawable,short srcx,short srcy,unsigned short srcw,unsigned short srch,short destx,short desty,unsigned short destw,unsigned short desth,VARectangle * cliprects,unsigned int number_cliprects,unsigned int flags)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