Cope with latest MPlayer master changes.
[vaapi:mplayer.git] / libvo / vo_vaapi.c
1 /*
2  * VA API output module
3  *
4  * Copyright (C) 2008-2009 Splitted-Desktop Systems
5  *
6  * This file is part of MPlayer.
7  *
8  * MPlayer is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * MPlayer is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include "config.h"
24 #include "mp_msg.h"
25 #include "help_mp.h"
26 #include "subopt-helper.h"
27 #include "video_out.h"
28 #include "video_out_internal.h"
29 #include "fastmemcpy.h"
30 #include "sub/sub.h"
31 #include "sub/eosd.h"
32 #include "x11_common.h"
33 #include "libavutil/common.h"
34 #include "libavcodec/vaapi.h"
35 #include "gui/interface.h"
36 #include "stats.h"
37 #include <stdarg.h>
38
39 #if CONFIG_GL
40 #include "gl_common.h"
41 #include <GL/glu.h>
42 #include <GL/glx.h>
43 #endif
44
45 #include <assert.h>
46 #include <X11/Xlib.h>
47 #include <X11/Xutil.h>
48 #include <va/va_x11.h>
49 #if CONFIG_VAAPI_GLX
50 #include <va/va_glx.h>
51 #endif
52
53 #if CONFIG_XRENDER
54 #include <X11/extensions/Xrender.h>
55 #endif
56
57 /* Compatibility glue with upstream libva */
58 #ifndef VA_SDS_VERSION
59 #define VA_SDS_VERSION          0
60 #endif
61
62 /* Compatibility glue with VA-API >= 0.30 */
63 #ifndef VA_INVALID_ID
64 #define VA_INVALID_ID           0xffffffff
65 #endif
66 #ifndef VA_FOURCC
67 #define VA_FOURCC(ch0, ch1, ch2, ch3)           \
68     ((uint32_t)(uint8_t)(ch0) |                 \
69      ((uint32_t)(uint8_t)(ch1) << 8) |          \
70      ((uint32_t)(uint8_t)(ch2) << 16) |         \
71      ((uint32_t)(uint8_t)(ch3) << 24 ))
72 #endif
73 #if defined VA_SRC_BT601 && defined VA_SRC_BT709
74 # define USE_VAAPI_COLORSPACE 1
75 #else
76 # define USE_VAAPI_COLORSPACE 0
77 #endif
78
79 /* Defined to 1 if VA/GLX 'bind' API is available */
80 #define USE_VAAPI_GLX_BIND                                \
81     (VA_MAJOR_VERSION == 0 &&                             \
82      ((VA_MINOR_VERSION == 30 &&                          \
83        VA_MICRO_VERSION == 4 && VA_SDS_VERSION >= 5) ||   \
84       (VA_MINOR_VERSION == 31 &&                          \
85        VA_MICRO_VERSION == 0 && VA_SDS_VERSION >= 1 && VA_SDS_VERSION < 5)))
86
87 /* Compatibility glue with VA-API >= 0.31 */
88 #if defined VA_CHECK_VERSION
89 #if VA_CHECK_VERSION(0,31,0)
90 #define vaPutImage2             vaPutImage
91 #define vaAssociateSubpicture2  vaAssociateSubpicture
92 #endif
93 #endif
94
95 /* Compatibility glue with VA-API >= 0.31.1 */
96 #ifndef VA_SRC_SMPTE_240
97 #define VA_SRC_SMPTE_240        0x00000040
98 #endif
99 #if defined VA_FILTER_SCALING_MASK
100 # define USE_VAAPI_SCALING 1
101 #else
102 # define USE_VAAPI_SCALING 0
103 #endif
104
105 static vo_info_t info = {
106     "VA API with X11",
107     "vaapi",
108     "Gwenole Beauchesne <gbeauchesne@splitted-desktop.com>",
109     ""
110 };
111
112 const LIBVO_EXTERN(vaapi)
113
114 /* Numbers of video surfaces */
115 #define MAX_OUTPUT_SURFACES       2 /* Maintain synchronisation points in flip_page() */
116 #define MAX_VIDEO_SURFACES       21 /* Maintain free surfaces in a queue (use least-recently-used) */
117 #define NUM_VIDEO_SURFACES_MPEG2  3 /* 1 decode frame, up to  2 references */
118 #define NUM_VIDEO_SURFACES_MPEG4  3 /* 1 decode frame, up to  2 references */
119 #define NUM_VIDEO_SURFACES_H264  21 /* 1 decode frame, up to 20 references */
120 #define NUM_VIDEO_SURFACES_VC1    3 /* 1 decode frame, up to  2 references */
121
122 static void ensure_osd(void);
123 static int reset_xrender_specific(void);
124
125 typedef void (*draw_alpha_func)(int x0, int y0, int w, int h,
126                                 unsigned char *src, unsigned char *srca,
127                                 int stride);
128
129 typedef void (*eosd_draw_alpha_func)(unsigned char *src,
130                                      int src_w, int src_h, int src_stride,
131                                      int dst_x, int dst_y,
132                                      uint32_t color);
133
134 struct vaapi_surface {
135     VASurfaceID id;
136     VAImage     image;
137     int         is_bound; /* Flag: image bound to the surface? */
138 };
139
140 struct vaapi_equalizer {
141     VADisplayAttribute brightness;
142     VADisplayAttribute contrast;
143     VADisplayAttribute hue;
144     VADisplayAttribute saturation;
145 };
146
147 static int                      g_is_visible;
148 static int                      g_is_paused;
149 static uint32_t                 g_image_width;
150 static uint32_t                 g_image_height;
151 static uint32_t                 g_image_format;
152 static uint32_t                 g_image_fields;
153 static Pixmap                   g_image_pixmap;
154 static struct vo_rect           g_output_rect;
155 static struct vaapi_surface    *g_output_surfaces[MAX_OUTPUT_SURFACES];
156 static unsigned int             g_output_surface;
157 static int                      g_deint;
158 static int                      g_deint_type;
159 static int                      g_colorspace;
160 static unsigned int             g_scaling;
161
162 static int                      gl_enabled;
163 static int                      gl_use_tfp;
164 #if CONFIG_GL
165 static MPGLContext              gl_context;
166 static int                      gl_binding;
167 static int                      gl_reflect;
168 static int                      gl_finish;
169 static GLuint                   gl_texture;
170 static GLuint                   gl_font_base;
171 static Pixmap                   gl_pixmap;
172 static int                      gl_visual_attr[] = {
173     GLX_RGBA,
174     GLX_RED_SIZE, 1,
175     GLX_GREEN_SIZE, 1,
176     GLX_BLUE_SIZE, 1,
177     GLX_DOUBLEBUFFER,
178     GL_NONE
179 };
180 #endif
181
182 #if CONFIG_VAAPI_GLX
183 static void                    *gl_surface;
184 #endif
185
186 static int                      xr_enabled;
187 #if CONFIG_XRENDER
188 static Picture                  xr_video_picture;
189 static Picture                  xr_window_picture;
190 #endif
191
192 static struct vaapi_context    *va_context;
193 static VAProfile               *va_profiles;
194 static int                      va_num_profiles;
195 static VAEntrypoint            *va_entrypoints;
196 static int                      va_num_entrypoints;
197 static VASurfaceID             *va_surface_ids;
198 static int                      va_num_surfaces;
199 static struct vaapi_surface   **va_free_surfaces;
200 static int                      va_free_surfaces_head_index;
201 static int                      va_free_surfaces_tail_index;
202 static VAImageFormat           *va_image_formats;
203 static int                      va_num_image_formats;
204 static VAImageFormat           *va_subpic_formats;
205 static unsigned int            *va_subpic_flags;
206 static int                      va_num_subpic_formats;
207 static VAImage                  va_osd_image;
208 static uint8_t                 *va_osd_image_data;
209 static VASubpictureID           va_osd_subpicture;
210 static int                      va_osd_associated;
211 static draw_alpha_func          va_osd_draw_alpha;
212 static uint8_t                 *va_osd_palette;
213 static struct vaapi_equalizer   va_equalizer;
214 static VAImage                  va_eosd_image;
215 static uint8_t                 *va_eosd_image_data;
216 static VASubpictureID           va_eosd_subpicture;
217 static int                      va_eosd_associated;
218 static eosd_draw_alpha_func     va_eosd_draw_alpha;
219
220 ///< Flag: direct surface mapping: use mpi->number to select free VA surface?
221 static int                      va_dm;
222
223 ///< Flag: gather run-time statistics (CPU usage, frequency)
224 static int                      cpu_stats;
225 static unsigned int             cpu_frequency;
226 static float                    cpu_usage;
227
228 // X error trap
229 static int x11_error_code = 0;
230 static int (*old_error_handler)(Display *, XErrorEvent *);
231
232 static int error_handler(Display *dpy, XErrorEvent *error)
233 {
234     x11_error_code = error->error_code;
235     return 0;
236 }
237
238 static void x11_trap_errors(void)
239 {
240     x11_error_code    = 0;
241     old_error_handler = XSetErrorHandler(error_handler);
242 }
243
244 static int x11_untrap_errors(void)
245 {
246     XSetErrorHandler(old_error_handler);
247     return x11_error_code;
248 }
249
250 static int check_status(VAStatus status, const char *msg)
251 {
252     if (status != VA_STATUS_SUCCESS) {
253         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] %s: %s\n", msg, vaErrorStr(status));
254         return 0;
255     }
256     return 1;
257 }
258
259 static const char *string_of_VAImageFormat(VAImageFormat *imgfmt)
260 {
261     static char str[5];
262     str[0] = imgfmt->fourcc;
263     str[1] = imgfmt->fourcc >> 8;
264     str[2] = imgfmt->fourcc >> 16;
265     str[3] = imgfmt->fourcc >> 24;
266     str[4] = '\0';
267     return str;
268 }
269
270 static const char *string_of_VAProfile(VAProfile profile)
271 {
272     switch (profile) {
273 #define PROFILE(profile) \
274         case VAProfile##profile: return "VAProfile" #profile
275         PROFILE(MPEG2Simple);
276         PROFILE(MPEG2Main);
277         PROFILE(MPEG4Simple);
278         PROFILE(MPEG4AdvancedSimple);
279         PROFILE(MPEG4Main);
280         PROFILE(H264Baseline);
281         PROFILE(H264Main);
282         PROFILE(H264High);
283         PROFILE(VC1Simple);
284         PROFILE(VC1Main);
285         PROFILE(VC1Advanced);
286 #undef PROFILE
287     }
288     return "<unknown>";
289 }
290
291 static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
292 {
293     switch (entrypoint) {
294 #define ENTRYPOINT(entrypoint) \
295         case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
296         ENTRYPOINT(VLD);
297         ENTRYPOINT(IZZ);
298         ENTRYPOINT(IDCT);
299         ENTRYPOINT(MoComp);
300         ENTRYPOINT(Deblocking);
301 #undef ENTRYPOINT
302     }
303     return "<unknown>";
304 }
305
306 static int has_profile(VAProfile profile)
307 {
308     if (va_profiles && va_num_profiles > 0) {
309         int i;
310         for (i = 0; i < va_num_profiles; i++) {
311             if (va_profiles[i] == profile)
312                 return 1;
313         }
314     }
315     return 0;
316 }
317
318 static int VAProfile_from_imgfmt(uint32_t format)
319 {
320     static const int mpeg2_profiles[] =
321         { VAProfileMPEG2Main, VAProfileMPEG2Simple, -1 };
322     static const int mpeg4_profiles[] =
323         { VAProfileMPEG4Main, VAProfileMPEG4AdvancedSimple, VAProfileMPEG4Simple, -1 };
324     static const int h264_profiles[] =
325         { VAProfileH264High, VAProfileH264Main, VAProfileH264Baseline, -1 };
326     static const int wmv3_profiles[] =
327         { VAProfileVC1Main, VAProfileVC1Simple, -1 };
328     static const int vc1_profiles[] =
329         { VAProfileVC1Advanced, -1 };
330
331     const int *profiles = NULL;
332     switch (IMGFMT_VAAPI_CODEC(format)) {
333     case IMGFMT_VAAPI_CODEC_MPEG2:
334         profiles = mpeg2_profiles;
335         break;
336     case IMGFMT_VAAPI_CODEC_MPEG4:
337         profiles = mpeg4_profiles;
338         break;
339     case IMGFMT_VAAPI_CODEC_H264:
340         profiles = h264_profiles;
341         break;
342     case IMGFMT_VAAPI_CODEC_VC1:
343         switch (format) {
344         case IMGFMT_VAAPI_WMV3:
345             profiles = wmv3_profiles;
346             break;
347         case IMGFMT_VAAPI_VC1:
348             profiles = vc1_profiles;
349             break;
350         }
351         break;
352     }
353
354     if (profiles) {
355         for (int i = 0; profiles[i] != -1; i++) {
356             if (has_profile(profiles[i]))
357                 return profiles[i];
358         }
359     }
360     return -1;
361 }
362
363 static int has_entrypoint(VAEntrypoint entrypoint)
364 {
365     if (va_entrypoints && va_num_entrypoints > 0) {
366         int i;
367         for (i = 0; i < va_num_entrypoints; i++) {
368             if (va_entrypoints[i] == entrypoint)
369                 return 1;
370         }
371     }
372     return 0;
373 }
374
375 static int VAEntrypoint_from_imgfmt(uint32_t format)
376 {
377     int entrypoint = 0;
378     switch (format) {
379     case IMGFMT_VAAPI_MPEG2:
380     case IMGFMT_VAAPI_MPEG4:
381     case IMGFMT_VAAPI_H263:
382     case IMGFMT_VAAPI_H264:
383     case IMGFMT_VAAPI_WMV3:
384     case IMGFMT_VAAPI_VC1:
385         entrypoint = VAEntrypointVLD;
386         break;
387     case IMGFMT_VAAPI_MPEG2_IDCT:
388         entrypoint = VAEntrypointIDCT;
389         break;
390     case IMGFMT_VAAPI_MPEG2_MOCO:
391         entrypoint = VAEntrypointMoComp;
392         break;
393     }
394
395     if (entrypoint)
396         return has_entrypoint(entrypoint);
397
398     return -1;
399 }
400
401 static VAImageFormat *find_image_format(uint32_t fourcc)
402 {
403     if (va_image_formats && va_num_image_formats > 0) {
404         int i;
405         for (i = 0; i < va_num_image_formats; i++) {
406             if (va_image_formats[i].fourcc == fourcc)
407                 return &va_image_formats[i];
408         }
409     }
410     return NULL;
411 }
412
413 static VAImageFormat *VAImageFormat_from_imgfmt(uint32_t format)
414 {
415     uint32_t fourcc = 0;
416
417     switch (format) {
418     case IMGFMT_NV12: fourcc = VA_FOURCC('N','V','1','2'); break;
419     case IMGFMT_YV12: fourcc = VA_FOURCC('Y','V','1','2'); break;
420     case IMGFMT_I420: fourcc = VA_FOURCC('I','4','2','0'); break;
421     case IMGFMT_IYUV: fourcc = VA_FOURCC('I','Y','U','V'); break;
422     }
423
424     if (fourcc)
425         return find_image_format(fourcc);
426
427     return NULL;
428 }
429
430 static struct vaapi_surface *alloc_vaapi_surface(unsigned int width,
431                                                  unsigned int height,
432                                                  unsigned int format)
433 {
434     struct vaapi_surface *surface = NULL;
435     struct vaapi_surface **surfaces;
436     VASurfaceID *surface_ids;
437     VAStatus status;
438
439     surface = calloc(1, sizeof(*surface));
440     if (!surface)
441         goto error;
442
443     surfaces = realloc(va_free_surfaces,
444                        (1 + va_num_surfaces) * sizeof(surfaces[0]));
445     if (!surfaces)
446         goto error;
447
448     surface_ids = realloc(va_surface_ids,
449                           (1 + va_num_surfaces) * sizeof(surface_ids[0]));
450     if (!surface_ids)
451         goto error;
452
453     status = vaCreateSurfaces(va_context->display, width, height, format,
454                               1, &surface->id);
455     if (!check_status(status, "vaCreateSurfaces()"))
456         goto error;
457
458     va_surface_ids                    = surface_ids;
459     va_surface_ids[va_num_surfaces]   = surface->id;
460     va_free_surfaces                  = surfaces;
461     va_free_surfaces[va_num_surfaces] = surface;
462     surface->image.image_id           = VA_INVALID_ID;
463     surface->image.buf                = VA_INVALID_ID;
464     ++va_num_surfaces;
465     return surface;
466 error:
467     free(surface);
468     return NULL;
469 }
470
471 static void resize(void)
472 {
473     struct vo_rect src;
474
475     calc_src_dst_rects(g_image_width, g_image_height,
476                        &src, &g_output_rect, NULL, NULL);
477
478     ensure_osd();
479
480     vo_x11_clearwindow(mDisplay, vo_window);
481
482 #if CONFIG_GL
483 #define FOVY     60.0f
484 #define ASPECT   1.0f
485 #define Z_NEAR   0.1f
486 #define Z_FAR    100.0f
487 #define Z_CAMERA 0.869f
488
489     if (gl_enabled) {
490         glViewport(0, 0, vo_dwidth, vo_dheight);
491         glMatrixMode(GL_PROJECTION);
492         glLoadIdentity();
493         gluPerspective(FOVY, ASPECT, Z_NEAR, Z_FAR);
494         glMatrixMode(GL_MODELVIEW);
495         glLoadIdentity();
496
497         glTranslatef(-0.5f, -0.5f, -Z_CAMERA);
498         glScalef(1.0f / (GLfloat)vo_dwidth,
499                  -1.0f / (GLfloat)vo_dheight,
500                  1.0f / (GLfloat)vo_dwidth);
501         glTranslatef(0.0f, -1.0f * (GLfloat)vo_dheight, 0.0f);
502     }
503 #endif
504
505 #if CONFIG_XRENDER
506     if (xr_enabled)
507         reset_xrender_specific();
508 #endif
509
510     if (g_is_visible)
511         flip_page();
512 }
513
514 #if CONFIG_GL
515 static int gl_build_font(void)
516 {
517     XFontStruct *fi;
518
519     gl_font_base = glGenLists(96);
520
521     fi = XLoadQueryFont(mDisplay, "-adobe-helvetica-medium-r-normal--16-*-*-*-p-*-iso8859-1" );
522     if (!fi) {
523         fi = XLoadQueryFont(mDisplay, "fixed");
524         if (!fi)
525             return -1;
526     }
527
528     glXUseXFont(fi->fid, 32, 96, gl_font_base);
529     XFreeFont(mDisplay, fi);
530     return 0;
531 }
532
533 static void gl_printf(const char *format, ...)
534 {
535     va_list args;
536     char *text;
537     int textlen;
538
539     va_start(args, format);
540     textlen = vsnprintf(NULL, 0, format, args);
541     va_end(args);
542
543     text = malloc(textlen + 1);
544     if (!text)
545         return;
546
547     va_start(args, format);
548     vsprintf(text, format, args);
549     va_end(args);
550
551     glPushAttrib(GL_LIST_BIT);
552     glListBase(gl_font_base - 32);
553     glCallLists(textlen, GL_UNSIGNED_BYTE, text);
554     glPopAttrib();
555     free(text);
556 }
557
558 static void gl_draw_rectangle(int x, int y, int w, int h, unsigned int rgba)
559 {
560     glColor4f((GLfloat)((rgba >> 24) & 0xff) / 255.0,
561               (GLfloat)((rgba >> 16) & 0xff) / 255.0,
562               (GLfloat)((rgba >> 8) & 0xff) / 255.0,
563               (GLfloat)(rgba & 0xff) / 255.0);
564
565     glTranslatef((GLfloat)x, (GLfloat)y, 0.0f);
566     glBegin(GL_QUADS);
567     {
568         glVertex2i(0, 0);
569         glVertex2i(w, 0);
570         glVertex2i(w, h);
571         glVertex2i(0, h);
572     }
573     glEnd();
574 }
575 #endif
576
577 #if CONFIG_XRENDER
578 static int init_xrender(void)
579 {
580     int dummy;
581
582     return XRenderQueryExtension(mDisplay, &dummy, &dummy);
583 }
584
585 static void uninit_xrender(void)
586 {
587 }
588 #endif
589
590 static inline unsigned char *get_osd_image_data(int x0, int y0)
591 {
592     return (va_osd_image_data +
593             va_osd_image.offsets[0] +
594             va_osd_image.pitches[0] * y0 +
595             x0 * ((va_osd_image.format.bits_per_pixel + 7) / 8));
596 }
597
598 static void draw_alpha_rgb32(int x0, int y0, int w, int h,
599                              unsigned char *src, unsigned char *srca,
600                              int stride)
601 {
602     int x, y;
603     const unsigned int dststride = va_osd_image.pitches[0];
604     unsigned char *dst = get_osd_image_data(x0, y0);
605
606     for (y = 0; y < h; y++, dst += dststride, src += stride, srca += stride)
607         for (x = 0; x < w; x++) {
608             const unsigned char c = src[x];
609             dst[4*x + 0] = c;
610             dst[4*x + 1] = c;
611             dst[4*x + 2] = c;
612             dst[4*x + 3] = -srca[x];
613         }
614 }
615
616 static void draw_alpha_IA44(int x0, int y0, int w, int h,
617                             unsigned char *src, unsigned char *srca,
618                             int stride)
619 {
620     int x, y;
621     const unsigned int dststride = va_osd_image.pitches[0];
622     unsigned char *dst = get_osd_image_data(x0, y0);
623
624     for (y = 0; y < h; y++, dst += dststride)
625         for (x = 0; x < w; x++)
626             dst[x] = (src[y*stride + x] >> 4) | (-srca[y*stride + x] & 0xf0);
627 }
628
629 static void draw_alpha_AI44(int x0, int y0, int w, int h,
630                             unsigned char *src, unsigned char *srca,
631                             int stride)
632 {
633     int x, y;
634     const unsigned int dststride = va_osd_image.pitches[0];
635     unsigned char *dst = get_osd_image_data(x0, y0);
636
637     for (y = 0; y < h; y++, dst += dststride)
638         for (x = 0; x < w; x++)
639             dst[x] = (src[y*stride + x] & 0xf0) | (-srca[y*stride + x] >> 4);
640 }
641
642 static void draw_alpha_IA88(int x0, int y0, int w, int h,
643                             unsigned char *src, unsigned char *srca,
644                             int stride)
645 {
646     int x, y;
647     const unsigned int dststride = va_osd_image.pitches[0];
648     unsigned char *dst = get_osd_image_data(x0, y0);
649
650     for (y = 0; y < h; y++, dst += dststride)
651         for (x = 0; x < w; x++) {
652             dst[2*x + 0] =  src [y*stride + x];
653             dst[2*x + 1] = -srca[y*stride + x];
654         }
655 }
656
657 static void draw_alpha_AI88(int x0, int y0, int w, int h,
658                             unsigned char *src, unsigned char *srca,
659                             int stride)
660 {
661     int x, y;
662     const unsigned int dststride = va_osd_image.pitches[0];
663     unsigned char *dst = get_osd_image_data(x0, y0);
664
665     for (y = 0; y < h; y++, dst += dststride)
666         for (x = 0; x < w; x++) {
667             dst[2*x + 0] = -srca[y*stride + x];
668             dst[2*x + 1] =  src [y*stride + x];
669         }
670 }
671
672 ///< List of subpicture formats in preferred order
673 static const struct {
674     uint32_t format;
675     draw_alpha_func draw_alpha;
676 }
677 va_osd_info[] = {
678     { VA_FOURCC('I','A','4','4'), draw_alpha_IA44  },
679     { VA_FOURCC('A','I','4','4'), draw_alpha_AI44  },
680     { VA_FOURCC('I','A','8','8'), draw_alpha_IA88  },
681     { VA_FOURCC('A','I','8','8'), draw_alpha_AI88  },
682     { VA_FOURCC('B','G','R','A'), draw_alpha_rgb32 },
683     { VA_FOURCC('R','G','B','A'), draw_alpha_rgb32 },
684     { 0, NULL }
685 };
686
687 static uint8_t *gen_osd_palette(const VAImage *image)
688 {
689     uint8_t *palette;
690     int i, is_rgb;
691     int r_idx = -1, g_idx = -1, b_idx = -1;
692     int y_idx = -1, u_idx = -1, v_idx = -1;
693     int i_idx = -1, a_idx = -1;
694
695     if (image->num_palette_entries < 1)
696         return NULL;
697
698     palette = malloc(image->num_palette_entries * image->entry_bytes);
699     if (!palette)
700         return NULL;
701
702     for (i = 0; i < image->entry_bytes; i++) {
703         switch (image->component_order[i]) {
704         case 'R': r_idx = i; is_rgb = 1; break;
705         case 'G': g_idx = i; is_rgb = 1; break;
706         case 'B': b_idx = i; is_rgb = 1; break;
707         case 'Y': y_idx = i; is_rgb = 0; break;
708         case 'U': u_idx = i; is_rgb = 0; break;
709         case 'V': v_idx = i; is_rgb = 0; break;
710         case 'I': i_idx = i; break;
711         case 'A': a_idx = i; break;
712         }
713     }
714
715     if (r_idx != -1 && g_idx != -1 && b_idx != -1) {      /* RGB format */
716         for (i = 0; i < image->num_palette_entries; i++) {
717             const int n = i * image->entry_bytes;
718             palette[n + r_idx] = i * 0xff / (image->num_palette_entries - 1);
719             palette[n + g_idx] = i * 0xff / (image->num_palette_entries - 1);
720             palette[n + b_idx] = i * 0xff / (image->num_palette_entries - 1);
721         }
722     }
723     else if (y_idx != -1 && u_idx != -1 && v_idx != -1) { /* YUV format */
724         for (i = 0; i < image->num_palette_entries; i++) {
725             const int n = i * image->entry_bytes;
726             palette[n + y_idx] = i * 0xff / (image->num_palette_entries - 1);
727             palette[n + u_idx] = 0x80;
728             palette[n + v_idx] = 0x80;
729         }
730     }
731     else if (i_idx != -1 && a_idx != -1) {/* AYUV format (GMA500 "psb" bug) */
732         for (i = 0; i < image->num_palette_entries; i++) {
733             const int n = i * image->entry_bytes;
734             palette[n + 0] = 0x80;
735             palette[n + 1] = 0x80;
736             palette[n + 2] = 16 + i * 220 / (image->num_palette_entries - 1);
737             palette[n + 3] = 0;
738         }
739     }
740     else {
741         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not set up subpicture palette\n");
742         free(palette);
743         palette = NULL;
744     }
745     return palette;
746 }
747
748 static void disable_osd(void)
749 {
750     if (!va_osd_associated)
751         return;
752
753     vaDeassociateSubpicture(va_context->display,
754                             va_osd_subpicture,
755                             va_surface_ids, va_num_surfaces);
756
757     va_osd_associated = 0;
758 }
759
760 static int enable_osd(void)
761 {
762     VAStatus status;
763
764     disable_osd();
765
766     status = vaAssociateSubpicture2(va_context->display,
767                                     va_osd_subpicture,
768                                     va_surface_ids, va_num_surfaces,
769                                     0, 0,
770                                     va_osd_image.width, va_osd_image.height,
771                                     0, 0,
772                                     g_image_width, g_image_height,
773                                     0);
774     if (!check_status(status, "vaAssociateSubpicture()"))
775         return -1;
776
777     va_osd_associated = 1;
778     return 0;
779 }
780
781 static void destroy_osd(void)
782 {
783     disable_osd();
784
785     if (va_osd_subpicture != VA_INVALID_ID) {
786         vaDestroySubpicture(va_context->display, va_osd_subpicture);
787         va_osd_subpicture = VA_INVALID_ID;
788     }
789
790     if (va_osd_image.image_id != VA_INVALID_ID) {
791         vaDestroyImage(va_context->display, va_osd_image.image_id);
792         va_osd_image.image_id = VA_INVALID_ID;
793         va_osd_image.width    = 0;
794         va_osd_image.height   = 0;
795     }
796 }
797
798 static void create_osd(void)
799 {
800     VAStatus status;
801     int i, j;
802
803     for (i = 0; va_osd_info[i].format; i++) {
804         for (j = 0; j < va_num_subpic_formats; j++)
805             if (va_subpic_formats[j].fourcc == va_osd_info[i].format)
806                 break;
807         if (j < va_num_subpic_formats &&
808             vaCreateImage(va_context->display, &va_subpic_formats[j],
809                           g_output_rect.width, g_output_rect.height,
810                           &va_osd_image) == VA_STATUS_SUCCESS) {
811             va_osd_palette = gen_osd_palette(&va_osd_image);
812             if (((!va_osd_image.num_palette_entries) ^ (!va_osd_palette)) == 0)
813                 break;
814             vaDestroyImage(va_context->display, va_osd_image.image_id);
815             va_osd_image.image_id = VA_INVALID_ID;
816         }
817     }
818
819     if (va_osd_info[i].format &&
820         vaCreateSubpicture(va_context->display, va_osd_image.image_id,
821                            &va_osd_subpicture) == VA_STATUS_SUCCESS) {
822         va_osd_draw_alpha = va_osd_info[i].draw_alpha;
823         if (va_osd_palette) {
824             status = vaSetImagePalette(va_context->display,
825                                        va_osd_image.image_id, va_osd_palette);
826             check_status(status, "vaSetImagePalette()");
827         }
828         mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for OSD\n",
829                string_of_VAImageFormat(&va_osd_image.format));
830     }
831 }
832
833 static void ensure_osd(void)
834 {
835     if (g_output_rect.width  == va_osd_image.width &&
836         g_output_rect.height == va_osd_image.height)
837         return;
838
839     destroy_osd();
840     create_osd();
841 }
842
843 static inline unsigned char *get_eosd_image_data(int x0, int y0)
844 {
845     return (va_eosd_image_data +
846             va_eosd_image.offsets[0] +
847             va_eosd_image.pitches[0] * y0 +
848             x0 * ((va_eosd_image.format.bits_per_pixel + 7) / 8));
849 }
850
851 static void eosd_draw_alpha_bgra(unsigned char *src,
852                                  int src_w, int src_h, int src_stride,
853                                  int dst_x, int dst_y,
854                                  uint32_t color)
855 {
856     int x, y;
857     const unsigned int dst_stride = va_eosd_image.pitches[0];
858     unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
859     const unsigned int r = (color >> 24) & 0xff;
860     const unsigned int g = (color >> 16) & 0xff;
861     const unsigned int b = (color >>  8) & 0xff;
862     const unsigned int a = 0xff - (color & 0xff);
863
864     for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
865         for (x = 0; x < src_w; x++) {
866             const unsigned int v = src[x];
867             dst[4*x + 0] = (b * v + dst[4*x + 0] * (0xff - v)) / 255;
868             dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
869             dst[4*x + 2] = (r * v + dst[4*x + 2] * (0xff - v)) / 255;
870             dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
871         }
872 }
873
874 static void eosd_draw_alpha_rgba(unsigned char *src,
875                                  int src_w, int src_h, int src_stride,
876                                  int dst_x, int dst_y,
877                                  uint32_t color)
878 {
879     int x, y;
880     const unsigned int dst_stride = va_eosd_image.pitches[0];
881     unsigned char *dst = get_eosd_image_data(dst_x, dst_y);
882     const unsigned int r = (color >> 24) & 0xff;
883     const unsigned int g = (color >> 16) & 0xff;
884     const unsigned int b = (color >>  8) & 0xff;
885     const unsigned int a = 0xff - (color & 0xff);
886
887     for (y = 0; y < src_h; y++, dst += dst_stride, src += src_stride)
888         for (x = 0; x < src_w; x++) {
889             const unsigned int v = src[x];
890             dst[4*x + 0] = (r * v + dst[4*x + 0] * (0xff - v)) / 255;
891             dst[4*x + 1] = (g * v + dst[4*x + 1] * (0xff - v)) / 255;
892             dst[4*x + 2] = (b * v + dst[4*x + 2] * (0xff - v)) / 255;
893             dst[4*x + 3] = (a * v + dst[4*x + 3] * (0xff - v)) / 255;
894         }
895 }
896
897 static void disable_eosd(void)
898 {
899     if (!va_eosd_associated)
900         return;
901
902     vaDeassociateSubpicture(va_context->display,
903                             va_eosd_subpicture,
904                             va_surface_ids, va_num_surfaces);
905
906     va_eosd_associated = 0;
907 }
908
909 static int enable_eosd(void)
910 {
911     VAStatus status;
912
913     if (va_eosd_associated)
914         return 0;
915
916     status = vaAssociateSubpicture2(va_context->display,
917                                     va_eosd_subpicture,
918                                     va_surface_ids, va_num_surfaces,
919                                     0, 0, g_image_width, g_image_height,
920                                     0, 0, g_image_width, g_image_height,
921                                     0);
922     if (!check_status(status, "vaAssociateSubpicture()"))
923         return -1;
924
925     va_eosd_associated = 1;
926     return 0;
927 }
928
929 ///< List of subpicture formats in preferred order
930 static const struct {
931     uint32_t format;
932     eosd_draw_alpha_func draw_alpha;
933 }
934 va_eosd_info[] = {
935     { VA_FOURCC('B','G','R','A'), eosd_draw_alpha_bgra },
936     { VA_FOURCC('R','G','B','A'), eosd_draw_alpha_rgba },
937     { 0, NULL }
938 };
939
940 static int is_direct_mapping_init(void)
941 {
942     VADisplayAttribute attr;
943     VAStatus status;
944
945     if (va_dm < 2)
946         return va_dm;
947
948     /* If the driver doesn't make a copy of the VA surface for
949        display, then we have to retain it until it's no longer the
950        visible surface. In other words, if the driver is using
951        DirectSurface mode, we don't want to decode the new surface
952        into the previous one that was used for display. */
953     attr.type  = VADisplayAttribDirectSurface;
954     attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
955
956     status = vaGetDisplayAttributes(va_context->display, &attr, 1);
957     if (status == VA_STATUS_SUCCESS)
958         return !attr.value;
959     return 0;
960 }
961
962 static inline int is_direct_mapping(void)
963 {
964     static int dm = -1;
965     if (dm < 0) {
966         dm = is_direct_mapping_init();
967         if (dm)
968             mp_msg(MSGT_VO, MSGL_INFO,
969                    "[vo_vaapi] Using 1:1 VA surface mapping\n");
970     }
971     return dm;
972 }
973
974 static int int_012(int *n)
975 {
976     return *n >= 0 && *n <= 2;
977 }
978
979 #if USE_VAAPI_SCALING
980 static strarg_t g_scaling_arg = { 0, NULL };
981
982 static int test_scaling_arg(void *arg)
983 {
984     strarg_t * const strarg = arg;
985
986     return (strargcmp(strarg, "default") == 0 ||
987             strargcmp(strarg, "fast") == 0 ||
988             strargcmp(strarg, "hq") == 0);
989 }
990
991 static void setup_scaling(const char *scaling)
992 {
993     if (strcmp(scaling, "default") == 0)
994         g_scaling = VA_FILTER_SCALING_DEFAULT;
995     else if (strcmp(scaling, "fast") == 0)
996         g_scaling = VA_FILTER_SCALING_FAST;
997     else if (strcmp(scaling, "hq") == 0)
998         g_scaling = VA_FILTER_SCALING_HQ;
999     else if (strcmp(scaling, "nla") == 0)
1000         g_scaling = VA_FILTER_SCALING_NL_ANAMORPHIC;
1001 }
1002 #endif
1003
1004 static const opt_t subopts[] = {
1005     { "dm",          OPT_ARG_INT,  &va_dm,        (opt_test_f)int_012 },
1006     { "stats",       OPT_ARG_BOOL, &cpu_stats,    NULL },
1007     { "deint",       OPT_ARG_INT,  &g_deint,      (opt_test_f)int_012 },
1008 #if USE_VAAPI_COLORSPACE
1009     { "colorspace",  OPT_ARG_INT,  &g_colorspace, (opt_test_f)int_012 },
1010 #endif
1011 #if USE_VAAPI_SCALING
1012     { "scaling",     OPT_ARG_STR,  &g_scaling_arg, test_scaling_arg },
1013 #endif
1014 #if CONFIG_GL
1015     { "gl",          OPT_ARG_BOOL, &gl_enabled,   NULL },
1016     { "glfinish",    OPT_ARG_BOOL, &gl_finish,    NULL },
1017 #if USE_VAAPI_GLX_BIND
1018     { "bind",        OPT_ARG_BOOL, &gl_binding,   NULL },
1019 #endif
1020     { "reflect",     OPT_ARG_BOOL, &gl_reflect,   NULL },
1021     { "tfp",         OPT_ARG_BOOL, &gl_use_tfp,   NULL },
1022 #endif
1023 #if CONFIG_XRENDER
1024     { "xrender",     OPT_ARG_BOOL, &xr_enabled,   NULL },
1025 #endif
1026     { NULL, }
1027 };
1028
1029 static int preinit(const char *arg)
1030 {
1031     VADisplayAttribute *display_attrs;
1032     VAStatus status;
1033     int va_major_version, va_minor_version;
1034     int i, max_image_formats, max_subpic_formats, max_profiles;
1035     int num_display_attrs, max_display_attrs;
1036
1037     va_dm = 2;
1038     g_deint = 0;
1039     g_deint_type = 2;
1040     g_colorspace = 1;
1041     g_scaling = 0;
1042     if (subopt_parse(arg, subopts) != 0) {
1043         mp_msg(MSGT_VO, MSGL_FATAL,
1044                "\n-vo vaapi command line help:\n"
1045                "Example: mplayer -vo vaapi:gl\n"
1046                "\nOptions:\n"
1047                "  dm\n"
1048                "    0: use least-recently-used VA surface\n"
1049                "    1: identify VA surface with MPI index\n"
1050                "    2: auto-detect use of direct surface mapping (default)\n"
1051                "  deint (all modes > 0 respect -field-dominance)\n"
1052                "    0: no deinterlacing (default)\n"
1053                "    1: only show first field\n"
1054                "    2: bob deinterlacing\n"
1055 #if USE_VAAPI_COLORSPACE
1056                "  colorspace\n"
1057                "    0: guess based on video resolution\n"
1058                "    1: ITU-R BT.601 (default)\n"
1059                "    2: ITU-R BT.709\n"
1060                "    3: SMPTE-240M\n"
1061 #endif
1062 #if USE_VAAPI_SCALING
1063                "  scaling\n"
1064                "    default: use implementation default (default)\n"
1065                "    fast:    use fast scaling, but possibly with less quality\n"
1066                "    hq:      use high-quality scaling, but possibly slower\n"
1067                "    nla:     use non-linear anamorphic scaling\n"
1068 #endif
1069 #if CONFIG_GL
1070                "  gl\n"
1071                "    Enable OpenGL rendering\n"
1072                "  glfinish\n"
1073                "    Call glFinish() before swapping buffers\n"
1074                "  tfp\n"
1075                "    Use GLX texture-from-pixmap instead of VA/GLX extensions\n"
1076 #if USE_VAAPI_GLX_BIND
1077                "  bind\n"
1078                "    Use VA surface binding instead of copy\n"
1079 #endif
1080                "  reflect\n"
1081                "    Enable OpenGL reflection effects\n"
1082 #endif
1083 #if CONFIG_XRENDER
1084                "  xrender\n"
1085                "    Enable Xrender rendering, thus vaPutSurface() to a Pixmap\n"
1086 #endif
1087                "\n" );
1088         return -1;
1089     }
1090     if (gl_enabled && xr_enabled) {
1091         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] User requested both Xrender and OpenGL rendering\n");
1092         return -1;
1093     }
1094     if (g_deint)
1095         g_deint_type = g_deint;
1096 #if CONFIG_GL
1097     if (gl_enabled)
1098         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using OpenGL rendering%s\n",
1099                gl_reflect ? ", with reflection effects" : "");
1100 #endif
1101 #if CONFIG_XRENDER
1102     if (xr_enabled)
1103         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using Xrender rendering\n");
1104 #endif
1105 #if USE_VAAPI_SCALING
1106     if (g_scaling_arg.str) {
1107         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using '%s' scaling\n", g_scaling_arg.str);
1108         setup_scaling(g_scaling_arg.str);
1109     }
1110 #endif
1111
1112     stats_init();
1113
1114 #if CONFIG_GL
1115     if (gl_enabled && !init_mpglcontext(&gl_context, GLTYPE_X11))
1116         return -1;
1117     else
1118 #endif
1119     if (!vo_init())
1120         return -1;
1121 #if CONFIG_XRENDER
1122     if (xr_enabled && !init_xrender())
1123         return -1;
1124 #endif
1125
1126     va_context = calloc(1, sizeof(*va_context));
1127     if (!va_context)
1128         return -1;
1129
1130 #if CONFIG_VAAPI_GLX
1131     if (gl_enabled)
1132         va_context->display = vaGetDisplayGLX(mDisplay);
1133     else
1134 #endif
1135         va_context->display = vaGetDisplay(mDisplay);
1136     if (!va_context->display)
1137         return -1;
1138     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA display %p\n", va_context->display);
1139
1140     status = vaInitialize(va_context->display, &va_major_version, &va_minor_version);
1141     if (!check_status(status, "vaInitialize()"))
1142         return -1;
1143     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): VA API version %d.%d\n",
1144            va_major_version, va_minor_version);
1145
1146     max_image_formats = vaMaxNumImageFormats(va_context->display);
1147     va_image_formats = calloc(max_image_formats, sizeof(*va_image_formats));
1148     if (!va_image_formats)
1149         return -1;
1150     status = vaQueryImageFormats(va_context->display, va_image_formats, &va_num_image_formats);
1151     if (!check_status(status, "vaQueryImageFormats()"))
1152         return -1;
1153     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d image formats available\n",
1154            va_num_image_formats);
1155     for (i = 0; i < va_num_image_formats; i++)
1156         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAImageFormat(&va_image_formats[i]));
1157
1158     max_subpic_formats = vaMaxNumSubpictureFormats(va_context->display);
1159     va_subpic_formats = calloc(max_subpic_formats, sizeof(*va_subpic_formats));
1160     if (!va_subpic_formats)
1161         return -1;
1162     va_subpic_flags = calloc(max_subpic_formats, sizeof(*va_subpic_flags));
1163     if (!va_subpic_flags)
1164         return -1;
1165     status = vaQuerySubpictureFormats(va_context->display, va_subpic_formats, va_subpic_flags, &va_num_subpic_formats);
1166     if (!check_status(status, "vaQuerySubpictureFormats()"))
1167         va_num_subpic_formats = 0; /* XXX: don't error out for IEGD */
1168     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d subpicture formats available\n",
1169            va_num_subpic_formats);
1170     for (i = 0; i < va_num_subpic_formats; i++)
1171         mp_msg(MSGT_VO, MSGL_DBG2, "  %s, flags 0x%x\n", string_of_VAImageFormat(&va_subpic_formats[i]), va_subpic_flags[i]);
1172
1173     max_profiles = vaMaxNumProfiles(va_context->display);
1174     va_profiles = calloc(max_profiles, sizeof(*va_profiles));
1175     if (!va_profiles)
1176         return -1;
1177     status = vaQueryConfigProfiles(va_context->display, va_profiles, &va_num_profiles);
1178     if (!check_status(status, "vaQueryConfigProfiles()"))
1179         return -1;
1180     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] preinit(): %d profiles available\n",
1181            va_num_profiles);
1182     for (i = 0; i < va_num_profiles; i++)
1183         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAProfile(va_profiles[i]));
1184
1185     va_osd_subpicture      = VA_INVALID_ID;
1186     va_osd_image.image_id  = VA_INVALID_ID;
1187     va_eosd_subpicture     = VA_INVALID_ID;
1188     va_eosd_image.image_id = VA_INVALID_ID;
1189
1190     max_display_attrs = vaMaxNumDisplayAttributes(va_context->display);
1191     display_attrs = calloc(max_display_attrs, sizeof(*display_attrs));
1192     if (display_attrs) {
1193         num_display_attrs = 0;
1194         status = vaQueryDisplayAttributes(va_context->display,
1195                                           display_attrs, &num_display_attrs);
1196         if (check_status(status, "vaQueryDisplayAttributes()")) {
1197             for (i = 0; i < num_display_attrs; i++) {
1198                 VADisplayAttribute *attr;
1199                 switch (display_attrs[i].type) {
1200                 case VADisplayAttribBrightness:
1201                     attr = &va_equalizer.brightness;
1202                     break;
1203                 case VADisplayAttribContrast:
1204                     attr = &va_equalizer.contrast;
1205                     break;
1206                 case VADisplayAttribHue:
1207                     attr = &va_equalizer.hue;
1208                     break;
1209                 case VADisplayAttribSaturation:
1210                     attr = &va_equalizer.saturation;
1211                     break;
1212                 default:
1213                     attr = NULL;
1214                     break;
1215                 }
1216                 if (attr)
1217                     *attr = display_attrs[i];
1218             }
1219         }
1220         free(display_attrs);
1221     }
1222     return 0;
1223 }
1224
1225 static void free_video_specific(void)
1226 {
1227     int i;
1228
1229 #if CONFIG_VAAPI_GLX
1230     if (gl_surface) {
1231         VAStatus status;
1232         status = vaDestroySurfaceGLX(va_context->display, gl_surface);
1233         check_status(status, "vaDestroySurfaceGLX()");
1234         gl_surface = NULL;
1235     }
1236 #endif
1237
1238     if (va_context && va_context->context_id) {
1239         vaDestroyContext(va_context->display, va_context->context_id);
1240         va_context->context_id = 0;
1241     }
1242
1243     if (va_free_surfaces) {
1244         for (i = 0; i < va_num_surfaces; i++) {
1245             if (!va_free_surfaces[i])
1246                 continue;
1247             if (va_free_surfaces[i]->image.image_id != VA_INVALID_ID) {
1248                 vaDestroyImage(va_context->display,
1249                                va_free_surfaces[i]->image.image_id);
1250                 va_free_surfaces[i]->image.image_id = VA_INVALID_ID;
1251             }
1252             free(va_free_surfaces[i]);
1253             va_free_surfaces[i] = NULL;
1254         }
1255         free(va_free_surfaces);
1256         va_free_surfaces = NULL;
1257         va_free_surfaces_head_index = 0;
1258         va_free_surfaces_tail_index = 0;
1259     }
1260
1261     g_output_surface = 0;
1262     memset(g_output_surfaces, 0, sizeof(g_output_surfaces));
1263
1264     if (va_osd_palette) {
1265         free(va_osd_palette);
1266         va_osd_palette = NULL;
1267     }
1268
1269     disable_eosd();
1270     disable_osd();
1271
1272     if (va_eosd_subpicture != VA_INVALID_ID) {
1273         vaDestroySubpicture(va_context->display, va_eosd_subpicture);
1274         va_eosd_subpicture = VA_INVALID_ID;
1275     }
1276
1277     if (va_eosd_image.image_id != VA_INVALID_ID) {
1278         vaDestroyImage(va_context->display, va_eosd_image.image_id);
1279         va_eosd_image.image_id = VA_INVALID_ID;
1280     }
1281
1282     destroy_osd();
1283
1284     if (va_surface_ids) {
1285         vaDestroySurfaces(va_context->display, va_surface_ids, va_num_surfaces);
1286         free(va_surface_ids);
1287         va_surface_ids = NULL;
1288         va_num_surfaces = 0;
1289     }
1290
1291     if (va_context && va_context->config_id) {
1292         vaDestroyConfig(va_context->display, va_context->config_id);
1293         va_context->config_id = 0;
1294     }
1295
1296     if (va_entrypoints) {
1297         free(va_entrypoints);
1298         va_entrypoints = NULL;
1299     }
1300
1301 #if CONFIG_GL
1302     if (gl_pixmap) {
1303         x11_trap_errors();
1304         mpglXDestroyPixmap(mDisplay, gl_pixmap);
1305         XSync(mDisplay, False);
1306         x11_untrap_errors();
1307         gl_pixmap = None;
1308     }
1309
1310     if (g_image_pixmap) {
1311         XFreePixmap(mDisplay, g_image_pixmap);
1312         g_image_pixmap = None;
1313     }
1314
1315     if (gl_texture) {
1316         glDeleteTextures(1, &gl_texture);
1317         gl_texture = GL_NONE;
1318     }
1319 #endif
1320
1321 #if CONFIG_XRENDER
1322     if (xr_window_picture) {
1323         XRenderFreePicture(mDisplay, xr_window_picture);
1324         xr_window_picture = None;
1325     }
1326 #endif
1327
1328     g_is_visible = 0;
1329 }
1330
1331 static void uninit(void)
1332 {
1333     if (!vo_config_count)
1334         return;
1335
1336     free_video_specific();
1337
1338     if (va_profiles) {
1339         free(va_profiles);
1340         va_profiles = NULL;
1341     }
1342
1343     if (va_subpic_flags) {
1344         free(va_subpic_flags);
1345         va_subpic_flags = NULL;
1346     }
1347
1348     if (va_subpic_formats) {
1349         free(va_subpic_formats);
1350         va_subpic_formats = NULL;
1351     }
1352
1353     if (va_image_formats) {
1354         free(va_image_formats);
1355         va_image_formats = NULL;
1356     }
1357
1358     if (va_context && va_context->display) {
1359         vaTerminate(va_context->display);
1360         va_context->display = NULL;
1361     }
1362
1363     if (va_context) {
1364         free(va_context);
1365         va_context = NULL;
1366     }
1367
1368 #ifdef CONFIG_XF86VM
1369     vo_vm_close();
1370 #endif
1371 #if CONFIG_XRENDER
1372     if (xr_enabled)
1373         uninit_xrender();
1374 #endif
1375 #if CONFIG_GL
1376     if (gl_enabled)
1377         uninit_mpglcontext(&gl_context);
1378     else
1379 #endif
1380     vo_x11_uninit();
1381
1382     stats_exit();
1383 }
1384
1385 static int config_x11(uint32_t width, uint32_t height,
1386                       uint32_t display_width, uint32_t display_height,
1387                       uint32_t flags, char *title)
1388 {
1389     Colormap cmap;
1390     XVisualInfo visualInfo;
1391     XVisualInfo *vi;
1392     XSetWindowAttributes xswa;
1393     unsigned long xswa_mask;
1394     XWindowAttributes wattr;
1395     int depth;
1396
1397 #ifdef CONFIG_GUI
1398     if (use_gui)
1399         guiGetEvent(guiSetShVideo, 0);  // the GUI will set up / resize our window
1400     else
1401 #endif
1402     {
1403 #ifdef CONFIG_XF86VM
1404         if (flags & VOFLAG_MODESWITCHING)
1405             vo_vm_switch();
1406 #endif
1407         XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &wattr);
1408         depth = wattr.depth;
1409         if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
1410             depth = 24;
1411         XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &visualInfo);
1412
1413 #if CONFIG_GL
1414         if (gl_enabled) {
1415             vi = glXChooseVisual(mDisplay, mScreen, gl_visual_attr);
1416             if (!vi)
1417                 return -1;
1418             cmap = XCreateColormap(mDisplay, mRootWin, vi->visual, AllocNone);
1419             if (cmap == None)
1420                 return -1;
1421         }
1422         else
1423 #endif
1424         {
1425             vi = &visualInfo;
1426             XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, vi);
1427             cmap = CopyFromParent;
1428         }
1429
1430         vo_x11_create_vo_window(vi,
1431                                 vo_dx, vo_dy, display_width, display_height,
1432                                 flags, cmap, "vaapi", title);
1433
1434         if (vi != &visualInfo)
1435             XFree(vi);
1436
1437         xswa_mask             = CWBorderPixel | CWBackPixel;
1438         xswa.border_pixel     = 0;
1439         xswa.background_pixel = 0;
1440         XChangeWindowAttributes(mDisplay, vo_window, xswa_mask, &xswa);
1441
1442 #ifdef CONFIG_XF86VM
1443         if (flags & VOFLAG_MODESWITCHING) {
1444             /* Grab the mouse pointer in our window */
1445             if (vo_grabpointer)
1446                 XGrabPointer(mDisplay, vo_window, True, 0,
1447                              GrabModeAsync, GrabModeAsync,
1448                              vo_window, None, CurrentTime);
1449             XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
1450         }
1451 #endif
1452     }
1453     return 0;
1454 }
1455
1456 #if CONFIG_GL
1457 static GLXFBConfig *get_fbconfig_for_depth(int depth)
1458 {
1459     GLXFBConfig *fbconfigs, *ret = NULL;
1460     int          n_elements, i, found;
1461     int          db, stencil, alpha, mipmap, rgba, value;
1462
1463     static GLXFBConfig *cached_config = NULL;
1464     static int          have_cached_config = 0;
1465
1466     if (have_cached_config)
1467         return cached_config;
1468
1469     fbconfigs = glXGetFBConfigs(mDisplay, mScreen, &n_elements);
1470
1471     db      = SHRT_MAX;
1472     stencil = SHRT_MAX;
1473     mipmap  = 0;
1474     rgba    = 0;
1475
1476     found = n_elements;
1477
1478     for (i = 0; i < n_elements; i++) {
1479         XVisualInfo *vi;
1480         int          visual_depth;
1481
1482         vi = glXGetVisualFromFBConfig(mDisplay, fbconfigs[i]);
1483         if (!vi)
1484             continue;
1485
1486         visual_depth = vi->depth;
1487         XFree(vi);
1488
1489         if (visual_depth != depth)
1490             continue;
1491
1492         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_ALPHA_SIZE, &alpha);
1493         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_BUFFER_SIZE, &value);
1494         if (value != depth && (value - alpha) != depth)
1495             continue;
1496
1497         value = 0;
1498         if (depth == 32) {
1499             glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
1500                                  GLX_BIND_TO_TEXTURE_RGBA_EXT, &value);
1501             if (value)
1502                 rgba = 1;
1503         }
1504
1505         if (!value) {
1506             if (rgba)
1507                 continue;
1508
1509             glXGetFBConfigAttrib(mDisplay, fbconfigs[i],
1510                                  GLX_BIND_TO_TEXTURE_RGB_EXT, &value);
1511             if (!value)
1512                 continue;
1513         }
1514
1515         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_DOUBLEBUFFER, &value);
1516         if (value > db)
1517             continue;
1518         db = value;
1519
1520         glXGetFBConfigAttrib(mDisplay, fbconfigs[i], GLX_STENCIL_SIZE, &value);
1521         if (value > stencil)
1522             continue;
1523         stencil = value;
1524
1525         found = i;
1526     }
1527
1528     if (found != n_elements) {
1529         ret = malloc(sizeof(*ret));
1530         *ret = fbconfigs[found];
1531     }
1532
1533     if (n_elements)
1534         XFree(fbconfigs);
1535
1536     have_cached_config = 1;
1537     cached_config = ret;
1538     return ret;
1539 }
1540
1541 static int config_tfp(unsigned int width, unsigned int height)
1542 {
1543     GLXFBConfig *fbconfig;
1544     int attribs[7], i = 0;
1545     const int depth = 24;
1546
1547     if (!mpglXBindTexImage || !mpglXReleaseTexImage) {
1548         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] No GLX texture-from-pixmap extension available\n");
1549         return -1;
1550     }
1551
1552     if (depth != 24 && depth != 32)
1553         return -1;
1554
1555     g_image_pixmap = XCreatePixmap(mDisplay, vo_window, width, height, depth);
1556     if (!g_image_pixmap) {
1557         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create X11 pixmap\n");
1558         return -1;
1559     }
1560
1561     fbconfig = get_fbconfig_for_depth(depth);
1562     if (!fbconfig) {
1563         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not find an FBConfig for 32-bit pixmap\n");
1564         return -1;
1565     }
1566
1567     attribs[i++] = GLX_TEXTURE_TARGET_EXT;
1568     attribs[i++] = GLX_TEXTURE_2D_EXT;
1569     attribs[i++] = GLX_TEXTURE_FORMAT_EXT;
1570     if (depth == 24)
1571         attribs[i++] = GLX_TEXTURE_FORMAT_RGB_EXT;
1572     else if (depth == 32)
1573         attribs[i++] = GLX_TEXTURE_FORMAT_RGBA_EXT;
1574     attribs[i++] = GLX_MIPMAP_TEXTURE_EXT;
1575     attribs[i++] = GL_FALSE;
1576     attribs[i++] = None;
1577
1578     x11_trap_errors();
1579     gl_pixmap = mpglXCreatePixmap(mDisplay, *fbconfig, g_image_pixmap, attribs);
1580     XSync(mDisplay, False);
1581     if (x11_untrap_errors()) {
1582         mp_msg(MSGT_VO, MSGL_ERR, "[vo_vaapi] Could not create GLX pixmap\n");
1583         return -1;
1584     }
1585     return 0;
1586 }
1587
1588 static int config_glx(unsigned int width, unsigned int height)
1589 {
1590     if (gl_context.setGlWindow(&gl_context) == SET_WINDOW_FAILED)
1591         return -1;
1592
1593     glDisable(GL_DEPTH_TEST);
1594     glDepthMask(GL_FALSE);
1595     glDisable(GL_CULL_FACE);
1596     glEnable(GL_TEXTURE_2D);
1597     glDrawBuffer(vo_doublebuffering ? GL_BACK : GL_FRONT);
1598     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1599     glEnable(GL_BLEND);
1600     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1601
1602     /* Create TFP resources */
1603     if (gl_use_tfp && config_tfp(width, height) == 0)
1604         mp_msg(MSGT_VO, MSGL_INFO, "[vo_vaapi] Using GLX texture-from-pixmap extension\n");
1605     else
1606         gl_use_tfp = 0;
1607
1608     /* Create OpenGL texture */
1609     /* XXX: assume GL_ARB_texture_non_power_of_two is available */
1610     glEnable(GL_TEXTURE_2D);
1611     glGenTextures(1, &gl_texture);
1612     mpglBindTexture(GL_TEXTURE_2D, gl_texture);
1613     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1614     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1615     if (!gl_use_tfp) {
1616         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1617         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1618         glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1619         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
1620                      GL_BGRA, GL_UNSIGNED_BYTE, NULL);
1621     }
1622     mpglBindTexture(GL_TEXTURE_2D, 0);
1623     glDisable(GL_TEXTURE_2D);
1624
1625     glClearColor(0.0, 0.0, 0.0, 1.0);
1626     glClear(GL_COLOR_BUFFER_BIT);
1627
1628     if (gl_build_font() < 0)
1629         return -1;
1630     return 0;
1631 }
1632 #endif
1633
1634 #if CONFIG_XRENDER
1635 static XRenderPictFormat *get_xrender_argb32_format(void)
1636 {
1637     static XRenderPictFormat *pictformat = NULL;
1638     XRenderPictFormat templ;
1639
1640     const unsigned long mask =
1641         PictFormatType      |
1642         PictFormatDepth     |
1643         PictFormatRed       |
1644         PictFormatRedMask   |
1645         PictFormatGreen     |
1646         PictFormatGreenMask |
1647         PictFormatBlue      |
1648         PictFormatBlueMask  |
1649         PictFormatAlphaMask;
1650
1651     if (pictformat)
1652         return pictformat;
1653
1654     /* First, look for a 32-bit format which ignores the alpha component */
1655     templ.depth            = 32;
1656     templ.type             = PictTypeDirect;
1657     templ.direct.red       = 16;
1658     templ.direct.green     = 8;
1659     templ.direct.blue      = 0;
1660     templ.direct.redMask   = 0xff;
1661     templ.direct.greenMask = 0xff;
1662     templ.direct.blueMask  = 0xff;
1663     templ.direct.alphaMask = 0;
1664
1665     pictformat = XRenderFindFormat(mDisplay, mask, &templ, 0);
1666
1667     if (!pictformat) {
1668         /* Not all X servers support xRGB32 formats. However, the
1669          * XRENDER spec says that they must support an ARGB32 format,
1670          * so we can always return that.
1671          */
1672         pictformat = XRenderFindStandardFormat(mDisplay, PictStandardARGB32);
1673         if (!pictformat)
1674             mp_msg(MSGT_VO, MSGL_ERR, "XRENDER ARGB32 format not supported\n");
1675     }
1676     return pictformat;
1677 }
1678
1679 static int create_xrender_specific(void)
1680 {
1681     XRenderPictFormat *pictformat;
1682
1683     if (g_output_rect.width == 0 && g_output_rect.height == 0)
1684         return 0;
1685
1686     g_image_pixmap = XCreatePixmap(mDisplay, vo_window, g_output_rect.width,
1687                                    g_output_rect.height, 32);
1688     if (!g_image_pixmap) {
1689         mp_msg(MSGT_VO, MSGL_ERR, "Could not create video pixmap\n");
1690         return -1;
1691     }
1692
1693     pictformat = get_xrender_argb32_format();
1694     if (!pictformat)
1695         return -1;
1696     xr_video_picture = XRenderCreatePicture(mDisplay, g_image_pixmap,
1697                                             pictformat, 0, NULL);
1698     if (!xr_video_picture) {
1699         mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Pixmap\n");
1700         return -1;
1701     }
1702     return 0;
1703 }
1704
1705 static void free_xrender_specific(void)
1706 {
1707     if (xr_video_picture) {
1708         XRenderFreePicture(mDisplay, xr_video_picture);
1709         xr_video_picture = None;
1710     }
1711
1712     if (g_image_pixmap) {
1713         XFreePixmap(mDisplay, g_image_pixmap);
1714         g_image_pixmap = None;
1715     }
1716 }
1717
1718 static int reset_xrender_specific(void)
1719 {
1720     free_xrender_specific();
1721     return create_xrender_specific();
1722 }
1723
1724 /* XXX: create a Pixmap as large as the display rect */
1725 static int config_xrender(unsigned int width, unsigned int height)
1726 {
1727     XWindowAttributes wattr;
1728     XRenderPictFormat *pictformat;
1729
1730     XGetWindowAttributes(mDisplay, vo_window, &wattr);
1731     pictformat = XRenderFindVisualFormat(mDisplay, wattr.visual);
1732     if (!pictformat) {
1733         mp_msg(MSGT_VO, MSGL_ERR, "XRENDER does not support Window visual\n");
1734         return -1;
1735     }
1736
1737     xr_window_picture = XRenderCreatePicture(mDisplay, vo_window, pictformat,
1738                                              0, NULL);
1739     if (!xr_window_picture) {
1740         mp_msg(MSGT_VO, MSGL_ERR, "Could not create XRENDER backing picture for Window\n");
1741         return -1;
1742     }
1743     return reset_xrender_specific();
1744 }
1745 #endif
1746
1747 static int config_vaapi(uint32_t width, uint32_t height, uint32_t format)
1748 {
1749     VAConfigAttrib attrib;
1750     VAStatus status;
1751     int i, j, profile, entrypoint, max_entrypoints, num_surfaces;
1752
1753     /* Create video surfaces */
1754     if (!IMGFMT_IS_VAAPI(format))
1755         num_surfaces = MAX_OUTPUT_SURFACES;
1756     else {
1757         switch (IMGFMT_VAAPI_CODEC(format)) {
1758         case IMGFMT_VAAPI_CODEC_MPEG2:
1759             num_surfaces = NUM_VIDEO_SURFACES_MPEG2;
1760             break;
1761         case IMGFMT_VAAPI_CODEC_MPEG4:
1762             num_surfaces = NUM_VIDEO_SURFACES_MPEG4;
1763             break;
1764         case IMGFMT_VAAPI_CODEC_H264:
1765             num_surfaces = NUM_VIDEO_SURFACES_H264;
1766             break;
1767         case IMGFMT_VAAPI_CODEC_VC1:
1768             num_surfaces = NUM_VIDEO_SURFACES_VC1;
1769             break;
1770         default:
1771             num_surfaces = 0;
1772             break;
1773         }
1774         if (num_surfaces == 0)
1775             return -1;
1776         if (!is_direct_mapping())
1777             num_surfaces = FFMIN(2 * num_surfaces, MAX_VIDEO_SURFACES);
1778     }
1779     for (i = 0; i < num_surfaces; i++) {
1780         struct vaapi_surface *surface;
1781         surface = alloc_vaapi_surface(width, height, VA_RT_FORMAT_YUV420);
1782         if (!surface)
1783             return -1;
1784     }
1785     assert(va_num_surfaces == num_surfaces);
1786
1787 #if CONFIG_VAAPI_GLX
1788     /* Create GLX surfaces */
1789     if (gl_enabled && !gl_use_tfp) {
1790         status = vaCreateSurfaceGLX(va_context->display,
1791                                     GL_TEXTURE_2D, gl_texture,
1792                                     &gl_surface);
1793         if (!check_status(status, "vaCreateSurfaceGLX()"))
1794             return -1;
1795     }
1796 #endif
1797
1798     /* Create OSD data */
1799     va_osd_draw_alpha     = NULL;
1800     va_osd_image.image_id = VA_INVALID_ID;
1801     va_osd_image.buf      = VA_INVALID_ID;
1802     va_osd_subpicture     = VA_INVALID_ID;
1803     ensure_osd();
1804
1805     /* Create EOSD data */
1806     va_eosd_draw_alpha     = NULL;
1807     va_eosd_image.image_id = VA_INVALID_ID;
1808     va_eosd_image.buf      = VA_INVALID_ID;
1809     va_eosd_subpicture     = VA_INVALID_ID;
1810     for (i = 0; va_eosd_info[i].format; i++) {
1811         for (j = 0; j < va_num_subpic_formats; j++)
1812             if (va_subpic_formats[j].fourcc == va_eosd_info[i].format)
1813                 break;
1814         if (j < va_num_subpic_formats &&
1815             vaCreateImage(va_context->display, &va_subpic_formats[j],
1816                           width, height, &va_eosd_image) == VA_STATUS_SUCCESS)
1817             break;
1818     }
1819     if (va_eosd_info[i].format &&
1820         vaCreateSubpicture(va_context->display, va_eosd_image.image_id,
1821                            &va_eosd_subpicture) == VA_STATUS_SUCCESS) {
1822         va_eosd_draw_alpha = va_eosd_info[i].draw_alpha;
1823         mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using %s surface for EOSD\n",
1824                string_of_VAImageFormat(&va_eosd_image.format));
1825     }
1826
1827     /* Allocate VA images */
1828     if (!IMGFMT_IS_VAAPI(format)) {
1829         VAImageFormat *image_format = VAImageFormat_from_imgfmt(format);
1830         if (!image_format)
1831             return -1;
1832         for (i = 0; i < va_num_surfaces; i++) {
1833             struct vaapi_surface * const s = va_free_surfaces[i];
1834             s->is_bound = 0;
1835             status = vaDeriveImage(va_context->display, s->id, &s->image);
1836             if (status == VA_STATUS_SUCCESS) {
1837                 /* vaDeriveImage() is supported, check format */
1838                 if (s->image.format.fourcc != image_format->fourcc) {
1839                     vaDestroyImage(va_context->display, s->image.image_id);
1840                     return -1;
1841                 }
1842                 if (s->image.width == width && s->image.height == height) {
1843                     s->is_bound = 1;
1844                     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] Using vaDeriveImage()\n");
1845                 }
1846                 else {
1847                     vaDestroyImage(va_context->display, s->image.image_id);
1848                     status = VA_STATUS_ERROR_OPERATION_FAILED;
1849                 }
1850                 
1851             }
1852             if (status != VA_STATUS_SUCCESS) {
1853                 status = vaCreateImage(va_context->display, image_format,
1854                                        width, height, &s->image);
1855                 if (!check_status(status, "vaCreateImage()"))
1856                     return -1;
1857             }
1858         }
1859         return 0;
1860     }
1861
1862     /* Check profile */
1863     profile = VAProfile_from_imgfmt(format);
1864     if (profile < 0)
1865         return -1;
1866
1867     /* Check entry-point (only VLD for now) */
1868     max_entrypoints = vaMaxNumEntrypoints(va_context->display);
1869     va_entrypoints = calloc(max_entrypoints, sizeof(*va_entrypoints));
1870     if (!va_entrypoints)
1871         return -1;
1872
1873     status = vaQueryConfigEntrypoints(va_context->display, profile,
1874                                       va_entrypoints, &va_num_entrypoints);
1875     if (!check_status(status, "vaQueryConfigEntrypoints()"))
1876         return -1;
1877
1878     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config_vaapi(%s): %d entrypoints available\n",
1879            string_of_VAProfile(profile), va_num_entrypoints);
1880     for (i = 0; i < va_num_entrypoints; i++)
1881         mp_msg(MSGT_VO, MSGL_DBG2, "  %s\n", string_of_VAEntrypoint(va_entrypoints[i]));
1882
1883     entrypoint = VAEntrypoint_from_imgfmt(format);
1884     if (entrypoint != VAEntrypointVLD)
1885         return -1;
1886
1887     /* Check chroma format (only 4:2:0 for now) */
1888     attrib.type = VAConfigAttribRTFormat;
1889     status = vaGetConfigAttributes(va_context->display, profile, entrypoint, &attrib, 1);
1890     if (!check_status(status, "vaGetConfigAttributes()"))
1891         return -1;
1892     if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
1893         return -1;
1894
1895     /* Create a configuration for the decode pipeline */
1896     status = vaCreateConfig(va_context->display, profile, entrypoint, &attrib, 1, &va_context->config_id);
1897     if (!check_status(status, "vaCreateConfig()"))
1898         return -1;
1899
1900     /* Create a context for the decode pipeline */
1901     status = vaCreateContext(va_context->display, va_context->config_id,
1902                              width, height, VA_PROGRESSIVE,
1903                              va_surface_ids, va_num_surfaces,
1904                              &va_context->context_id);
1905     if (!check_status(status, "vaCreateContext()"))
1906         return -1;
1907     return 0;
1908 }
1909
1910 static int config(uint32_t width, uint32_t height,
1911                   uint32_t display_width, uint32_t display_height,
1912                   uint32_t flags, char *title, uint32_t format)
1913 {
1914     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] config(): size %dx%d, display size %dx%d, flags %x, title '%s', format %x (%s)\n",
1915            width, height, display_width, display_height, flags, title, format, vo_format_name(format));
1916
1917     free_video_specific();
1918
1919     if (config_x11(width, height, display_width, display_height, flags, title) < 0)
1920         return -1;
1921
1922 #if CONFIG_GL
1923     if (gl_enabled && config_glx(width, height) < 0)
1924         return -1;
1925 #endif
1926
1927 #if CONFIG_XRENDER
1928     if (xr_enabled && config_xrender(width, height) < 0)
1929         return -1;
1930 #endif
1931
1932     if (config_vaapi(width, height, format) < 0)
1933         return -1;
1934
1935     g_is_visible   = 0;
1936     g_is_paused    = 0;
1937     g_image_width  = width;
1938     g_image_height = height;
1939     g_image_format = format;
1940     resize();
1941     return 0;
1942 }
1943
1944 static int query_format(uint32_t format)
1945 {
1946     const int default_caps = (VFCAP_CSP_SUPPORTED |
1947                               VFCAP_CSP_SUPPORTED_BY_HW |
1948                               VFCAP_HWSCALE_UP |
1949                               VFCAP_HWSCALE_DOWN |
1950                               VFCAP_OSD |
1951                               VFCAP_EOSD);
1952
1953     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] query_format(): format %x (%s)\n",
1954            format, vo_format_name(format));
1955
1956     switch (format) {
1957     case IMGFMT_VAAPI_MPEG2:
1958     case IMGFMT_VAAPI_MPEG4:
1959     case IMGFMT_VAAPI_H263:
1960     case IMGFMT_VAAPI_H264:
1961     case IMGFMT_VAAPI_WMV3:
1962     case IMGFMT_VAAPI_VC1:
1963         return default_caps | VOCAP_NOSLICES;
1964     case IMGFMT_NV12:
1965     case IMGFMT_YV12:
1966     case IMGFMT_I420:
1967     case IMGFMT_IYUV:
1968         if (VAImageFormat_from_imgfmt(format))
1969             return default_caps;
1970         break;
1971     }
1972     return 0;
1973 }
1974
1975 static inline int get_field_flags(int i)
1976 {
1977     return (g_deint && (g_image_fields & MP_IMGFIELD_INTERLACED) ? 
1978             (((!!(g_image_fields & MP_IMGFIELD_TOP_FIRST)) ^ i) == 0 ?
1979              VA_BOTTOM_FIELD : VA_TOP_FIELD) : VA_FRAME_PICTURE);
1980 }
1981
1982 static inline int get_colorspace_flags(void)
1983 {
1984     int csp = 0;
1985 #if USE_VAAPI_COLORSPACE
1986     switch (g_colorspace) {
1987     case 0:
1988         csp = ((g_image_width >= 1280 || g_image_height > 576) ?
1989                VA_SRC_BT709 : VA_SRC_BT601);
1990         break;
1991     case 1:
1992         csp = VA_SRC_BT601;
1993         break;
1994     case 2:
1995         csp = VA_SRC_BT709;
1996         break;
1997     case 3:
1998         csp = VA_SRC_SMPTE_240;
1999         break;
2000     default:
2001         assert(0);
2002         break;
2003     }
2004 #endif
2005     return csp;
2006 }
2007
2008 static void put_surface_x11(struct vaapi_surface *surface)
2009 {
2010     VAStatus status;
2011     int i;
2012
2013     for (i = 0; i <= !!(g_deint > 1); i++) {
2014         const unsigned int flags = (get_field_flags(i) |
2015                                     get_colorspace_flags() |
2016                                     g_scaling);
2017         status = vaPutSurface(va_context->display,
2018                               surface->id,
2019                               vo_window,
2020                               0, 0, g_image_width, g_image_height,
2021                               g_output_rect.left,
2022                               g_output_rect.top,
2023                               g_output_rect.width,
2024                               g_output_rect.height,
2025                               NULL, 0,
2026                               flags);
2027         if (!check_status(status, "vaPutSurface()"))
2028             return;
2029     }
2030 }
2031
2032 #if CONFIG_GL
2033 static void put_surface_glx(struct vaapi_surface *surface)
2034 {
2035     VAStatus status;
2036     int i;
2037
2038     if (gl_use_tfp) {
2039         for (i = 0; i <= !!(g_deint > 1); i++) {
2040             const unsigned int flags = (get_field_flags(i) |
2041                                         get_colorspace_flags() |
2042                                         g_scaling);
2043             status = vaPutSurface(va_context->display,
2044                                   surface->id,
2045                                   g_image_pixmap,
2046                                   0, 0, g_image_width, g_image_height,
2047                                   0, 0, g_image_width, g_image_height,
2048                                   NULL, 0,
2049                                   flags);
2050             if (!check_status(status, "vaPutSurface()"))
2051                 return;
2052         }
2053         g_output_surfaces[g_output_surface] = surface;
2054         return;
2055     }
2056
2057 #if CONFIG_VAAPI_GLX
2058     if (gl_binding) {
2059 #if USE_VAAPI_GLX_BIND
2060         for (i = 0; i <= !!(g_deint > 1); i++) {
2061             const unsigned int flags = (get_field_flags(i) |
2062                                         get_colorspace_flags() |
2063                                         g_scaling);
2064             status = vaAssociateSurfaceGLX(va_context->display,
2065                                            gl_surface,
2066                                            surface->id,
2067                                            flags);
2068             if (!check_status(status, "vaAssociateSurfaceGLX()"))
2069                 return;
2070         }
2071 #else
2072         mp_msg(MSGT_VO, MSGL_WARN, "vaAssociateSurfaceGLX() is not implemented\n");
2073         gl_binding = 0;
2074 #endif
2075     }
2076
2077     if (!gl_binding) {
2078         for (i = 0; i <= !!(g_deint > 1); i++) {
2079             const unsigned int flags = (get_field_flags(i) |
2080                                         get_colorspace_flags() |
2081                                         g_scaling);
2082             status = vaCopySurfaceGLX(va_context->display,
2083                                       gl_surface,
2084                                       surface->id,
2085                                       flags);
2086
2087             if (status == VA_STATUS_ERROR_UNIMPLEMENTED) {
2088                 mp_msg(MSGT_VO, MSGL_WARN,
2089                        "[vo_vaapi] vaCopySurfaceGLX() is not implemented\n");
2090                 gl_binding = 1;
2091             }
2092             else {
2093                 if (!check_status(status, "vaCopySurfaceGLX()"))
2094                     return;
2095             }
2096         }
2097     }
2098 #endif
2099     g_output_surfaces[g_output_surface] = surface;
2100 }
2101
2102 static int glx_bind_texture(void)
2103 {
2104     glEnable(GL_TEXTURE_2D);
2105     mpglBindTexture(GL_TEXTURE_2D, gl_texture);
2106
2107     if (gl_use_tfp) {
2108         x11_trap_errors();
2109         mpglXBindTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT, NULL);
2110         XSync(mDisplay, False);
2111         if (x11_untrap_errors())
2112             mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Update bind_tex_image failed\n");
2113     }
2114
2115 #if USE_VAAPI_GLX_BIND
2116     if (gl_binding) {
2117         VAStatus status;
2118         status = vaBeginRenderSurfaceGLX(va_context->display, gl_surface);
2119         if (!check_status(status, "vaBeginRenderSurfaceGLX()"))
2120             return -1;
2121     }
2122 #endif
2123     return 0;
2124 }
2125
2126 static int glx_unbind_texture(void)
2127 {
2128     if (gl_use_tfp) {
2129         x11_trap_errors();
2130         mpglXReleaseTexImage(mDisplay, gl_pixmap, GLX_FRONT_LEFT_EXT);
2131         if (x11_untrap_errors())
2132             mp_msg(MSGT_VO, MSGL_WARN, "[vo_vaapi] Failed to release?\n");
2133     }
2134
2135 #if USE_VAAPI_GLX_BIND
2136     if (gl_binding) {
2137         VAStatus status;
2138         status = vaEndRenderSurfaceGLX(va_context->display, gl_surface);
2139         if (!check_status(status, "vaEndRenderSurfaceGLX()"))
2140             return -1;
2141     }
2142 #endif
2143
2144     mpglBindTexture(GL_TEXTURE_2D, 0);
2145     glDisable(GL_TEXTURE_2D);
2146     return 0;
2147 }
2148
2149 static void render_background(void)
2150 {
2151     /* Original code from Mirco Muller (MacSlow):
2152        <http://cgit.freedesktop.org/~macslow/gl-gst-player/> */
2153     GLfloat fStartX = 0.0f;
2154     GLfloat fStartY = 0.0f;
2155     GLfloat fWidth  = (GLfloat)vo_dwidth;
2156     GLfloat fHeight = (GLfloat)vo_dheight;
2157
2158     glBegin(GL_QUADS);
2159     {
2160         /* top third, darker grey to white */
2161         glColor3f(0.85f, 0.85f, 0.85f);
2162         glVertex3f(fStartX, fStartY, 0.0f);
2163         glColor3f(0.85f, 0.85f, 0.85f);
2164         glVertex3f(fStartX + fWidth, fStartY, 0.0f);
2165         glColor3f(1.0f, 1.0f, 1.0f);
2166         glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
2167         glColor3f(1.0f, 1.0f, 1.0f);
2168         glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
2169
2170         /* middle third, just plain white */
2171         glColor3f(1.0f, 1.0f, 1.0f);
2172         glVertex3f(fStartX, fStartY + fHeight / 3.0f, 0.0f);
2173         glVertex3f(fStartX + fWidth, fStartY + fHeight / 3.0f, 0.0f);
2174         glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2175         glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2176
2177         /* bottom third, white to lighter grey */
2178         glColor3f(1.0f, 1.0f, 1.0f);
2179         glVertex3f(fStartX, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2180         glColor3f(1.0f, 1.0f, 1.0f);
2181         glVertex3f(fStartX + fWidth, fStartY + 2.0f * fHeight / 3.0f, 0.0f);
2182         glColor3f(0.62f, 0.66f, 0.69f);
2183         glVertex3f(fStartX + fWidth, fStartY + fHeight, 0.0f);
2184         glColor3f(0.62f, 0.66f, 0.69f);
2185         glVertex3f(fStartX, fStartY + fHeight, 0.0f);
2186     }
2187     glEnd();
2188 }
2189
2190 static void render_frame(void)
2191 {
2192     struct vo_rect * const r = &g_output_rect;
2193
2194     if (glx_bind_texture() < 0)
2195         return;
2196     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
2197     glBegin(GL_QUADS);
2198     {
2199         glTexCoord2f(0.0f, 0.0f); glVertex2i(r->left, r->top);
2200         glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->bottom);
2201         glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->bottom);
2202         glTexCoord2f(1.0f, 0.0f); glVertex2i(r->right, r->top);
2203     }
2204     glEnd();
2205     if (glx_unbind_texture() < 0)
2206         return;
2207 }
2208
2209 static void render_reflection(void)
2210 {
2211     struct vo_rect * const r = &g_output_rect;
2212     const unsigned int rh  = g_output_rect.height / 5;
2213     GLfloat ry = 1.0f - (GLfloat)rh / (GLfloat)r->height;
2214
2215     if (glx_bind_texture() < 0)
2216         return;
2217     glBegin(GL_QUADS);
2218     {
2219         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
2220         glTexCoord2f(0.0f, 1.0f); glVertex2i(r->left, r->top);
2221         glTexCoord2f(1.0f, 1.0f); glVertex2i(r->right, r->top);
2222
2223         glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
2224         glTexCoord2f(1.0f, ry); glVertex2i(r->right, r->top + rh);
2225         glTexCoord2f(0.0f, ry); glVertex2i(r->left, r->top + rh);
2226     }
2227     glEnd();
2228     if (glx_unbind_texture() < 0)
2229         return;
2230 }
2231
2232 static void flip_page_glx(void)
2233 {
2234     glClear(GL_COLOR_BUFFER_BIT);
2235
2236     if (gl_reflect) {
2237         render_background();
2238
2239         glPushMatrix();
2240         glRotatef(20.0f, 0.0f, 1.0f, 0.0f);
2241         glTranslatef(50.0f, 0.0f, 0.0f);
2242     }
2243
2244     render_frame();
2245
2246     if (gl_reflect) {
2247         glPushMatrix();
2248         glTranslatef(0.0, (GLfloat)g_output_rect.height + 5.0f, 0.0f);
2249         render_reflection();
2250         glPopMatrix();
2251         glPopMatrix();
2252     }
2253
2254     if (cpu_stats) {
2255         gl_draw_rectangle(0, 0, vo_dwidth, 32, 0x000000ff);
2256         glColor3f(1.0f, 1.0f, 1.0f);
2257         glRasterPos2i(16, 20);
2258         gl_printf("MPlayer: %.1f%% of CPU @ %u MHz", cpu_usage, cpu_frequency);
2259     }
2260
2261     if (gl_finish)
2262         mpglFinish();
2263     gl_context.swapGlBuffers(&gl_context);
2264
2265     if (vo_fs) /* avoid flickering borders in fullscreen mode */
2266         glClear(GL_COLOR_BUFFER_BIT);
2267 }
2268 #endif
2269
2270 #if CONFIG_XRENDER
2271 static void put_surface_xrender(struct vaapi_surface *surface)
2272 {
2273     VAStatus status;
2274     int i;
2275
2276     for (i = 0; i <= !!(g_deint > 1); i++) {
2277         const unsigned int flags = (get_field_flags(i) |
2278                                     get_colorspace_flags() |
2279                                     g_scaling);
2280         status = vaPutSurface(va_context->display,
2281                               surface->id,
2282                               g_image_pixmap,
2283                               0, 0, g_image_width, g_image_height,
2284                               0, 0, g_output_rect.width, g_output_rect.height,
2285                               NULL, 0,
2286                               flags);
2287         if (!check_status(status, "vaPutSurface()"))
2288             return;
2289         XRenderComposite(mDisplay,
2290                          PictOpSrc, xr_video_picture, 0, xr_window_picture,
2291                          0, 0,
2292                          0, 0,
2293                          g_output_rect.left, g_output_rect.top,
2294                          g_output_rect.width, g_output_rect.height);
2295     }
2296 }
2297 #endif
2298
2299 static void put_surface(struct vaapi_surface *surface)
2300 {
2301     if (!surface || surface->id == VA_INVALID_SURFACE)
2302         return;
2303
2304 #if CONFIG_GL
2305     if (gl_enabled)
2306         put_surface_glx(surface);
2307     else
2308 #endif
2309 #if CONFIG_XRENDER
2310     if (xr_enabled)
2311         put_surface_xrender(surface);
2312     else
2313 #endif
2314         put_surface_x11(surface);
2315 }
2316
2317 static int draw_slice(uint8_t * image[], int stride[],
2318                       int w, int h, int x, int y)
2319 {
2320     struct vaapi_surface * const surface = va_free_surfaces[g_output_surface];
2321     VAImage * const va_image = &surface->image;
2322     VAStatus status;
2323     uint8_t *image_data = NULL;
2324     uint8_t *dst[3] = { 0, };
2325     unsigned int dst_stride[3];
2326
2327     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_slice(): location (%d,%d), size %dx%d\n", x, y, w, h);
2328
2329     status = vaMapBuffer(va_context->display, va_image->buf,
2330                          (void *)&image_data);
2331     if (!check_status(status, "vaMapBuffer()"))
2332         return VO_FALSE;
2333
2334     dst_stride[0] = va_image->pitches[0];
2335     dst[0] = image_data + va_image->offsets[0] + y * dst_stride[0] + x;
2336
2337     memcpy_pic(dst[0], image[0], w, h, dst_stride[0], stride[0]);
2338
2339     x /= 2;
2340     y /= 2;
2341     w /= 2;
2342     h /= 2;
2343
2344     if (g_image_format == IMGFMT_YV12) {
2345         /* MPlayer's YV12 is actually I420, so swap U/V components */
2346         dst_stride[1] = va_image->pitches[2];
2347         dst[1] = image_data + va_image->offsets[2] + y * dst_stride[1] + x;
2348         dst_stride[2] = va_image->pitches[1];
2349         dst[2] = image_data + va_image->offsets[1] + y * dst_stride[2] + x;
2350     }
2351     else {
2352         if (image[1]) {
2353             dst_stride[1] = va_image->pitches[1];
2354             dst[1] = image_data + va_image->offsets[1] + y * dst_stride[1] + x;
2355         }
2356         if (image[2]) {
2357             dst_stride[2] = va_image->pitches[2];
2358             dst[2] = image_data + va_image->offsets[2] + y * dst_stride[2] + x;
2359         }
2360     }
2361
2362     if (image[1]) /* RGBA only has a single plane */
2363         memcpy_pic(dst[1], image[1], w, h, dst_stride[1], stride[1]);
2364
2365     if (image[2]) /* NV12 only has two planes */
2366         memcpy_pic(dst[2], image[2], w, h, dst_stride[2], stride[2]);
2367
2368     status = vaUnmapBuffer(va_context->display, surface->image.buf);
2369     if (!check_status(status, "vaUnmapBuffer()"))
2370         return VO_FALSE;
2371
2372     return VO_TRUE;
2373 }
2374
2375 static int draw_frame(uint8_t * src[])
2376 {
2377     mp_msg(MSGT_VO,MSGL_INFO, MSGTR_LIBVO_X11_DrawFrameCalled);
2378
2379     return -1;
2380 }
2381
2382 static void draw_osd(void)
2383 {
2384     VAStatus status;
2385     const int osd_width  = va_osd_image.width;
2386     const int osd_height = va_osd_image.height;
2387
2388     ensure_osd();
2389     if (va_osd_image.image_id == VA_INVALID_ID)
2390         return;
2391
2392     if (!va_osd_draw_alpha)
2393         return;
2394
2395     if (!vo_update_osd(osd_width, osd_height))
2396         return;
2397  
2398     if (!vo_osd_check_range_update(0, 0, osd_width, osd_height)) {
2399         disable_osd();
2400         return;
2401     }
2402
2403     status = vaMapBuffer(va_context->display, va_osd_image.buf,
2404                          (void *)&va_osd_image_data);
2405     if (!check_status(status, "vaMapBuffer()"))
2406         return;
2407
2408     memset(va_osd_image_data, 0, va_osd_image.data_size);
2409
2410     vo_draw_text(osd_width, osd_height, va_osd_draw_alpha);
2411
2412     status = vaUnmapBuffer(va_context->display, va_osd_image.buf);
2413     if (!check_status(status, "vaUnmapBuffer()"))
2414         return;
2415     va_osd_image_data = NULL;
2416
2417     enable_osd();
2418 }
2419
2420 static void draw_eosd(struct mp_eosd_image_list *imgs)
2421 {
2422     struct mp_eosd_image *img = eosd_image_first(imgs);
2423     struct mp_eosd_image *i;
2424     VAStatus status;
2425
2426     if (!va_eosd_draw_alpha)
2427         return;
2428
2429     // Nothing changed, no need to redraw
2430     if (imgs->changed == 0)
2431         return;
2432
2433     // There's nothing to render!
2434     if (!img) {
2435         disable_eosd();
2436         return;
2437     }
2438
2439     if (imgs->changed == 1)
2440         goto eosd_skip_upload;
2441
2442     status = vaMapBuffer(va_context->display, va_eosd_image.buf,
2443                          (void *)&va_eosd_image_data);
2444     if (!check_status(status, "vaMapBuffer()"))
2445         return;
2446
2447     memset(va_eosd_image_data, 0, va_eosd_image.data_size);
2448
2449     for (i = img; i; i = i->next)
2450         va_eosd_draw_alpha(i->bitmap, i->w, i->h, i->stride,
2451                            i->dst_x, i->dst_y, i->color);
2452
2453     status = vaUnmapBuffer(va_context->display, va_eosd_image.buf);
2454     if (!check_status(status, "vaUnmapBuffer()"))
2455         return;
2456     va_eosd_image_data = NULL;
2457
2458 eosd_skip_upload:
2459     enable_eosd();
2460 }
2461
2462 static void flip_page(void)
2463 {
2464     struct vaapi_surface *surface;
2465
2466     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] flip_page()\n");
2467
2468     surface = g_output_surfaces[g_output_surface];
2469     if (!surface)
2470         return;
2471
2472     put_surface(surface);
2473     g_output_surface = (g_output_surface + 1) % MAX_OUTPUT_SURFACES;
2474     g_is_visible     = 1;
2475
2476 #if CONFIG_GL
2477     if (gl_enabled)
2478         flip_page_glx();
2479 #endif
2480 }
2481
2482 static struct vaapi_surface *get_surface(mp_image_t *mpi)
2483 {
2484     struct vaapi_surface *surface;
2485
2486     if (mpi->type == MP_IMGTYPE_NUMBERED && is_direct_mapping()) {
2487         assert(mpi->number < va_num_surfaces);
2488         surface = va_free_surfaces[mpi->number];
2489         return surface;
2490     }
2491
2492     /* Push current surface to a free slot */
2493     if (mpi->priv) {
2494         assert(!va_free_surfaces[va_free_surfaces_tail_index]);
2495         va_free_surfaces[va_free_surfaces_tail_index] = mpi->priv;
2496         va_free_surfaces_tail_index = (va_free_surfaces_tail_index + 1) % va_num_surfaces;
2497     }
2498
2499     /* Pop the least recently used free surface */
2500     assert(va_free_surfaces[va_free_surfaces_head_index]);
2501     surface = va_free_surfaces[va_free_surfaces_head_index];
2502     va_free_surfaces[va_free_surfaces_head_index] = NULL;
2503     va_free_surfaces_head_index = (va_free_surfaces_head_index + 1) % va_num_surfaces;
2504     return surface;
2505 }
2506
2507 static uint32_t get_image(mp_image_t *mpi)
2508 {
2509     struct vaapi_surface *surface;
2510
2511     if (mpi->type != MP_IMGTYPE_NUMBERED)
2512         return VO_FALSE;
2513
2514     if (!IMGFMT_IS_VAAPI(g_image_format))
2515         return VO_FALSE;
2516
2517     surface = get_surface(mpi);
2518     if (!surface)
2519         return VO_FALSE;
2520
2521     mpi->flags |= MP_IMGFLAG_DIRECT;
2522     mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = mpi->stride[3] = 0;
2523     mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = mpi->planes[3] = NULL;
2524     mpi->planes[0] = (char *)surface;
2525     mpi->planes[3] = (char *)(uintptr_t)surface->id;
2526     mpi->num_planes = 1;
2527     mpi->priv = surface;
2528
2529     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] get_image(): surface 0x%08x\n", surface->id);
2530
2531     return VO_TRUE;
2532 }
2533
2534 static int put_image(mp_image_t *mpi, struct vaapi_surface *surface)
2535 {
2536     VAStatus status;
2537  
2538     if ((mpi->flags & (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV)) != (MP_IMGFLAG_PLANAR|MP_IMGFLAG_YUV))
2539         return VO_FALSE;
2540
2541     if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
2542         if (!draw_slice(mpi->planes, mpi->stride, mpi->w, mpi->h, 0, 0))
2543             return VO_FALSE;
2544     }
2545
2546     if (!surface->is_bound) {
2547         status = vaPutImage2(va_context->display,
2548                              surface->id,
2549                              surface->image.image_id,
2550                              mpi->x, mpi->y, mpi->w, mpi->h,
2551                              mpi->x, mpi->y, mpi->w, mpi->h);
2552         if (!check_status(status, "vaPutImage()"))
2553             return VO_FALSE;
2554     }
2555
2556     return VO_TRUE;
2557 }
2558
2559 static uint32_t draw_image(mp_image_t *mpi)
2560 {
2561     struct vaapi_surface *surface = (struct vaapi_surface *)mpi->priv;
2562
2563     g_image_fields = mpi->fields;
2564
2565     if (!IMGFMT_IS_VAAPI(mpi->imgfmt)) {
2566         /* XXX: no direct rendering in non-accelerated mode */
2567         surface = va_free_surfaces[g_output_surface];
2568         if (!put_image(mpi, surface))
2569             return VO_FALSE;
2570     }
2571
2572     mp_msg(MSGT_VO, MSGL_DBG2, "[vo_vaapi] draw_image(): surface 0x%08x\n", surface->id);
2573
2574     g_output_surfaces[g_output_surface] = surface;
2575
2576     if (cpu_stats) {
2577         static uint64_t ticks;
2578         if ((ticks++ % 30) == 0) {
2579             cpu_frequency = get_cpu_frequency();
2580             cpu_usage = get_cpu_usage(CPU_USAGE_QUANTUM);
2581         }
2582     }
2583     return VO_TRUE;
2584 }
2585
2586 static void check_events(void)
2587 {
2588     int events = vo_x11_check_events(mDisplay);
2589
2590     if (events & VO_EVENT_RESIZE)
2591         resize();
2592
2593     if ((events & (VO_EVENT_EXPOSE|VO_EVENT_RESIZE)) && g_is_paused) {
2594         /* Redraw the last visible buffer  */
2595         if (g_is_visible) {
2596             struct vaapi_surface *surface = g_output_surfaces[g_output_surface];
2597             if (surface)
2598                 put_surface(surface);
2599         }
2600     }
2601 }
2602
2603 static VADisplayAttribute *get_display_attribute(const char *name)
2604 {
2605     VADisplayAttribute *attr;
2606     if (!strcasecmp(name, "brightness"))
2607         attr = &va_equalizer.brightness;
2608     else if (!strcasecmp(name, "contrast"))
2609         attr = &va_equalizer.contrast;
2610     else if (!strcasecmp(name, "saturation"))
2611         attr = &va_equalizer.saturation;
2612     else if (!strcasecmp(name, "hue"))
2613         attr = &va_equalizer.hue;
2614     else
2615         attr = NULL;
2616     return attr;
2617 }
2618
2619 static int get_equalizer(const char *name, int *value)
2620 {
2621     VADisplayAttribute * const attr = get_display_attribute(name);
2622     int r;
2623
2624     if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_GETTABLE))
2625         return VO_NOTIMPL;
2626
2627     /* normalize to -100 .. 100 range */
2628     r = attr->max_value - attr->min_value;
2629     if (r == 0)
2630         return VO_NOTIMPL;
2631     *value = ((attr->value - attr->min_value) * 200) / r - 100;
2632     return VO_TRUE;
2633 }
2634
2635 static int set_equalizer(const char *name, int value)
2636 {
2637     VADisplayAttribute * const attr = get_display_attribute(name);
2638     VAStatus status;
2639     int r;
2640
2641     if (!attr || !(attr->flags & VA_DISPLAY_ATTRIB_SETTABLE))
2642         return VO_NOTIMPL;
2643
2644     /* normalize to attribute value range */
2645     r = attr->max_value - attr->min_value;
2646     if (r == 0)
2647         return VO_NOTIMPL;
2648     attr->value = ((value + 100) * r) / 200 + attr->min_value;
2649
2650     status = vaSetDisplayAttributes(va_context->display, attr, 1);
2651     if (!check_status(status, "vaSetDisplayAttributes()"))
2652         return VO_FALSE;
2653     return VO_TRUE;
2654 }
2655
2656 static int control(uint32_t request, void *data)
2657 {
2658     switch (request) {
2659     case VOCTRL_GET_DEINTERLACE:
2660         *(int*)data = g_deint;
2661         return VO_TRUE;
2662     case VOCTRL_SET_DEINTERLACE:
2663         g_deint = *(int*)data;
2664         if (g_deint)
2665             g_deint = g_deint_type;
2666         return VO_TRUE;
2667     case VOCTRL_PAUSE:
2668         return (g_is_paused = 1);
2669     case VOCTRL_RESUME:
2670         return (g_is_paused = 0);
2671     case VOCTRL_QUERY_FORMAT:
2672         return query_format(*((uint32_t *)data));
2673     case VOCTRL_GET_IMAGE:
2674         return get_image(data);
2675     case VOCTRL_DRAW_IMAGE:
2676         return draw_image(data);
2677     case VOCTRL_GUISUPPORT:
2678         return VO_TRUE;
2679     case VOCTRL_BORDER:
2680         vo_x11_border();
2681         resize();
2682         return VO_TRUE;
2683     case VOCTRL_FULLSCREEN:
2684         vo_x11_fullscreen();
2685         resize();
2686         return VO_TRUE;
2687     case VOCTRL_SET_EQUALIZER: {
2688         vf_equalizer_t *eq = data;
2689         if (g_image_format == IMGFMT_BGRA)
2690             return VO_NOTIMPL;
2691
2692         return set_equalizer(eq->item, eq->value);
2693     }
2694     case VOCTRL_GET_EQUALIZER: {
2695         vf_equalizer_t *eq = data;
2696         return get_equalizer(eq->item, &eq->value);
2697     }
2698     case VOCTRL_ONTOP:
2699         vo_x11_ontop();
2700         return VO_TRUE;
2701     case VOCTRL_UPDATE_SCREENINFO:
2702         update_xinerama_info();
2703         return VO_TRUE;
2704     case VOCTRL_GET_PANSCAN:
2705         return VO_TRUE;
2706     case VOCTRL_SET_PANSCAN:
2707         resize();
2708         return VO_TRUE;
2709     case VOCTRL_GET_HWACCEL_CONTEXT:
2710         *((void **)data) = va_context;
2711         return VO_TRUE;
2712     case VOCTRL_DRAW_EOSD:
2713         if (!data)
2714             return VO_FALSE;
2715         draw_eosd(data);
2716         return VO_TRUE;
2717     case VOCTRL_GET_EOSD_RES: {
2718         struct mp_eosd_settings *r = data;
2719         r->mt = r->mb = r->ml = r->mr = 0;
2720         r->srcw = g_image_width;
2721         r->srch = g_image_height;
2722         r->w    = g_image_width;
2723         r->h    = g_image_height;
2724         return VO_TRUE;
2725     }
2726     }
2727     return VO_NOTIMPL;
2728 }