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