vaapi: add H.263 Baseline and H.264 Constrained Baseline profiles.
[hwdecode-demos:jenssvenssons-hwdecode-demos.git] / src / vaapi.c
1 /*
2  *  vaapi.c - VA API common code
3  *
4  *  hwdecode-demos (C) 2009-2010 Splitted-Desktop Systems
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "sysdeps.h"
22 #include "vaapi.h"
23 #include "vaapi_compat.h"
24 #include "common.h"
25 #include "utils.h"
26 #include "x11.h"
27
28 #if USE_GLX
29 #include "glx.h"
30 #endif
31
32 #if USE_VAAPI_GLX
33 #include <va/va_glx.h>
34 #endif
35
36 #define DEBUG 1
37 #include "debug.h"
38
39
40 static VAAPIContext *vaapi_context;
41
42 static inline const char *string_of_VAImageFormat(VAImageFormat *imgfmt)
43 {
44     return string_of_FOURCC(imgfmt->fourcc);
45 }
46
47 static const char *string_of_VAProfile(VAProfile profile)
48 {
49     switch (profile) {
50 #define PROFILE(profile) \
51         case VAProfile##profile: return "VAProfile" #profile
52         PROFILE(MPEG2Simple);
53         PROFILE(MPEG2Main);
54         PROFILE(MPEG4Simple);
55         PROFILE(MPEG4AdvancedSimple);
56         PROFILE(MPEG4Main);
57 #if VA_CHECK_VERSION(0,32,0)
58         PROFILE(H263Baseline);
59         PROFILE(H264ConstrainedBaseline);
60 #endif
61         PROFILE(H264Baseline);
62         PROFILE(H264Main);
63         PROFILE(H264High);
64         PROFILE(VC1Simple);
65         PROFILE(VC1Main);
66         PROFILE(VC1Advanced);
67 #undef PROFILE
68     default: break;
69     }
70     return "<unknown>";
71 }
72
73 static const char *string_of_VAEntrypoint(VAEntrypoint entrypoint)
74 {
75     switch (entrypoint) {
76 #define ENTRYPOINT(entrypoint) \
77         case VAEntrypoint##entrypoint: return "VAEntrypoint" #entrypoint
78         ENTRYPOINT(VLD);
79         ENTRYPOINT(IZZ);
80         ENTRYPOINT(IDCT);
81         ENTRYPOINT(MoComp);
82         ENTRYPOINT(Deblocking);
83 #if VA_CHECK_VERSION(0,32,0)
84         ENTRYPOINT(EncSlice);
85         ENTRYPOINT(EncPicture);
86 #endif
87 #undef ENTRYPOINT
88     default: break;
89     }
90     return "<unknown>";
91 }
92
93 static const char *string_of_VADisplayAttribType(VADisplayAttribType type)
94 {
95     switch (type) {
96 #define TYPE(type) \
97         case VADisplayAttrib##type: return "VADisplayAttrib" #type
98         TYPE(Brightness);
99         TYPE(Contrast);
100         TYPE(Hue);
101         TYPE(Saturation);
102         TYPE(BackgroundColor);
103         TYPE(DirectSurface);
104 #undef TYPE
105     default: break;
106     }
107     return "<unknown>";
108 }
109
110 static void destroy_buffers(VADisplay display, VABufferID *buffers, unsigned int n_buffers)
111 {
112     unsigned int i;
113     for (i = 0; i < n_buffers; i++) {
114         if (buffers[i]) {
115             vaDestroyBuffer(display, buffers[i]);
116             buffers[i] = 0;
117         }
118     }
119 }
120
121 int vaapi_init(VADisplay display)
122 {
123     CommonContext * common = common_get_context();
124     VAAPIContext *vaapi;
125     int major_version, minor_version;
126     int i, num_display_attrs, max_display_attrs;
127     VADisplayAttribute *display_attrs;
128     VAStatus status;
129
130     if (vaapi_context)
131         return 0;
132
133     if (!display)
134         return -1;
135     D(bug("VA display %p\n", display));
136
137     status = vaInitialize(display, &major_version, &minor_version);
138     if (!vaapi_check_status(status, "vaInitialize()"))
139         return -1;
140     D(bug("VA API version %d.%d\n", major_version, minor_version));
141
142     max_display_attrs = vaMaxNumDisplayAttributes(display);
143     display_attrs = malloc(max_display_attrs * sizeof(display_attrs[0]));
144     if (!display_attrs)
145         return -1;
146
147     num_display_attrs = 0; /* XXX: workaround old GMA500 bug */
148     status = vaQueryDisplayAttributes(display, display_attrs, &num_display_attrs);
149     if (!vaapi_check_status(status, "vaQueryDisplayAttributes()")) {
150         free(display_attrs);
151         return -1;
152     }
153     D(bug("%d display attributes available\n", num_display_attrs));
154     for (i = 0; i < num_display_attrs; i++) {
155         VADisplayAttribute * const display_attr = &display_attrs[i];
156         D(bug("  %-32s (%s/%s) min %d max %d value 0x%x\n",
157               string_of_VADisplayAttribType(display_attr->type),
158               (display_attr->flags & VA_DISPLAY_ATTRIB_GETTABLE) ? "get" : "---",
159               (display_attr->flags & VA_DISPLAY_ATTRIB_SETTABLE) ? "set" : "---",
160               display_attr->min_value,
161               display_attr->max_value,
162               display_attr->value));
163     }
164     free(display_attrs);
165
166     if (common->use_vaapi_background_color) {
167         VADisplayAttribute attr;
168         attr.type  = VADisplayAttribBackgroundColor;
169         attr.value = common->vaapi_background_color;
170         status = vaSetDisplayAttributes(display, &attr, 1);
171         if (!vaapi_check_status(status, "vaSetDisplayAttributes()"))
172             return -1;
173     }
174
175     if ((vaapi = calloc(1, sizeof(*vaapi))) == NULL)
176         return -1;
177     vaapi->display               = display;
178     vaapi->subpic_image.image_id = VA_INVALID_ID;
179     for (i = 0; i < ARRAY_ELEMS(vaapi->subpic_ids); i++)
180         vaapi->subpic_ids[i]     = VA_INVALID_ID;
181
182     vaapi_context = vaapi;
183     return 0;
184 }
185
186 int vaapi_exit(void)
187 {
188     VAAPIContext * const vaapi = vaapi_get_context();
189     unsigned int i;
190
191     if (!vaapi)
192         return 0;
193
194 #if USE_GLX
195     if (display_type() == DISPLAY_GLX)
196         vaapi_glx_destroy_surface();
197 #endif
198
199     destroy_buffers(vaapi->display, &vaapi->pic_param_buf_id, 1);
200     destroy_buffers(vaapi->display, &vaapi->iq_matrix_buf_id, 1);
201     destroy_buffers(vaapi->display, &vaapi->bitplane_buf_id, 1);
202     destroy_buffers(vaapi->display, vaapi->slice_buf_ids, vaapi->n_slice_buf_ids);
203
204     if (vaapi->subpic_flags) {
205         free(vaapi->subpic_flags);
206         vaapi->subpic_flags = NULL;
207     }
208
209     if (vaapi->subpic_formats) {
210         free(vaapi->subpic_formats);
211         vaapi->subpic_formats = NULL;
212         vaapi->n_subpic_formats = 0;
213     }
214
215     if (vaapi->image_formats) {
216         free(vaapi->image_formats);
217         vaapi->image_formats = NULL;
218         vaapi->n_image_formats = 0;
219     }
220
221     if (vaapi->entrypoints) {
222         free(vaapi->entrypoints);
223         vaapi->entrypoints = NULL;
224         vaapi->n_entrypoints = 0;
225     }
226
227     if (vaapi->profiles) {
228         free(vaapi->profiles);
229         vaapi->profiles = NULL;
230         vaapi->n_profiles = 0;
231     }
232
233     if (vaapi->slice_params) {
234         free(vaapi->slice_params);
235         vaapi->slice_params = NULL;
236         vaapi->slice_params_alloc = 0;
237         vaapi->n_slice_params = 0;
238     }
239
240     if (vaapi->slice_buf_ids) {
241         free(vaapi->slice_buf_ids);
242         vaapi->slice_buf_ids = NULL;
243         vaapi->n_slice_buf_ids = 0;
244     }
245
246     if (vaapi->subpic_image.image_id != VA_INVALID_ID) {
247         vaDestroyImage(vaapi->display, vaapi->subpic_image.image_id);
248         vaapi->subpic_image.image_id = VA_INVALID_ID;
249     }
250
251     for (i = 0; i < ARRAY_ELEMS(vaapi->subpic_ids); i++) {
252         if (vaapi->subpic_ids[i] != VA_INVALID_ID) {
253             vaDestroySubpicture(vaapi->display, vaapi->subpic_ids[i]);
254             vaapi->subpic_ids[i] = VA_INVALID_ID;
255         }
256     }
257
258     if (vaapi->surface_id) {
259         vaDestroySurfaces(vaapi->display, &vaapi->surface_id, 1);
260         vaapi->surface_id = 0;
261     }
262
263     if (vaapi->context_id) {
264         vaDestroyContext(vaapi->display, vaapi->context_id);
265         vaapi->context_id = 0;
266     }
267
268     if (vaapi->config_id) {
269         vaDestroyConfig(vaapi->display, vaapi->config_id);
270         vaapi->config_id = 0;
271     }
272
273     if (vaapi->display) {
274         vaTerminate(vaapi->display);
275         vaapi->display = NULL;
276     }
277
278     free(vaapi_context);
279     return 0;
280 }
281
282 VAAPIContext *vaapi_get_context(void)
283 {
284     return vaapi_context;
285 }
286
287 int vaapi_check_status(VAStatus status, const char *msg)
288 {
289     if (status != VA_STATUS_SUCCESS) {
290         fprintf(stderr, "[%s] %s: %s\n", PACKAGE_NAME, msg, vaErrorStr(status));
291         return 0;
292     }
293     return 1;
294 }
295
296 static void *alloc_buffer(VAAPIContext *vaapi, int type, unsigned int size, VABufferID *buf_id)
297 {
298     VAStatus status;
299     void *data = NULL;
300
301     *buf_id = 0;
302     status = vaCreateBuffer(vaapi->display, vaapi->context_id,
303                             type, size, 1, NULL, buf_id);
304     if (!vaapi_check_status(status, "vaCreateBuffer()"))
305         return NULL;
306
307     status = vaMapBuffer(vaapi->display, *buf_id, &data);
308     if (!vaapi_check_status(status, "vaMapBuffer()"))
309         return NULL;
310
311     return data;
312 }
313
314 void *vaapi_alloc_picture(unsigned int size)
315 {
316     VAAPIContext *vaapi = vaapi_get_context();
317     if (!vaapi)
318         return NULL;
319     return alloc_buffer(vaapi, VAPictureParameterBufferType, size, &vaapi->pic_param_buf_id);
320 }
321
322 void *vaapi_alloc_iq_matrix(unsigned int size)
323 {
324     VAAPIContext *vaapi = vaapi_get_context();
325     if (!vaapi)
326         return NULL;
327     return alloc_buffer(vaapi, VAIQMatrixBufferType, size, &vaapi->iq_matrix_buf_id);
328 }
329
330 void *vaapi_alloc_bitplane(unsigned int size)
331 {
332     VAAPIContext *vaapi = vaapi_get_context();
333     if (!vaapi)
334         return NULL;
335     return alloc_buffer(vaapi, VABitPlaneBufferType, size, &vaapi->bitplane_buf_id);
336 }
337
338 static int commit_slices(VAAPIContext *vaapi)
339 {
340     VAStatus status;
341     VABufferID *slice_buf_ids;
342     VABufferID slice_param_buf_id, slice_data_buf_id;
343
344     if (vaapi->n_slice_params == 0)
345         return 0;
346
347     slice_buf_ids =
348         fast_realloc(vaapi->slice_buf_ids,
349                      &vaapi->slice_buf_ids_alloc,
350                      (vaapi->n_slice_buf_ids + 2) * sizeof(slice_buf_ids[0]));
351     if (!slice_buf_ids)
352         return -1;
353     vaapi->slice_buf_ids = slice_buf_ids;
354
355     slice_param_buf_id = 0;
356     status = vaCreateBuffer(vaapi->display, vaapi->context_id,
357                             VASliceParameterBufferType,
358                             vaapi->slice_param_size,
359                             vaapi->n_slice_params, vaapi->slice_params,
360                             &slice_param_buf_id);
361     if (!vaapi_check_status(status, "vaCreateBuffer() for slice params"))
362         return -1;
363     vaapi->n_slice_params = 0;
364
365     slice_data_buf_id = 0;
366     status = vaCreateBuffer(vaapi->display, vaapi->context_id,
367                             VASliceDataBufferType,
368                             vaapi->slice_data_size,
369                             1, (void *)vaapi->slice_data,
370                             &slice_data_buf_id);
371     if (!vaapi_check_status(status, "vaCreateBuffer() for slice data"))
372         return -1;
373     vaapi->slice_data = NULL;
374     vaapi->slice_data_size = 0;
375
376     slice_buf_ids[vaapi->n_slice_buf_ids++] = slice_param_buf_id;
377     slice_buf_ids[vaapi->n_slice_buf_ids++] = slice_data_buf_id;
378     return 0;
379 }
380
381 void *vaapi_alloc_slice(unsigned int size, const uint8_t *buf, unsigned int buf_size)
382 {
383     VAAPIContext *vaapi = vaapi_get_context();
384     uint8_t *slice_params;
385     VASliceParameterBufferBase *slice_param;
386
387     if (!vaapi)
388         return NULL;
389
390     if (vaapi->slice_param_size == 0)
391         vaapi->slice_param_size = size;
392     else if (vaapi->slice_param_size != size)
393         return NULL;
394
395     if (!vaapi->slice_data)
396         vaapi->slice_data = buf;
397     if (vaapi->slice_data + vaapi->slice_data_size != buf) {
398         if (commit_slices(vaapi) < 0)
399             return NULL;
400         vaapi->slice_data = buf;
401     }
402
403     slice_params =
404         fast_realloc(vaapi->slice_params,
405                      &vaapi->slice_params_alloc,
406                      (vaapi->n_slice_params + 1) * vaapi->slice_param_size);
407     if (!slice_params)
408         return NULL;
409     vaapi->slice_params = slice_params;
410
411     slice_param = (VASliceParameterBufferBase *)(slice_params + vaapi->n_slice_params * vaapi->slice_param_size);
412     slice_param->slice_data_size   = buf_size;
413     slice_param->slice_data_offset = vaapi->slice_data_size;
414     slice_param->slice_data_flag   = VA_SLICE_DATA_FLAG_ALL;
415
416     vaapi->n_slice_params++;
417     vaapi->slice_data_size += buf_size;
418     return slice_param;
419 }
420
421 static int has_profile(VAAPIContext *vaapi, VAProfile profile)
422 {
423     VAStatus status;
424     int i;
425
426     if (!vaapi->profiles || vaapi->n_profiles == 0) {
427         vaapi->profiles = calloc(vaMaxNumProfiles(vaapi->display), sizeof(vaapi->profiles[0]));
428
429         status = vaQueryConfigProfiles(vaapi->display,
430                                        vaapi->profiles,
431                                        &vaapi->n_profiles);
432         if (!vaapi_check_status(status, "vaQueryConfigProfiles()"))
433             return 0;
434
435         D(bug("%d profiles available\n", vaapi->n_profiles));
436         for (i = 0; i < vaapi->n_profiles; i++)
437             D(bug("  %s\n", string_of_VAProfile(vaapi->profiles[i])));
438     }
439
440     for (i = 0; i < vaapi->n_profiles; i++) {
441         if (vaapi->profiles[i] == profile)
442             return 1;
443     }
444     return 0;
445 }
446
447 static int has_entrypoint(VAAPIContext *vaapi, VAProfile profile, VAEntrypoint entrypoint)
448 {
449     VAStatus status;
450     int i;
451
452     if (!vaapi->entrypoints || vaapi->n_entrypoints == 0) {
453         vaapi->entrypoints = calloc(vaMaxNumEntrypoints(vaapi->display), sizeof(vaapi->entrypoints[0]));
454
455         status = vaQueryConfigEntrypoints(vaapi->display, profile,
456                                           vaapi->entrypoints,
457                                           &vaapi->n_entrypoints);
458         if (!vaapi_check_status(status, "vaQueryConfigEntrypoints()"))
459             return 0;
460
461         D(bug("%d entrypoints available for %s\n", vaapi->n_entrypoints,
462               string_of_VAProfile(profile)));
463         for (i = 0; i < vaapi->n_entrypoints; i++)
464             D(bug("  %s\n", string_of_VAEntrypoint(vaapi->entrypoints[i])));
465     }
466
467     for (i = 0; i < vaapi->n_entrypoints; i++) {
468         if (vaapi->entrypoints[i] == entrypoint)
469             return 1;
470     }
471     return 0;
472 }
473
474 int vaapi_init_decoder(VAProfile    profile,
475                        VAEntrypoint entrypoint,
476                        unsigned int picture_width,
477                        unsigned int picture_height)
478 {
479     VAAPIContext * const vaapi = vaapi_get_context();
480     VAConfigAttrib attrib;
481     VAConfigID config_id = 0;
482     VAContextID context_id = 0;
483     VASurfaceID surface_id = 0;
484     VAStatus status;
485
486     if (!vaapi)
487         return -1;
488
489     if (common_init_decoder(picture_width, picture_height) < 0)
490         return -1;
491
492     if (!has_profile(vaapi, profile))
493         return -1;
494     if (!has_entrypoint(vaapi, profile, entrypoint))
495         return -1;
496
497 #if USE_GLX
498     if (display_type() == DISPLAY_GLX) {
499         GLXContext * const glx = glx_get_context();
500
501         if (!glx)
502             return -1;
503
504         if (glx_init_texture(picture_width, picture_height) < 0)
505             return -1;
506
507         if (vaapi_glx_create_surface(glx->texture_target, glx->texture) < 0)
508             return -1;
509     }
510 #endif
511
512     if (vaapi->profile != profile || vaapi->entrypoint != entrypoint) {
513         if (vaapi->config_id)
514             vaDestroyConfig(vaapi->display, vaapi->config_id);
515
516         attrib.type = VAConfigAttribRTFormat;
517         status = vaGetConfigAttributes(vaapi->display, profile, entrypoint,
518                                        &attrib, 1);
519         if (!vaapi_check_status(status, "vaGetConfigAttributes()"))
520             return -1;
521         if ((attrib.value & VA_RT_FORMAT_YUV420) == 0)
522             return -1;
523
524         status = vaCreateConfig(vaapi->display, profile, entrypoint,
525                                 &attrib, 1, &config_id);
526         if (!vaapi_check_status(status, "vaCreateConfig()"))
527             return -1;
528     }
529     else
530         config_id = vaapi->config_id;
531
532     if (vaapi->picture_width != picture_width || vaapi->picture_height != picture_height) {
533         if (vaapi->surface_id)
534             vaDestroySurfaces(vaapi->display, &vaapi->surface_id, 1);
535
536         status = vaCreateSurfaces(vaapi->display, picture_width, picture_height,
537                                   VA_RT_FORMAT_YUV420, 1, &surface_id);
538         if (!vaapi_check_status(status, "vaCreateSurfaces()"))
539             return -1;
540
541         if (vaapi->context_id)
542             vaDestroyContext(vaapi->display, vaapi->context_id);
543
544         status = vaCreateContext(vaapi->display, config_id,
545                                  picture_width, picture_height,
546                                  VA_PROGRESSIVE,
547                                  &surface_id, 1,
548                                  &context_id);
549         if (!vaapi_check_status(status, "vaCreateContext()"))
550             return -1;
551     }
552     else {
553         context_id = vaapi->context_id;
554         surface_id = vaapi->surface_id;
555     }
556
557     vaapi->config_id      = config_id;
558     vaapi->context_id     = context_id;
559     vaapi->surface_id     = surface_id;
560     vaapi->profile        = profile;
561     vaapi->entrypoint     = entrypoint;
562     vaapi->picture_width  = picture_width;
563     vaapi->picture_height = picture_height;
564     return 0;
565 }
566
567 static int
568 get_image_format(
569     VAAPIContext   *vaapi,
570     uint32_t        fourcc,
571     VAImageFormat **image_format
572 )
573 {
574     VAStatus status;
575     int i;
576
577     if (image_format)
578         *image_format = NULL;
579
580     if (!vaapi->image_formats || vaapi->n_image_formats == 0) {
581         vaapi->image_formats = calloc(vaMaxNumImageFormats(vaapi->display),
582                                       sizeof(vaapi->image_formats[0]));
583         if (!vaapi->image_formats)
584             return 0;
585
586         status = vaQueryImageFormats(vaapi->display,
587                                      vaapi->image_formats,
588                                      &vaapi->n_image_formats);
589         if (!vaapi_check_status(status, "vaQueryImageFormats()"))
590             return 0;
591
592         D(bug("%d image formats\n", vaapi->n_image_formats));
593         for (i = 0; i < vaapi->n_image_formats; i++)
594             D(bug("  %s\n", string_of_VAImageFormat(&vaapi->image_formats[i])));
595     }
596
597     for (i = 0; i < vaapi->n_image_formats; i++) {
598         if (vaapi->image_formats[i].fourcc == fourcc) {
599             if (image_format)
600                 *image_format = &vaapi->image_formats[i];
601             return 1;
602         }
603     }
604     return 0;
605 }
606
607 /** Checks whether VAAPI format is RGB */
608 static int is_vaapi_rgb_format(const VAImageFormat *image_format)
609 {
610     switch (image_format->fourcc) {
611     case VA_FOURCC('A','R','G','B'):
612     case VA_FOURCC('A','B','G','R'):
613     case VA_FOURCC('B','G','R','A'):
614     case VA_FOURCC('R','G','B','A'):
615         return 1;
616     }
617     return 0;
618 }
619
620 static int bind_image(VAImage *va_image, Image *image)
621 {
622     VAAPIContext * const vaapi = vaapi_get_context();
623     VAImageFormat * const va_format = &va_image->format;
624     VAStatus status;
625     void *va_image_data;
626     unsigned int i;
627
628     if (va_image->num_planes > MAX_IMAGE_PLANES)
629         return -1;
630
631     status = vaMapBuffer(vaapi->display, va_image->buf, &va_image_data);
632     if (!vaapi_check_status(status, "vaMapBuffer()"))
633         return -1;
634
635     memset(image, 0, sizeof(*image));
636     image->format = va_format->fourcc;
637     if (is_vaapi_rgb_format(va_format)) {
638         image->format = image_rgba_format(
639             va_format->bits_per_pixel,
640             va_format->byte_order == VA_MSB_FIRST,
641             va_format->red_mask,
642             va_format->green_mask,
643             va_format->blue_mask,
644             va_format->alpha_mask
645         );
646         if (!image->format)
647             return -1;
648     }
649
650     image->width      = va_image->width;
651     image->height     = va_image->height;
652     image->num_planes = va_image->num_planes;
653     for (i = 0; i < va_image->num_planes; i++) {
654         image->pixels[i]  = (uint8_t *)va_image_data + va_image->offsets[i];
655         image->pitches[i] = va_image->pitches[i];
656     }
657     return 0;
658 }
659
660 static int release_image(VAImage *va_image)
661 {
662     VAAPIContext * const vaapi = vaapi_get_context();
663     VAStatus status;
664
665     status = vaUnmapBuffer(vaapi->display, va_image->buf);
666     if (!vaapi_check_status(status, "vaUnmapBuffer()"))
667         return -1;
668     return 0;
669 }
670
671 static const uint32_t image_formats[] = {
672     VA_FOURCC('Y','V','1','2'),
673     VA_FOURCC('N','V','1','2'),
674     VA_FOURCC('U','Y','V','Y'),
675     VA_FOURCC('Y','U','Y','V'),
676     VA_FOURCC('A','R','G','B'),
677     VA_FOURCC('A','B','G','R'),
678     VA_FOURCC('B','G','R','A'),
679     VA_FOURCC('R','G','B','A'),
680     0
681 };
682
683 /** Converts Image format to VAAPI format */
684 static uint32_t get_vaapi_format(uint32_t format)
685 {
686     uint32_t fourcc;
687
688     /* Only translate image formats we support */
689     switch (format) {
690     case IMAGE_NV12:
691     case IMAGE_YV12:
692     case IMAGE_IYUV:
693     case IMAGE_I420:
694     case IMAGE_AYUV:
695     case IMAGE_UYVY:
696     case IMAGE_YUY2:
697     case IMAGE_YUYV:
698     case IMAGE_ARGB:
699     case IMAGE_BGRA:
700     case IMAGE_RGBA:
701     case IMAGE_ABGR:
702         fourcc = format;
703         break;
704     default:
705         fourcc = 0;
706         break;
707     }
708     return fourcc;
709 }
710
711 static int get_image(VASurfaceID surface, Image *dst_img)
712 {
713     CommonContext * const common = common_get_context();
714     VAAPIContext * const vaapi = vaapi_get_context();
715     VAImage image;
716     VAImageFormat *image_format = NULL;
717     VAStatus status;
718     Image bound_image;
719     int i, is_bound_image = 0, is_derived_image = 0, error = -1;
720
721     image.image_id = VA_INVALID_ID;
722     image.buf      = VA_INVALID_ID;
723
724     if (common->getimage_format) {
725         uint32_t fourcc = get_vaapi_format(common->getimage_format);
726         if (!fourcc || !get_image_format(vaapi, fourcc, &image_format))
727             goto end;
728     }
729
730     if (!image_format) {
731         status = vaDeriveImage(vaapi->display, surface, &image);
732         if (vaapi_check_status(status, "vaDeriveImage()")) {
733             if (image.image_id != VA_INVALID_ID && image.buf != VA_INVALID_ID) {
734                 D(bug("using vaDeriveImage()\n"));
735                 is_derived_image = 1;
736                 image_format = &image.format;
737             }
738             else {
739                 D(bug("vaDeriveImage() returned success but VA image is invalid. Trying vaGetImage()\n"));
740             }
741         }
742     }
743
744     if (!image_format) {
745         for (i = 0; image_formats[i] != 0; i++) {
746             if (get_image_format(vaapi, image_formats[i], &image_format))
747                 break;
748         }
749     }
750
751     if (!image_format)
752         goto end;
753     D(bug("selected %s image format for getimage\n",
754           string_of_VAImageFormat(image_format)));
755
756     if (!is_derived_image) {
757         status = vaCreateImage(vaapi->display, image_format,
758                                vaapi->picture_width, vaapi->picture_height,
759                                &image);
760         if (!vaapi_check_status(status, "vaCreateImage()"))
761             goto end;
762         D(bug("created image with id 0x%08x and buffer id 0x%08x\n",
763               image.image_id, image.buf));
764
765         VARectangle src_rect;
766         if (common->use_getimage_rect) {
767             Rectangle * const img_rect = &common->getimage_rect;
768             if (img_rect->x < 0 || img_rect->y >= vaapi->picture_width)
769                 goto end;
770             if (img_rect->y < 0 || img_rect->y >= vaapi->picture_height)
771                 goto end;
772             if (img_rect->x + img_rect->width > vaapi->picture_width)
773                 goto end;
774             if (img_rect->y + img_rect->height > vaapi->picture_height)
775                 goto end;
776             src_rect.x      = img_rect->x;
777             src_rect.y      = img_rect->y;
778             src_rect.width  = img_rect->width;
779             src_rect.height = img_rect->height;
780         }
781         else {
782             src_rect.x      = 0;
783             src_rect.y      = 0;
784             src_rect.width  = vaapi->picture_width;
785             src_rect.height = vaapi->picture_height;
786         }
787         D(bug("src rect (%d,%d):%ux%u\n",
788               src_rect.x, src_rect.y, src_rect.width, src_rect.height));
789
790         status = vaGetImage(
791             vaapi->display, vaapi->surface_id,
792             src_rect.x, src_rect.y, src_rect.width, src_rect.height,
793             image.image_id
794         );
795         if (!vaapi_check_status(status, "vaGetImage()")) {
796             vaDestroyImage(vaapi->display, image.image_id);
797             goto end;
798         }
799     }
800
801     if (bind_image(&image, &bound_image) < 0)
802         goto end;
803     is_bound_image = 1;
804
805     if (image_convert(dst_img, &bound_image) < 0)
806         goto end;
807
808     error = 0;
809 end:
810     if (is_bound_image) {
811         if (release_image(&image) < 0)
812             error = -1;
813     }
814
815     if (image.image_id != VA_INVALID_ID) {
816         status = vaDestroyImage(vaapi->display, image.image_id);
817         if (!vaapi_check_status(status, "vaDestroyImage()"))
818             error = -1;
819     }
820     return error;
821 }
822
823 static inline int vaapi_decode_to_image(void)
824 {
825     CommonContext * const common = common_get_context();
826     VAAPIContext * const vaapi = vaapi_get_context();
827
828     return get_image(vaapi->surface_id, common->image);
829 }
830
831 static int put_image(VASurfaceID surface, Image *img)
832 {
833     CommonContext * const common = common_get_context();
834     VAAPIContext * const vaapi = vaapi_get_context();
835     VAImageFormat *va_image_format = NULL;
836     VAImage va_image;
837     VAStatus status;
838     Image bound_image;
839     int i, w, h, is_bound_image = 0, error = -1;
840
841     va_image.image_id = VA_INVALID_ID;
842     va_image.buf      = VA_INVALID_ID;
843
844     if (common->putimage_format) {
845         uint32_t fourcc = get_vaapi_format(common->putimage_format);
846         if (!fourcc || !get_image_format(vaapi, fourcc, &va_image_format))
847             goto end;
848     }
849
850     if (!va_image_format) {
851         for (i = 0; image_formats[i] != 0; i++) {
852             if (get_image_format(vaapi, image_formats[i], &va_image_format))
853                 break;
854         }
855     }
856
857     if (!va_image_format)
858         goto end;
859     D(bug("selected %s image format for putimage in override mode\n",
860           string_of_VAImageFormat(va_image_format)));
861
862     if (common->vaapi_putimage_scaled) {
863         /* Let vaPutImage() scale the image, though only a very few
864            drivers support that */
865         w = img->width;
866         h = img->height;
867     }
868     else {
869         w = vaapi->picture_width;
870         h = vaapi->picture_height;
871     }
872
873     status = vaCreateImage(vaapi->display, va_image_format, w, h, &va_image);
874     if (!vaapi_check_status(status, "vaCreateImage()"))
875         goto end;
876     D(bug("created image with id 0x%08x and buffer id 0x%08x\n",
877           va_image.image_id, va_image.buf));
878
879     if (bind_image(&va_image, &bound_image) < 0)
880         goto end;
881     is_bound_image = 1;
882     if (image_convert(&bound_image, img) < 0)
883         goto end;
884     is_bound_image = 0;
885     if (release_image(&va_image) < 0)
886         goto end;
887
888     status = vaPutImage2(vaapi->display, surface, va_image.image_id,
889                          0, 0, va_image.width, va_image.height,
890                          0, 0, vaapi->picture_width, vaapi->picture_height);
891     if (!vaapi_check_status(status, "vaPutImage()"))
892         goto end;
893     error = 0;
894 end:
895     if (is_bound_image) {
896         if (release_image(&va_image) < 0)
897             error = -1;
898     }
899
900     if (va_image.image_id != VA_INVALID_ID) {
901         status = vaDestroyImage(vaapi->display, va_image.image_id);
902         if (!vaapi_check_status(status, "vaDestroyImage()"))
903             error = -1;
904     }
905     return error;
906 }
907
908 static const uint32_t subpic_formats[] = {
909     VA_FOURCC('A','R','G','B'),
910     VA_FOURCC('A','B','G','R'),
911     VA_FOURCC('B','G','R','A'),
912     VA_FOURCC('R','G','B','A'),
913     0
914 };
915
916 static int
917 get_subpic_format(
918     VAAPIContext   *vaapi,
919     uint32_t        fourcc,
920     VAImageFormat **format,
921     unsigned int   *flags
922 )
923 {
924     VAStatus status;
925     unsigned int i;
926
927     if (format)
928         *format = NULL;
929
930     if (flags)
931         *flags = 0;
932
933     if (!vaapi->subpic_formats) {
934         vaapi->n_subpic_formats = vaMaxNumSubpictureFormats(vaapi->display);
935
936         vaapi->subpic_formats = calloc(vaapi->n_subpic_formats,
937                                        sizeof(vaapi->subpic_formats[0]));
938         if (!vaapi->subpic_formats)
939             return 0;
940
941         vaapi->subpic_flags = calloc(vaapi->n_subpic_formats,
942                                      sizeof(vaapi->subpic_flags[0]));
943         if (!vaapi->subpic_flags)
944             return 0;
945
946         status = vaQuerySubpictureFormats(vaapi->display,
947                                           vaapi->subpic_formats,
948                                           vaapi->subpic_flags,
949                                           &vaapi->n_subpic_formats);
950         if (!vaapi_check_status(status, "vaQuerySubpictureFormats()"))
951             return 0;
952
953         D(bug("%d subpicture formats\n", vaapi->n_subpic_formats));
954         for (i = 0; i < vaapi->n_subpic_formats; i++) {
955             VAImageFormat *const image_format = &vaapi->subpic_formats[i];
956             D(bug("  %s, flags 0x%x\n",
957                   string_of_VAImageFormat(image_format),
958                   vaapi->subpic_flags[i]));
959             if (is_vaapi_rgb_format(image_format))
960                 D(bug("    byte-order %s, %d-bit, depth %d, r/g/b/a 0x%08x/0x%08x/0x%08x/0x%08x\n",
961                       image_format->byte_order == VA_MSB_FIRST ? "MSB" : "LSB",
962                       image_format->bits_per_pixel,
963                       image_format->depth,
964                       image_format->red_mask,
965                       image_format->green_mask,
966                       image_format->blue_mask,
967                       image_format->alpha_mask));
968         }
969     }
970
971     for (i = 0; i < vaapi->n_subpic_formats; i++) {
972         if (vaapi->subpic_formats[i].fourcc == fourcc) {
973             if (format)
974                 *format = &vaapi->subpic_formats[i];
975             if (flags)
976                 *flags = vaapi->subpic_flags[i];
977             return 1;
978         }
979     }
980     return 0;
981 }
982
983 static int blend_image(VASurfaceID surface, Image *img)
984 {
985     CommonContext * const common = common_get_context();
986     VAAPIContext * const vaapi = vaapi_get_context();
987     unsigned int subpic_count, subpic_count_x, subpic_count_y, i, j;
988     unsigned int subpic_flags = 0;
989     VAImageFormat *subpic_format = NULL;
990     VAStatus status;
991     Image bound_image;
992     int is_bound_image = 0, error = -1;
993     Rectangle src_rect, dst_rect, srect, drect;
994
995     vaapi->subpic_image.image_id = VA_INVALID_ID;
996     vaapi->subpic_image.buf      = VA_INVALID_ID;
997
998     if (common->putimage_format) {
999         uint32_t fourcc = get_vaapi_format(common->putimage_format);
1000         if (!fourcc || !get_subpic_format(vaapi, fourcc, &subpic_format, &subpic_flags))
1001             goto end;
1002     }
1003
1004     if (!subpic_format) {
1005         for (i = 0; subpic_formats[i] != 0; i++) {
1006             if (get_subpic_format(vaapi, subpic_formats[i], &subpic_format, &subpic_flags))
1007                 break;
1008         }
1009     }
1010     if (!subpic_format)
1011         goto end;
1012
1013     if (common->use_vaapi_subpicture_flags &&
1014         ((common->vaapi_subpicture_flags ^ subpic_flags) & VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD) != 0) {
1015         D(bug("driver does not support VA_SUBPICTURE_DESTINATION_IS_SCREEN_COORD flag\n"));
1016         goto end;
1017     }
1018
1019     D(bug("selected %s subpicture format for putimage in blend mode\n",
1020           string_of_VAImageFormat(subpic_format)));
1021
1022     status = vaCreateImage(vaapi->display, subpic_format,
1023                            img->width, img->height, &vaapi->subpic_image);
1024     if (!vaapi_check_status(status, "vaCreateImage()"))
1025         goto end;
1026     D(bug("created image with id 0x%08x and buffer id 0x%08x\n",
1027           vaapi->subpic_image.image_id, vaapi->subpic_image.buf));
1028
1029     if (bind_image(&vaapi->subpic_image, &bound_image) < 0)
1030         goto end;
1031     is_bound_image = 1;
1032     if (image_convert(&bound_image, img) < 0)
1033         goto end;
1034     is_bound_image = 0;
1035     if (release_image(&vaapi->subpic_image) < 0)
1036         goto end;
1037
1038     subpic_count = 1;
1039     if (common->vaapi_multi_subpictures)
1040         subpic_count = ARRAY_ELEMS(vaapi->subpic_ids);
1041
1042     for (i = 0; i < subpic_count; i++) {
1043         status = vaCreateSubpicture(
1044             vaapi->display,
1045             vaapi->subpic_image.image_id,
1046             &vaapi->subpic_ids[i]
1047         );
1048         if (!vaapi_check_status(status, "vaCreateSubpicture()"))
1049             goto end;
1050         D(bug("created subpicture with id 0x%08x\n", vaapi->subpic_ids[i]));
1051     }
1052
1053     if (common->use_vaapi_subpicture_source_rect)
1054         src_rect = common->vaapi_subpicture_source_rect;
1055     else {
1056         src_rect.x      = 0;
1057         src_rect.y      = 0;
1058         src_rect.width  = img->width;
1059         src_rect.height = img->height;
1060     }
1061
1062     if (common->use_vaapi_subpicture_target_rect)
1063         dst_rect = common->vaapi_subpicture_target_rect;
1064     else {
1065         dst_rect.x      = 0;
1066         dst_rect.y      = 0;
1067         dst_rect.width  = vaapi->picture_width;
1068         dst_rect.height = vaapi->picture_height;
1069     }
1070
1071     D(bug("render %d subpicture%s from (%d,%d):%ux%u to (%d,%d):%ux%u\n",
1072           subpic_count, subpic_count > 1 ? "s" : "",
1073           src_rect.x, src_rect.y, src_rect.width, src_rect.height,
1074           dst_rect.x, dst_rect.y, dst_rect.width, dst_rect.height));
1075
1076     subpic_count_y = subpic_count / 2;
1077     if (subpic_count_y == 0)
1078         subpic_count_y = 1;
1079
1080     subpic_flags = 0;
1081     if (common->use_vaapi_subpicture_flags)
1082         subpic_flags = common->vaapi_subpicture_flags;
1083
1084     for (j = 0; j < subpic_count_y; j++) {
1085         subpic_count_x = subpic_count / subpic_count_y;
1086         if (j == subpic_count_y - 1)
1087             subpic_count_x += subpic_count % subpic_count_y; /* 0/1 */
1088
1089         for (i = 0; i < subpic_count_x; i++) {
1090             srect.x      = src_rect.x + (i * src_rect.width) / subpic_count_x;
1091             srect.y      = src_rect.y + (j * src_rect.height) / subpic_count_y;
1092             srect.width  = src_rect.width / subpic_count_x;
1093             srect.height = src_rect.height / subpic_count_y;
1094             drect.x      = dst_rect.x + (i * dst_rect.width) / subpic_count_x;
1095             drect.y      = dst_rect.y + (j * dst_rect.height) / subpic_count_y;
1096             drect.width  = dst_rect.width / subpic_count_x;
1097             drect.height = dst_rect.height / subpic_count_y;
1098
1099             if (i == subpic_count_x - 1) {
1100                 srect.width  = (src_rect.x + src_rect.width) - srect.x;
1101                 drect.width  = (dst_rect.x + dst_rect.width) - drect.x;
1102             }
1103
1104             if (j == subpic_count_y - 1) {
1105                 srect.height = (src_rect.y + src_rect.height) - srect.y;
1106                 drect.height = (dst_rect.y + dst_rect.height) - drect.y;
1107             }
1108
1109             if (subpic_count > 1)
1110                 D(bug("  id 0x%08x: src (%d,%d):%ux%u, dst (%d,%d):%ux%u\n",
1111                       vaapi->subpic_ids[j * subpic_count_y + i],
1112                       srect.x, srect.y, srect.width, srect.height,
1113                       drect.x, drect.y, drect.width, drect.height));
1114
1115             status = vaAssociateSubpicture2(
1116                 vaapi->display,
1117                 vaapi->subpic_ids[j * subpic_count_y + i],
1118                 &surface, 1,
1119                 srect.x, srect.y, srect.width, srect.height,
1120                 drect.x, drect.y, drect.width, drect.height,
1121                 subpic_flags
1122             );
1123             if (!vaapi_check_status(status, "vaAssociateSubpicture()"))
1124                 goto end;
1125         }
1126     }
1127     error = 0;
1128 end:
1129     if (is_bound_image) {
1130         if (release_image(&vaapi->subpic_image) < 0)
1131             error = -1;
1132     }
1133     return error;
1134 }
1135
1136 int vaapi_decode(void)
1137 {
1138     VAAPIContext * const vaapi = vaapi_get_context();
1139     VABufferID va_buffers[3];
1140     unsigned int n_va_buffers = 0;
1141     VAStatus status;
1142
1143     if (!vaapi || vaapi->context_id == 0 || vaapi->surface_id == 0)
1144         return -1;
1145
1146     if (commit_slices(vaapi) < 0)
1147         return -1;
1148
1149     vaUnmapBuffer(vaapi->display, vaapi->pic_param_buf_id);
1150     va_buffers[n_va_buffers++] = vaapi->pic_param_buf_id;
1151
1152     if (vaapi->iq_matrix_buf_id) {
1153         vaUnmapBuffer(vaapi->display, vaapi->iq_matrix_buf_id);
1154         va_buffers[n_va_buffers++] = vaapi->iq_matrix_buf_id;
1155     }
1156
1157     if (vaapi->bitplane_buf_id) {
1158         vaUnmapBuffer(vaapi->display, vaapi->bitplane_buf_id);
1159         va_buffers[n_va_buffers++] = vaapi->bitplane_buf_id;
1160     }
1161
1162     status = vaBeginPicture(vaapi->display, vaapi->context_id,
1163                             vaapi->surface_id);
1164     if (!vaapi_check_status(status, "vaBeginPicture()"))
1165         return -1;
1166
1167     status = vaRenderPicture(vaapi->display, vaapi->context_id,
1168                              va_buffers, n_va_buffers);
1169     if (!vaapi_check_status(status, "vaRenderPicture()"))
1170         return -1;
1171
1172     status = vaRenderPicture(vaapi->display, vaapi->context_id,
1173                              vaapi->slice_buf_ids,
1174                              vaapi->n_slice_buf_ids);
1175     if (!vaapi_check_status(status, "vaRenderPicture()"))
1176         return -1;
1177
1178     status = vaEndPicture(vaapi->display, vaapi->context_id);
1179     if (!vaapi_check_status(status, "vaEndPicture()"))
1180         return -1;
1181
1182     if (getimage_mode() == GETIMAGE_FROM_VIDEO)
1183         return vaapi_decode_to_image();
1184
1185     return 0;
1186 }
1187
1188 static int vaapi_display_cliprects(void)
1189 {
1190     CommonContext * const common = common_get_context();
1191     X11Context * const x11 = x11_get_context();
1192     VAAPIContext * const vaapi = vaapi_get_context();
1193     VASurfaceID clip_surface_id = VA_INVALID_ID;
1194     VARectangle *cliprects = NULL;
1195     VAStatus status;
1196     int i, error = 1;
1197
1198     if (!common->use_clipping)
1199         return 0;
1200
1201     status = vaCreateSurfaces(vaapi->display,
1202                               vaapi->picture_width,
1203                               vaapi->picture_height,
1204                               VA_RT_FORMAT_YUV420, 1, &clip_surface_id);
1205     if (!vaapi_check_status(status, "vaCreateSurfaces()"))
1206         goto end;
1207
1208     if (put_image(clip_surface_id, common->cliprects_image) < 0)
1209         goto end;
1210
1211     cliprects = malloc(common->cliprects_count * sizeof(cliprects[0]));
1212     if (!cliprects)
1213         goto end;
1214     for (i = 0; i < common->cliprects_count; i++) {
1215         cliprects[i].x      = common->cliprects[i].x;
1216         cliprects[i].y      = common->cliprects[i].y;
1217         cliprects[i].width  = common->cliprects[i].width;
1218         cliprects[i].height = common->cliprects[i].height;
1219     }
1220
1221     status = vaPutSurface(vaapi->display, clip_surface_id, x11->window,
1222                           0, 0, vaapi->picture_width, vaapi->picture_height,
1223                           0, 0, x11->window_width, x11->window_height,
1224                           cliprects, common->cliprects_count,
1225                           VA_FRAME_PICTURE);
1226     if (!vaapi_check_status(status, "vaPutSurface()"))
1227         goto end;
1228
1229     error = 0;
1230 end:
1231     if (cliprects)
1232         free(cliprects);
1233     if (clip_surface_id != VA_INVALID_ID)
1234         vaDestroySurfaces(vaapi->display, &clip_surface_id, 1);
1235     if (error)
1236         return -1;
1237     return 0;
1238 }
1239
1240 int vaapi_display(void)
1241 {
1242     CommonContext * const common = common_get_context();
1243     X11Context * const x11 = x11_get_context();
1244     VAAPIContext * const vaapi = vaapi_get_context();
1245     unsigned int vaPutSurface_count = 0;
1246     unsigned int flags = VA_FRAME_PICTURE;
1247     VAStatus status;
1248     Drawable drawable;
1249
1250     if (!common || !x11 || !vaapi)
1251         return -1;
1252
1253     if (putimage_mode() != PUTIMAGE_NONE) {
1254         Image *img;
1255         img = image_generate(
1256             common->putimage_size.width,
1257             common->putimage_size.height
1258         );
1259         if (img) {
1260             switch (putimage_mode()) {
1261             case PUTIMAGE_OVERRIDE:
1262                 if (put_image(vaapi->surface_id, img) < 0)
1263                     return -1;
1264                 break;
1265             case PUTIMAGE_BLEND:
1266                 if (blend_image(vaapi->surface_id, img) < 0)
1267                     return -1;
1268                 break;
1269             default:
1270                 break;
1271             }
1272             image_destroy(img);
1273         }
1274     }
1275
1276     /* XXX: video and output surfaces are the same for VA API */
1277     if (getimage_mode() == GETIMAGE_FROM_OUTPUT) {
1278         if (vaapi_decode_to_image() < 0)
1279             return -1;
1280         return 0;
1281     }
1282
1283     if (getimage_mode() == GETIMAGE_FROM_VIDEO)
1284         return 0;
1285
1286     if (getimage_mode() == GETIMAGE_FROM_PIXMAP)
1287         drawable = x11->pixmap;
1288     else
1289         drawable = x11->window;
1290
1291     if (common->use_vaapi_putsurface_flags)
1292         flags = common->vaapi_putsurface_flags;
1293
1294 #if USE_VAAPI_GLX
1295     if (display_type() == DISPLAY_GLX) {
1296         vaapi->use_glx_copy = common->vaapi_glx_use_copy;
1297         if (vaapi->use_glx_copy) {
1298             status = vaCopySurfaceGLX(vaapi->display,
1299                                       vaapi->glx_surface,
1300                                       vaapi->surface_id,
1301                                       flags);
1302
1303             if (status == VA_STATUS_ERROR_UNIMPLEMENTED) {
1304                 printf("VAAPI: vaCopySurfaceGLX() is not implemented\n");
1305                 vaapi->use_glx_copy = 0;
1306             }
1307             else {
1308                 printf("VAAPI: use vaCopySurfaceGLX()\n");
1309                 if (!vaapi_check_status(status, "vaCopySurfaceGLX()"))
1310                     return -1;
1311             }
1312         }
1313     }
1314     else
1315 #endif
1316     {
1317         Rectangle src_rect, dst_rect;
1318
1319         if (common->use_vaapi_putsurface_source_rect)
1320             src_rect = common->vaapi_putsurface_source_rect;
1321         else {
1322             src_rect.x      = 0;
1323             src_rect.y      = 0;
1324             src_rect.width  = vaapi->picture_width;
1325             src_rect.height = vaapi->picture_height;
1326         }
1327
1328         if (common->use_vaapi_putsurface_target_rect)
1329             dst_rect = common->vaapi_putsurface_target_rect;
1330         else {
1331             dst_rect.x      = 0;
1332             dst_rect.y      = 0;
1333             dst_rect.width  = x11->window_width;
1334             dst_rect.height = x11->window_height;
1335         }
1336
1337         if (common->use_vaapi_background_color)
1338             flags |= VA_CLEAR_DRAWABLE;
1339
1340         status = vaPutSurface(vaapi->display, vaapi->surface_id, drawable,
1341                               src_rect.x, src_rect.y,
1342                               src_rect.width, src_rect.height,
1343                               dst_rect.x, dst_rect.y,
1344                               dst_rect.width, dst_rect.height,
1345                               NULL, 0, flags);
1346         if (!vaapi_check_status(status, "vaPutSurface()"))
1347             return -1;
1348         ++vaPutSurface_count;
1349
1350         /* Clear the drawable only the first time */
1351         if (common->use_vaapi_background_color && !common->use_vaapi_putsurface_flags)
1352             flags &= ~VA_CLEAR_DRAWABLE;
1353
1354         if (common->multi_rendering) {
1355             status = vaPutSurface(vaapi->display, vaapi->surface_id, drawable,
1356                                   0, 0,
1357                                   vaapi->picture_width, vaapi->picture_height,
1358                                   x11->window_width/2, 0,
1359                                   x11->window_width/2, x11->window_height/2,
1360                                   NULL, 0, flags);
1361             if (!vaapi_check_status(status, "vaPutSurface() for multirendering"))
1362                 return -1;
1363             ++vaPutSurface_count;
1364
1365             status = vaPutSurface(vaapi->display, vaapi->surface_id, drawable,
1366                                   0, 0,
1367                                   vaapi->picture_width, vaapi->picture_height,
1368                                   0, x11->window_height/2,
1369                                   x11->window_width/2, x11->window_height/2,
1370                                   NULL, 0, flags);
1371             if (!vaapi_check_status(status, "vaPutSurface() for multirendering"))
1372                 return -1;
1373             ++vaPutSurface_count;
1374         }
1375     }
1376
1377     if (vaapi_display_cliprects() < 0)
1378         return -1;
1379
1380     if (common->use_subwindow_rect) {
1381         status = vaPutSurface(vaapi->display, vaapi->surface_id,
1382                               x11->subwindow,
1383                               0, 0, vaapi->picture_width, vaapi->picture_height,
1384                               0, 0,
1385                               common->subwindow_rect.width,
1386                               common->subwindow_rect.height,
1387                               NULL, 0, 0);
1388         if (!vaapi_check_status(status, "vaPutSurface()"))
1389             return -1;
1390         ++vaPutSurface_count;
1391     }
1392
1393     if (vaPutSurface_count > 1) {
1394         /* We don't have to call vaSyncSurface() explicitly. However,
1395            if we use multiple vaPutSurface() and subwindows, we probably
1396            want the surfaces to be presented at the same time */
1397         status = vaSyncSurface(vaapi->display, vaapi->context_id,
1398                                vaapi->surface_id);
1399         if (!vaapi_check_status(status, "vaSyncSurface() for display"))
1400             return -1;
1401     }
1402     return 0;
1403 }
1404
1405 #ifndef USE_FFMPEG
1406 int pre(void)
1407 {
1408     X11Context *x11;
1409     VADisplay dpy;
1410
1411     if (hwaccel_type() != HWACCEL_VAAPI)
1412         return -1;
1413
1414     if (x11_init() < 0)
1415         return -1;
1416     if ((x11 = x11_get_context()) == NULL)
1417         return -1;
1418 #if USE_GLX
1419     if (display_type() == DISPLAY_GLX) {
1420         if (glx_init() < 0)
1421             return -1;
1422     }
1423 #endif
1424 #if USE_VAAPI_GLX
1425     if (display_type() == DISPLAY_GLX)
1426         dpy = vaGetDisplayGLX(x11->display);
1427     else
1428 #endif
1429         dpy = vaGetDisplay(x11->display);
1430     return vaapi_init(dpy);
1431 }
1432
1433 int post(void)
1434 {
1435     if (vaapi_exit() < 0)
1436         return -1;
1437 #if USE_GLX
1438     if (display_type() == DISPLAY_GLX) {
1439         if (glx_exit() < 0)
1440             return -1;
1441     }
1442 #endif
1443     return x11_init();
1444 }
1445
1446 int display(void)
1447 {
1448     if (vaapi_display() < 0)
1449         return -1;
1450 #if USE_GLX
1451     if (display_type() == DISPLAY_GLX)
1452         return glx_display();
1453 #endif
1454     return x11_display();
1455 }
1456 #endif
1457
1458 int vaapi_glx_create_surface(unsigned int target, unsigned int texture)
1459 {
1460 #if USE_VAAPI_GLX
1461     VAAPIContext * const vaapi = vaapi_get_context();
1462     VAStatus status;
1463
1464     status = vaCreateSurfaceGLX(vaapi->display, target, texture,
1465                                 &vaapi->glx_surface);
1466     if (vaapi_check_status(status, "vaCreateSurfaceGLX()"))
1467         return 0;
1468 #endif
1469     return -1;
1470 }
1471
1472 void vaapi_glx_destroy_surface(void)
1473 {
1474 #if USE_VAAPI_GLX
1475     VAAPIContext * const vaapi = vaapi_get_context();
1476     VAStatus status;
1477
1478     status = vaDestroySurfaceGLX(vaapi->display, vaapi->glx_surface);
1479     if (vaapi_check_status(status, "vaDestroySurfaceGLX()"))
1480         return;
1481 #endif
1482 }
1483
1484 int vaapi_glx_begin_render_surface(void)
1485 {
1486 #if USE_VAAPI_GLX
1487     VAAPIContext * const vaapi = vaapi_get_context();
1488
1489     if (vaapi->use_glx_copy)
1490         return 0;
1491
1492     printf("VAAPI: use vaBeginRenderSurfaceGLX()\n");
1493
1494 #if HAS_VAAPI_GLX_BIND
1495     VAStatus status = vaAssociateSurfaceGLX(vaapi->display,
1496                                             vaapi->glx_surface,
1497                                             vaapi->surface_id,
1498                                             VA_FRAME_PICTURE);
1499     if (!vaapi_check_status(status, "vaAssociateSurfaceGLX()"))
1500         return -1;
1501
1502     status = vaBeginRenderSurfaceGLX(vaapi->display, vaapi->glx_surface);
1503     if (!vaapi_check_status(status, "vaBeginRenderSurfaceGLX()"))
1504         return -1;
1505     return 0;
1506 #endif
1507     fprintf(stderr, "ERROR: not implemented\n");
1508 #endif
1509     return -1;
1510 }
1511
1512 int vaapi_glx_end_render_surface(void)
1513 {
1514 #if USE_VAAPI_GLX
1515     VAAPIContext * const vaapi = vaapi_get_context();
1516
1517     if (vaapi->use_glx_copy)
1518         return 0;
1519
1520 #if HAS_VAAPI_GLX_BIND
1521     VAStatus status = vaEndRenderSurfaceGLX(vaapi->display, vaapi->glx_surface);
1522     if (!vaapi_check_status(status, "vaEndRenderSurfaceGLX()"))
1523         return -1;
1524
1525     status = vaDeassociateSurfaceGLX(vaapi->display, vaapi->glx_surface);
1526     if (!vaapi_check_status(status, "vaDeassociateSurfaceGLX()"))
1527         return -1;
1528     return 0;
1529 #endif
1530     fprintf(stderr, "ERROR: not implemented\n");
1531 #endif
1532     return -1;
1533 }