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