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