878761af83f2d3c2934dd0aad4fc523261d5b384
[platform/upstream/gstreamer.git] / subprojects / gstreamer-vaapi / gst-libs / gst / vaapi / gstvaapidisplay.c
1 /*
2  *  gstvaapidisplay.c - VA display abstraction
3  *
4  *  Copyright (C) 2010-2011 Splitted-Desktop Systems
5  *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
6  *  Copyright (C) 2011-2013 Intel Corporation
7  *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public License
11  *  as published by the Free Software Foundation; either version 2.1
12  *  of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free
21  *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  *  Boston, MA 02110-1301 USA
23  */
24
25 /**
26  * SECTION:gstvaapidisplay
27  * @short_description: VA display abstraction
28  */
29
30 #include "sysdeps.h"
31 #include "gstvaapiutils.h"
32 #include "gstvaapivalue.h"
33 #include "gstvaapidisplay.h"
34 #include "gstvaapitexturemap.h"
35 #include "gstvaapidisplay_priv.h"
36 #include "gstvaapiworkarounds.h"
37
38 /* Debug category for all vaapi libs */
39 GST_DEBUG_CATEGORY (gst_debug_vaapi);
40
41 /* Debug category for VaapiDisplay */
42 GST_DEBUG_CATEGORY (gst_debug_vaapi_display);
43 #define GST_CAT_DEFAULT gst_debug_vaapi_display
44
45 #define _do_init                                        \
46     G_ADD_PRIVATE (GstVaapiDisplay);                    \
47     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_display,   \
48         "vaapidisplay", 0, "VA-API Display");           \
49     GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi, "vaapi", 0, "VA-API helper");
50
51 G_DEFINE_TYPE_WITH_CODE (GstVaapiDisplay, gst_vaapi_display, GST_TYPE_OBJECT,
52     _do_init);
53
54 typedef struct _GstVaapiProfileConfig GstVaapiProfileConfig;
55 struct _GstVaapiProfileConfig
56 {
57   GstVaapiProfile profile;
58   guint32 entrypoints;          /* bits map of GstVaapiEntrypoint */
59 };
60
61 typedef struct _GstVaapiProperty GstVaapiProperty;
62 struct _GstVaapiProperty
63 {
64   const gchar *name;
65   VADisplayAttribute attribute;
66   gint old_value;
67 };
68
69 typedef struct _GstVaapiFormatInfo GstVaapiFormatInfo;
70 struct _GstVaapiFormatInfo
71 {
72   GstVideoFormat format;
73   guint flags;
74 };
75
76 #define DEFAULT_RENDER_MODE     GST_VAAPI_RENDER_MODE_TEXTURE
77 #define DEFAULT_ROTATION        GST_VAAPI_ROTATION_0
78
79 #define ENTRY_POINT_FLAG(entry) (1U << G_PASTE(GST_VAAPI_ENTRYPOINT_, entry))
80
81 enum
82 {
83   PROP_RENDER_MODE = 1,
84   PROP_ROTATION,
85   PROP_HUE,
86   PROP_SATURATION,
87   PROP_BRIGHTNESS,
88   PROP_CONTRAST,
89   PROP_VA_DISPLAY,
90
91   N_PROPERTIES
92 };
93
94 static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
95
96 static gboolean
97 get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
98     gint * value);
99
100 static gboolean
101 set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value);
102
103 static gboolean
104 get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v);
105
106 static gboolean
107 set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v);
108
109 /* GstVaapiDisplayType enumerations */
110 GType
111 gst_vaapi_display_type_get_type (void)
112 {
113   static GType g_type = 0;
114
115   static const GEnumValue display_types[] = {
116     {GST_VAAPI_DISPLAY_TYPE_ANY,
117         "Auto detection", "any"},
118 #if USE_X11
119     {GST_VAAPI_DISPLAY_TYPE_X11,
120         "VA/X11 display", "x11"},
121 #endif
122 #if USE_GLX
123     {GST_VAAPI_DISPLAY_TYPE_GLX,
124         "VA/GLX display", "glx"},
125 #endif
126 #if USE_EGL
127     {GST_VAAPI_DISPLAY_TYPE_EGL,
128         "VA/EGL display", "egl"},
129 #endif
130 #if USE_WAYLAND
131     {GST_VAAPI_DISPLAY_TYPE_WAYLAND,
132         "VA/Wayland display", "wayland"},
133 #endif
134 #if USE_DRM
135     {GST_VAAPI_DISPLAY_TYPE_DRM,
136         "VA/DRM display", "drm"},
137 #endif
138     {0, NULL, NULL},
139   };
140
141   if (!g_type)
142     g_type = g_enum_register_static ("GstVaapiDisplayType", display_types);
143   return g_type;
144 }
145
146 /**
147  * gst_vaapi_display_type_is_compatible:
148  * @type1: the #GstVaapiDisplayType to test
149  * @type2: the reference #GstVaapiDisplayType
150  *
151  * Compares whether #GstVaapiDisplay @type1 is compatible with @type2.
152  * That is, if @type2 is in "any" category, or derived from @type1.
153  *
154  * Returns: %TRUE if @type1 is compatible with @type2, %FALSE otherwise.
155  */
156 gboolean
157 gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1,
158     GstVaapiDisplayType type2)
159 {
160   if (type1 == type2)
161     return TRUE;
162
163   switch (type1) {
164     case GST_VAAPI_DISPLAY_TYPE_GLX:
165       if (type2 == GST_VAAPI_DISPLAY_TYPE_X11)
166         return TRUE;
167       break;
168     default:
169       break;
170   }
171   return type2 == GST_VAAPI_DISPLAY_TYPE_ANY;
172 }
173
174 /* Append GstVideoFormat to formats array */
175 static inline void
176 append_format (GArray * formats, GstVideoFormat format, guint flags)
177 {
178   GstVaapiFormatInfo fi;
179
180   fi.format = format;
181   fi.flags = flags;
182   g_array_append_val (formats, fi);
183 }
184
185 /* Append VAImageFormats to formats array */
186 static void
187 append_formats (GArray * formats, const VAImageFormat * va_formats,
188     guint * flags, guint n)
189 {
190   GstVideoFormat format;
191   int YV12_idx = -1;
192   int I420_idx = -1;
193   const GstVaapiFormatInfo *fip;
194   guint i;
195
196   for (i = 0; i < n; i++) {
197     const VAImageFormat *const va_format = &va_formats[i];
198
199     format = gst_vaapi_video_format_from_va_format (va_format);
200     if (format == GST_VIDEO_FORMAT_UNKNOWN) {
201       GST_DEBUG ("unsupported format %" GST_FOURCC_FORMAT,
202           GST_FOURCC_ARGS (va_format->fourcc));
203       continue;
204     }
205     append_format (formats, format, flags ? flags[i] : 0);
206
207     switch (format) {
208       case GST_VIDEO_FORMAT_YV12:
209         YV12_idx = formats->len - 1;
210         break;
211       case GST_VIDEO_FORMAT_I420:
212         I420_idx = formats->len - 1;
213         break;
214       default:
215         break;
216     }
217   }
218
219   /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
220      supported by the underlying driver */
221   if ((YV12_idx != -1) && (I420_idx == -1)) {
222     fip = &g_array_index (formats, GstVaapiFormatInfo, YV12_idx);
223     append_format (formats, GST_VIDEO_FORMAT_I420, fip->flags);
224   } else if ((I420_idx != -1) && (YV12_idx == -1)) {
225     fip = &g_array_index (formats, GstVaapiFormatInfo, I420_idx);
226     append_format (formats, GST_VIDEO_FORMAT_YV12, fip->flags);
227   }
228 }
229
230 /* Sort image formats. Prefer YUV formats first */
231 static gint
232 compare_yuv_formats (gconstpointer a, gconstpointer b)
233 {
234   const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
235   const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
236
237   const gboolean is_fmt1_yuv = gst_vaapi_video_format_is_yuv (fmt1);
238   const gboolean is_fmt2_yuv = gst_vaapi_video_format_is_yuv (fmt2);
239
240   if (is_fmt1_yuv != is_fmt2_yuv)
241     return is_fmt1_yuv ? -1 : 1;
242
243   return ((gint) gst_vaapi_video_format_get_score (fmt1) -
244       (gint) gst_vaapi_video_format_get_score (fmt2));
245 }
246
247 /* Sort subpicture formats. Prefer RGB formats first */
248 static gint
249 compare_rgb_formats (gconstpointer a, gconstpointer b)
250 {
251   const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
252   const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
253
254   const gboolean is_fmt1_rgb = gst_vaapi_video_format_is_rgb (fmt1);
255   const gboolean is_fmt2_rgb = gst_vaapi_video_format_is_rgb (fmt2);
256
257   if (is_fmt1_rgb != is_fmt2_rgb)
258     return is_fmt1_rgb ? -1 : 1;
259
260   return ((gint) gst_vaapi_video_format_get_score (fmt1) -
261       (gint) gst_vaapi_video_format_get_score (fmt2));
262 }
263
264 /* Check if configs array contains profile at entrypoint */
265 static inline gboolean
266 find_config (GPtrArray * configs, GstVaapiProfile profile,
267     GstVaapiEntrypoint entrypoint)
268 {
269   GstVaapiProfileConfig *config;
270   guint i;
271
272   if (!configs)
273     return FALSE;
274
275   for (i = 0; i < configs->len; i++) {
276     config = g_ptr_array_index (configs, i);
277     if (config->profile == profile
278         && (config->entrypoints & (1U << entrypoint)))
279       return TRUE;
280   }
281   return FALSE;
282 }
283
284 /* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
285 static void
286 append_h263_config (GArray * configs, GPtrArray * decoders)
287 {
288   GstVaapiProfileConfig *config, tmp_config;
289   GstVaapiProfileConfig *mpeg4_simple_config = NULL;
290   GstVaapiProfileConfig *h263_baseline_config = NULL;
291   guint i;
292
293   if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
294     return;
295
296   if (!decoders)
297     return;
298
299   for (i = 0; i < decoders->len; i++) {
300     config = g_ptr_array_index (decoders, i);
301     if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
302       mpeg4_simple_config = config;
303     else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
304       h263_baseline_config = config;
305   }
306
307   if (mpeg4_simple_config && !h263_baseline_config) {
308     tmp_config = *mpeg4_simple_config;
309     tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
310     tmp_config.entrypoints = ENTRY_POINT_FLAG (VLD);
311     g_array_append_val (configs, tmp_config);
312     g_ptr_array_add (decoders, &g_array_index (configs,
313             GstVaapiProfileConfig, configs->len - 1));
314   }
315 }
316
317 /* Sort profiles. Group per codec */
318 static gint
319 compare_profiles (gconstpointer a, gconstpointer b)
320 {
321   const GstVaapiProfileConfig *const config1 = (GstVaapiProfileConfig *) a;
322   const GstVaapiProfileConfig *const config2 = (GstVaapiProfileConfig *) b;
323
324   g_assert (config1->profile != config2->profile);
325   return config1->profile - config2->profile;
326 }
327
328 /* Convert configs array to profiles as GstCaps */
329 static GArray *
330 get_profiles (GPtrArray * configs, GstVaapiCodec codec)
331 {
332   GstVaapiProfileConfig *config;
333   GArray *out_profiles;
334   guint i;
335
336   if (!configs)
337     return NULL;
338
339   out_profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
340   if (!out_profiles)
341     return NULL;
342
343   for (i = 0; i < configs->len; i++) {
344     config = g_ptr_array_index (configs, i);
345     if (!codec || (codec == gst_vaapi_profile_get_codec (config->profile)))
346       g_array_append_val (out_profiles, config->profile);
347   }
348   return out_profiles;
349 }
350
351 /* Find format info */
352 static const GstVaapiFormatInfo *
353 find_format_info (GArray * formats, GstVideoFormat format)
354 {
355   const GstVaapiFormatInfo *fip;
356   guint i;
357
358   for (i = 0; i < formats->len; i++) {
359     fip = &g_array_index (formats, GstVaapiFormatInfo, i);
360     if (fip->format == format)
361       return fip;
362   }
363   return NULL;
364 }
365
366 /* Check if formats array contains format */
367 static inline gboolean
368 find_format (GArray * formats, GstVideoFormat format)
369 {
370   return find_format_info (formats, format) != NULL;
371 }
372
373 /* Convert formats array to GstCaps */
374 static GArray *
375 get_formats (GArray * formats)
376 {
377   const GstVaapiFormatInfo *fip;
378   GArray *out_formats;
379   guint i;
380
381   out_formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
382   if (!out_formats)
383     return NULL;
384
385   for (i = 0; i < formats->len; i++) {
386     fip = &g_array_index (formats, GstVaapiFormatInfo, i);
387     g_array_append_val (out_formats, fip->format);
388   }
389   return out_formats;
390 }
391
392 /* Find display attribute */
393 static const GstVaapiProperty *
394 find_property (GArray * properties, const gchar * name)
395 {
396   GstVaapiProperty *prop;
397   guint i;
398
399   if (!name)
400     return NULL;
401
402   for (i = 0; i < properties->len; i++) {
403     prop = &g_array_index (properties, GstVaapiProperty, i);
404     if (strcmp (prop->name, name) == 0)
405       return prop;
406   }
407   return NULL;
408 }
409
410 #if 0
411 static const GstVaapiProperty *
412 find_property_by_type (GArray * properties, VADisplayAttribType type)
413 {
414   GstVaapiProperty *prop;
415   guint i;
416
417   for (i = 0; i < properties->len; i++) {
418     prop = &g_array_index (properties, GstVaapiProperty, i);
419     if (prop->attribute.type == type)
420       return prop;
421   }
422   return NULL;
423 }
424 #endif
425
426 static inline const GstVaapiProperty *
427 find_property_by_pspec (GstVaapiDisplay * display, GParamSpec * pspec)
428 {
429   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
430
431   return find_property (priv->properties, pspec->name);
432 }
433
434 static guint
435 find_property_id (const gchar * name)
436 {
437   typedef struct
438   {
439     const gchar *name;
440     guint id;
441   } property_map;
442
443   static const property_map g_property_map[] = {
444     {GST_VAAPI_DISPLAY_PROP_RENDER_MODE, PROP_RENDER_MODE},
445     {GST_VAAPI_DISPLAY_PROP_ROTATION, PROP_ROTATION},
446     {GST_VAAPI_DISPLAY_PROP_HUE, PROP_HUE},
447     {GST_VAAPI_DISPLAY_PROP_SATURATION, PROP_SATURATION},
448     {GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, PROP_BRIGHTNESS},
449     {GST_VAAPI_DISPLAY_PROP_CONTRAST, PROP_CONTRAST},
450     {NULL,}
451   };
452
453   const property_map *m;
454   for (m = g_property_map; m->name != NULL; m++) {
455     if (strcmp (m->name, name) == 0)
456       return m->id;
457   }
458   return 0;
459 }
460
461 /* Initialize VA profiles (decoders, encoders) */
462 static gboolean
463 ensure_profiles (GstVaapiDisplay * display)
464 {
465   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
466   VAProfile *profiles = NULL;
467   VAEntrypoint *entrypoints = NULL;
468   gint i, j, n, num_entrypoints;
469   VAStatus status;
470   gboolean success = FALSE;
471
472   GST_VAAPI_DISPLAY_LOCK (display);
473
474   if (priv->has_profiles) {
475     GST_VAAPI_DISPLAY_UNLOCK (display);
476     return TRUE;
477   }
478
479   priv->codecs = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfileConfig));
480   if (!priv->codecs)
481     goto cleanup;
482
483   priv->decoders = g_ptr_array_new ();
484   if (!priv->decoders)
485     goto cleanup;
486   priv->encoders = g_ptr_array_new ();
487   if (!priv->encoders)
488     goto cleanup;
489   priv->has_profiles = TRUE;
490
491   /* VA profiles */
492   profiles = g_new (VAProfile, vaMaxNumProfiles (priv->display));
493   if (!profiles)
494     goto cleanup;
495   entrypoints = g_new (VAEntrypoint, vaMaxNumEntrypoints (priv->display));
496   if (!entrypoints)
497     goto cleanup;
498
499   n = 0;
500   status = vaQueryConfigProfiles (priv->display, profiles, &n);
501   if (!vaapi_check_status (status, "vaQueryConfigProfiles()"))
502     goto cleanup;
503
504   GST_DEBUG ("%d profiles", n);
505   for (i = 0; i < n; i++) {
506     if (profiles[i] == VAProfileNone)
507       continue;
508     GST_DEBUG ("  %s", string_of_VAProfile (profiles[i]));
509   }
510
511   for (i = 0; i < n; i++) {
512     GstVaapiProfileConfig config = { 0, };
513
514     config.profile = gst_vaapi_profile (profiles[i]);
515     if (!config.profile)
516       continue;
517
518     status = vaQueryConfigEntrypoints (priv->display,
519         profiles[i], entrypoints, &num_entrypoints);
520     if (!vaapi_check_status (status, "vaQueryConfigEntrypoints()"))
521       continue;
522
523     for (j = 0; j < num_entrypoints; j++)
524       config.entrypoints |= (1U << gst_vaapi_entrypoint (entrypoints[j]));
525
526     priv->codecs = g_array_append_val (priv->codecs, config);
527   }
528
529   for (i = 0; i < priv->codecs->len; i++) {
530     GstVaapiProfileConfig *cfg;
531
532     cfg = &g_array_index (priv->codecs, GstVaapiProfileConfig, i);
533
534     if ((cfg->entrypoints & ENTRY_POINT_FLAG (VLD))
535         || (cfg->entrypoints & ENTRY_POINT_FLAG (IDCT))
536         || (cfg->entrypoints & ENTRY_POINT_FLAG (MOCO)))
537       g_ptr_array_add (priv->decoders, cfg);
538     if ((cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE))
539         || (cfg->entrypoints & ENTRY_POINT_FLAG (PICTURE_ENCODE))
540         || (cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE_LP)))
541       g_ptr_array_add (priv->encoders, cfg);
542   }
543
544   append_h263_config (priv->codecs, priv->decoders);
545
546   g_ptr_array_sort (priv->decoders, compare_profiles);
547   g_ptr_array_sort (priv->encoders, compare_profiles);
548
549   /* Video processing API */
550   status = vaQueryConfigEntrypoints (priv->display, VAProfileNone,
551       entrypoints, &num_entrypoints);
552   if (vaapi_check_status (status, "vaQueryEntrypoints() [VAProfileNone]")) {
553     for (j = 0; j < num_entrypoints; j++) {
554       if (entrypoints[j] == VAEntrypointVideoProc)
555         priv->has_vpp = TRUE;
556     }
557   }
558   success = TRUE;
559
560 cleanup:
561   g_free (profiles);
562   g_free (entrypoints);
563   GST_VAAPI_DISPLAY_UNLOCK (display);
564   return success;
565 }
566
567 /* Initialize VA display attributes */
568 static gboolean
569 ensure_properties (GstVaapiDisplay * display)
570 {
571   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
572   VADisplayAttribute *display_attrs = NULL;
573   VAStatus status;
574   gint i, n;
575   gboolean success = FALSE;
576
577   if (priv->properties)
578     return TRUE;
579
580   priv->properties = g_array_new (FALSE, FALSE, sizeof (GstVaapiProperty));
581   if (!priv->properties)
582     goto cleanup;
583
584   /* VA display attributes */
585   display_attrs =
586       g_new (VADisplayAttribute, vaMaxNumDisplayAttributes (priv->display));
587   if (!display_attrs)
588     goto cleanup;
589
590   n = 0;
591   status = vaQueryDisplayAttributes (priv->display, display_attrs, &n);
592   if (!vaapi_check_status (status, "vaQueryDisplayAttributes()"))
593     goto cleanup;
594
595   GST_DEBUG ("%d display attributes", n);
596   for (i = 0; i < n; i++) {
597     VADisplayAttribute *const attr = &display_attrs[i];
598     GstVaapiProperty prop;
599     gint value;
600
601     GST_DEBUG ("  %s", string_of_VADisplayAttributeType (attr->type));
602
603     switch (attr->type) {
604       case VADisplayAttribRenderMode:
605         prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
606         break;
607       case VADisplayAttribRotation:
608         prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION;
609         break;
610       case VADisplayAttribHue:
611         prop.name = GST_VAAPI_DISPLAY_PROP_HUE;
612         break;
613       case VADisplayAttribSaturation:
614         prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION;
615         break;
616       case VADisplayAttribBrightness:
617         prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS;
618         break;
619       case VADisplayAttribContrast:
620         prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST;
621         break;
622       default:
623         prop.name = NULL;
624         break;
625     }
626     if (!prop.name)
627       continue;
628
629     /* Assume the attribute is really supported if we can get the
630      * actual and current value */
631     if (!get_attribute (display, attr->type, &value))
632       continue;
633
634     /* Some drivers (e.g. EMGD) have completely random initial
635      * values */
636     if (value < attr->min_value || value > attr->max_value)
637       continue;
638
639     prop.attribute = *attr;
640     prop.old_value = value;
641     g_array_append_val (priv->properties, prop);
642   }
643   success = TRUE;
644
645 cleanup:
646   g_free (display_attrs);
647   return success;
648 }
649
650 /* Initialize VA image formats */
651 static gboolean
652 ensure_image_formats (GstVaapiDisplay * display)
653 {
654   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
655   VAImageFormat *formats = NULL;
656   VAStatus status;
657   gint i, n, max_images;
658   gboolean success = FALSE;
659
660   GST_VAAPI_DISPLAY_LOCK (display);
661   if (priv->image_formats) {
662     GST_VAAPI_DISPLAY_UNLOCK (display);
663     return TRUE;
664   }
665
666   priv->image_formats = g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
667   if (!priv->image_formats)
668     goto cleanup;
669
670   /* VA image formats */
671   max_images = vaMaxNumImageFormats (priv->display);
672   formats = g_new (VAImageFormat, max_images);
673   if (!formats)
674     goto cleanup;
675
676   n = 0;
677   status = vaQueryImageFormats (priv->display, formats, &n);
678   if (!vaapi_check_status (status, "vaQueryImageFormats()"))
679     goto cleanup;
680
681   /* XXX(victor): Force RGBA in i965 display formats.
682    *
683    * This is required for GLTextureUploadMeta since it only negotiates
684    * RGBA, nevertheless i965 driver only reports RGBx breaking back
685    * compatibility.
686    *
687    * Side effects are not expected since it worked before commit
688    * 32bf6f1e */
689   if (gst_vaapi_display_has_driver_quirks (display,
690           GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT)) {
691     formats = g_renew (VAImageFormat, formats, max_images + 1);
692
693     formats[n].fourcc = VA_FOURCC_RGBA;
694     formats[n].byte_order = VA_LSB_FIRST;
695     formats[n].bits_per_pixel = 32;
696     formats[n].depth = 32;
697     formats[n].red_mask = 0x000000ff;
698     formats[n].green_mask = 0x0000ff00;
699     formats[n].blue_mask = 0x00ff0000;
700     formats[n].alpha_mask = 0xff000000;
701     n++;
702   }
703
704   GST_DEBUG ("%d image formats", n);
705   for (i = 0; i < n; i++)
706     GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
707
708   if (!gst_vaapi_video_format_create_map (formats, n)) {
709     GST_ERROR ("fail to create map between gst video format and vaImageFormat");
710     goto cleanup;
711   }
712
713   append_formats (priv->image_formats, formats, NULL, n);
714   g_array_sort (priv->image_formats, compare_yuv_formats);
715   success = TRUE;
716
717 cleanup:
718   g_free (formats);
719   GST_VAAPI_DISPLAY_UNLOCK (display);
720   return success;
721 }
722
723 /* Initialize VA subpicture formats */
724 static gboolean
725 ensure_subpicture_formats (GstVaapiDisplay * display)
726 {
727   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
728   VAImageFormat *formats = NULL;
729   unsigned int *flags = NULL;
730   VAStatus status;
731   guint i, n;
732   gboolean success = FALSE;
733
734   GST_VAAPI_DISPLAY_LOCK (display);
735   if (priv->subpicture_formats) {
736     GST_VAAPI_DISPLAY_UNLOCK (display);
737     return TRUE;
738   }
739
740   priv->subpicture_formats =
741       g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
742   if (!priv->subpicture_formats)
743     goto cleanup;
744
745   /* VA subpicture formats */
746   n = vaMaxNumSubpictureFormats (priv->display);
747   formats = g_new (VAImageFormat, n);
748   if (!formats)
749     goto cleanup;
750   flags = g_new (guint, n);
751   if (!flags)
752     goto cleanup;
753
754   n = 0;
755   status = vaQuerySubpictureFormats (priv->display, formats, flags, &n);
756   if (!vaapi_check_status (status, "vaQuerySubpictureFormats()"))
757     goto cleanup;
758
759   GST_DEBUG ("%d subpicture formats", n);
760   for (i = 0; i < n; i++) {
761     GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
762     flags[i] = to_GstVaapiSubpictureFlags (flags[i]);
763   }
764
765   append_formats (priv->subpicture_formats, formats, flags, n);
766   g_array_sort (priv->subpicture_formats, compare_rgb_formats);
767   success = TRUE;
768
769 cleanup:
770   g_free (formats);
771   g_free (flags);
772   GST_VAAPI_DISPLAY_UNLOCK (display);
773   return success;
774 }
775
776 /* Ensures the VA driver vendor string was copied */
777 static gboolean
778 ensure_vendor_string (GstVaapiDisplay * display)
779 {
780   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
781   const gchar *vendor_string;
782
783   GST_VAAPI_DISPLAY_LOCK (display);
784   if (!priv->vendor_string) {
785     vendor_string = vaQueryVendorString (priv->display);
786     if (vendor_string)
787       priv->vendor_string = g_strdup (vendor_string);
788     GST_INFO_OBJECT (display, "vendor: %s", priv->vendor_string);
789   }
790   GST_VAAPI_DISPLAY_UNLOCK (display);
791   return priv->vendor_string != NULL;
792 }
793
794 static void
795 set_driver_quirks (GstVaapiDisplay * display)
796 {
797   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
798   guint i;
799
800   /* *INDENT-OFF* */
801   static const struct
802   {
803     const char *match_string;
804     guint quirks;
805   } vaapi_driver_quirks_table[] = {
806     /* @XXX(victor): is this string enough to identify it */
807     { "AMD", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE },
808     { "i965", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD },
809     { "i965", GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT },
810     { "iHD", GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50 },
811     { "iHD", GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE },
812     { "i965", GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS },
813   };
814   /* *INDENT-ON* */
815
816   if (!ensure_vendor_string (display))
817     return;
818
819   for (i = 0; i < G_N_ELEMENTS (vaapi_driver_quirks_table); i++) {
820     const char *match_str = vaapi_driver_quirks_table[i].match_string;
821     if (g_strstr_len (priv->vendor_string, strlen (priv->vendor_string),
822             match_str) != NULL) {
823       priv->driver_quirks |= vaapi_driver_quirks_table[i].quirks;
824     }
825   }
826
827   GST_INFO_OBJECT (display, "Matched driver string \"%s\", setting quirks "
828       "(%#x)", priv->vendor_string, priv->driver_quirks);
829 }
830
831 static void
832 gst_vaapi_display_calculate_pixel_aspect_ratio (GstVaapiDisplay * display)
833 {
834   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
835   gdouble ratio, delta;
836   gint i, j, index, windex;
837
838   static const gint par[][2] = {
839     {1, 1},                     /* regular screen            */
840     {16, 15},                   /* PAL TV                    */
841     {11, 10},                   /* 525 line Rec.601 video    */
842     {54, 59},                   /* 625 line Rec.601 video    */
843     {64, 45},                   /* 1280x1024 on 16:9 display */
844     {5, 3},                     /* 1280x1024 on  4:3 display */
845     {4, 3}                      /*  800x600  on 16:9 display */
846   };
847
848   /* First, calculate the "real" ratio based on the X values;
849    * which is the "physical" w/h divided by the w/h in pixels of the
850    * display */
851   if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
852     ratio = 1.0;
853   else
854     ratio = (gdouble) (priv->width_mm * priv->height) /
855         (priv->height_mm * priv->width);
856   GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
857
858   /* Now, find the one from par[][2] with the lowest delta to the real one */
859 #define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)])))
860   delta = DELTA (0, 0);
861   index = 0;
862   windex = 0;
863
864   for (i = 1; i < G_N_ELEMENTS (par); i++) {
865     for (j = 0; j < 2; j++) {
866       const gdouble this_delta = DELTA (i, j);
867       if (this_delta < delta) {
868         index = i;
869         windex = j;
870         delta = this_delta;
871       }
872     }
873   }
874 #undef DELTA
875
876   priv->par_n = par[index][windex];
877   priv->par_d = par[index][windex ^ 1];
878 }
879
880 static void
881 gst_vaapi_display_ensure_screen_resolution (GstVaapiDisplay * display)
882 {
883   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
884   const GstVaapiDisplayClass *const klass =
885       GST_VAAPI_DISPLAY_GET_CLASS (display);
886
887   if (priv->got_scrres)
888     return;
889
890   if (klass->get_size)
891     klass->get_size (display, &priv->width, &priv->height);
892   if (klass->get_size_mm)
893     klass->get_size_mm (display, &priv->width_mm, &priv->height_mm);
894
895   gst_vaapi_display_calculate_pixel_aspect_ratio (display);
896   priv->got_scrres = TRUE;
897 }
898
899 static void
900 gst_vaapi_display_destroy (GstVaapiDisplay * display)
901 {
902   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
903   GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
904
905   g_clear_pointer (&priv->decoders, g_ptr_array_unref);
906   g_clear_pointer (&priv->encoders, g_ptr_array_unref);
907   g_clear_pointer (&priv->codecs, g_array_unref);
908   g_clear_pointer (&priv->image_formats, g_array_unref);
909   g_clear_pointer (&priv->subpicture_formats, g_array_unref);
910   g_clear_pointer (&priv->properties, g_array_unref);
911
912   if (priv->display) {
913     if (!priv->parent)
914       vaTerminate (priv->display);
915     priv->display = NULL;
916   }
917
918   if (klass->close_display)
919     klass->close_display (display);
920
921   g_clear_pointer (&priv->display_name, g_free);
922   g_clear_pointer (&priv->vendor_string, g_free);
923
924   gst_vaapi_display_replace (&priv->parent, NULL);
925 }
926
927 static gboolean
928 gst_vaapi_display_create (GstVaapiDisplay * display,
929     GstVaapiDisplayInitType init_type, gpointer data)
930 {
931   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
932   const GstVaapiDisplayClass *const klass =
933       GST_VAAPI_DISPLAY_GET_CLASS (display);
934   GstVaapiDisplayInfo info = {
935     .display = display,
936   };
937
938   switch (init_type) {
939     case GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY:{
940       GstVaapiDisplayInfo *p_info = data;
941
942       info.va_display = p_info->va_display;
943       priv->display = p_info->va_display;
944       priv->use_foreign_display = TRUE;
945
946       if (!klass->bind_display)
947         break;
948
949       data = p_info->native_display;
950       goto bind_display;
951     }
952     case GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME:
953       if (klass->open_display && !klass->open_display (display, data))
954         return FALSE;
955       goto create_display;
956     case GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY:
957     bind_display:
958       if (klass->bind_display && !klass->bind_display (display, data))
959         return FALSE;
960       // fall-through
961     create_display:
962       if (!klass->get_display || !klass->get_display (display, &info))
963         return FALSE;
964       priv->display = info.va_display;
965       priv->native_display = info.native_display;
966       break;
967   }
968   if (!priv->display)
969     return FALSE;
970
971   if (!priv->parent) {
972     if (!vaapi_initialize (priv->display))
973       return FALSE;
974   }
975
976   GST_INFO_OBJECT (display, "new display addr=%p", display);
977   g_free (priv->display_name);
978   priv->display_name = g_strdup (info.display_name);
979
980   set_driver_quirks (display);
981
982   if (!ensure_image_formats (display)) {
983     gst_vaapi_display_destroy (display);
984     return FALSE;
985   }
986
987   return TRUE;
988 }
989
990 static void
991 gst_vaapi_display_lock_default (GstVaapiDisplay * display)
992 {
993   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
994
995   if (priv->parent)
996     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
997   g_rec_mutex_lock (&priv->mutex);
998 }
999
1000 static void
1001 gst_vaapi_display_unlock_default (GstVaapiDisplay * display)
1002 {
1003   GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1004
1005   if (priv->parent)
1006     priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
1007   g_rec_mutex_unlock (&priv->mutex);
1008 }
1009
1010 static void
1011 gst_vaapi_display_init (GstVaapiDisplay * display)
1012 {
1013   GstVaapiDisplayPrivate *const priv =
1014       gst_vaapi_display_get_instance_private (display);
1015
1016   display->priv = priv;
1017   priv->par_n = 1;
1018   priv->par_d = 1;
1019
1020   g_rec_mutex_init (&priv->mutex);
1021 }
1022
1023 static gboolean
1024 _set_property (GstVaapiDisplay * display, const GstVaapiProperty * prop,
1025     const GValue * value)
1026 {
1027   switch (prop->attribute.type) {
1028     case VADisplayAttribRenderMode:{
1029       GstVaapiRenderMode mode;
1030       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_RENDER_MODE))
1031         return FALSE;
1032       mode = g_value_get_enum (value);
1033       return gst_vaapi_display_set_render_mode (display, mode);
1034     }
1035     case VADisplayAttribRotation:{
1036       GstVaapiRotation rotation;
1037       if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_ROTATION))
1038         return FALSE;
1039       rotation = g_value_get_enum (value);
1040       return gst_vaapi_display_set_rotation (display, rotation);
1041     }
1042     case VADisplayAttribHue:
1043     case VADisplayAttribSaturation:
1044     case VADisplayAttribBrightness:
1045     case VADisplayAttribContrast:{
1046       gfloat v;
1047       if (!G_VALUE_HOLDS (value, G_TYPE_FLOAT))
1048         return FALSE;
1049       v = g_value_get_float (value);
1050       return set_color_balance (display, find_property_id (prop->name), v);
1051     }
1052     default:
1053       break;
1054   }
1055
1056   GST_WARNING ("unsupported property '%s'", prop->name);
1057   return FALSE;
1058 }
1059
1060 static void
1061 gst_vaapi_display_set_property (GObject * object, guint property_id,
1062     const GValue * value, GParamSpec * pspec)
1063 {
1064   GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object);
1065   const GstVaapiProperty *prop;
1066
1067   if (!ensure_properties (display))
1068     return;
1069
1070   prop = find_property_by_pspec (display, pspec);
1071   if (!prop) {
1072     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1073     return;
1074   }
1075
1076   _set_property (display, prop, value);
1077 }
1078
1079 static gboolean
1080 _get_property (GstVaapiDisplay * display, const GstVaapiProperty * prop,
1081     GValue * value)
1082 {
1083   switch (prop->attribute.type) {
1084     case VADisplayAttribRenderMode:{
1085       GstVaapiRenderMode mode;
1086       if (!gst_vaapi_display_get_render_mode (display, &mode))
1087         return FALSE;
1088       if (!G_IS_VALUE (value))
1089         g_value_init (value, GST_VAAPI_TYPE_RENDER_MODE);
1090       g_value_set_enum (value, mode);
1091       break;
1092     }
1093     case VADisplayAttribRotation:{
1094       GstVaapiRotation rotation;
1095       rotation = gst_vaapi_display_get_rotation (display);
1096       if (!G_IS_VALUE (value))
1097         g_value_init (value, GST_VAAPI_TYPE_ROTATION);
1098       g_value_set_enum (value, rotation);
1099       break;
1100     }
1101     case VADisplayAttribHue:
1102     case VADisplayAttribSaturation:
1103     case VADisplayAttribBrightness:
1104     case VADisplayAttribContrast:{
1105       gfloat val;
1106       if (!get_color_balance (display, find_property_id (prop->name), &val))
1107         return FALSE;
1108       if (!G_IS_VALUE (value))
1109         g_value_init (value, G_TYPE_FLOAT);
1110       g_value_set_float (value, val);
1111       break;
1112     }
1113     default:
1114       GST_WARNING ("unsupported property '%s'", prop->name);
1115       return FALSE;
1116   }
1117   return TRUE;
1118 }
1119
1120 static void
1121 gst_vaapi_display_get_property (GObject * object, guint property_id,
1122     GValue * value, GParamSpec * pspec)
1123 {
1124   GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object);
1125   const GstVaapiProperty *prop;
1126
1127   if (property_id == PROP_VA_DISPLAY) {
1128     g_value_set_pointer (value, gst_vaapi_display_get_display (display));
1129     return;
1130   }
1131
1132   if (!ensure_properties (display))
1133     return;
1134
1135   prop = find_property_by_pspec (display, pspec);
1136   if (!prop) {
1137     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1138     return;
1139   }
1140
1141   _get_property (display, prop, value);
1142 }
1143
1144 static void
1145 gst_vaapi_display_finalize (GObject * object)
1146 {
1147   GstVaapiDisplay *const display = GST_VAAPI_DISPLAY (object);
1148   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1149
1150   gst_vaapi_display_destroy (display);
1151   g_rec_mutex_clear (&priv->mutex);
1152
1153   G_OBJECT_CLASS (gst_vaapi_display_parent_class)->finalize (object);
1154 }
1155
1156 void
1157 gst_vaapi_display_class_init (GstVaapiDisplayClass * klass)
1158 {
1159   GObjectClass *const object_class = G_OBJECT_CLASS (klass);
1160
1161   object_class->finalize = gst_vaapi_display_finalize;
1162   object_class->set_property = gst_vaapi_display_set_property;
1163   object_class->get_property = gst_vaapi_display_get_property;
1164
1165   klass->lock = gst_vaapi_display_lock_default;
1166   klass->unlock = gst_vaapi_display_unlock_default;
1167
1168   /**
1169    * GstVaapiDisplay:render-mode:
1170    *
1171    * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
1172    */
1173   g_properties[PROP_RENDER_MODE] =
1174       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
1175       "render mode",
1176       "The display rendering mode",
1177       GST_VAAPI_TYPE_RENDER_MODE, DEFAULT_RENDER_MODE, G_PARAM_READWRITE);
1178
1179   /**
1180    * GstVaapiDisplay:rotation:
1181    *
1182    * The VA display rotation mode, expressed as a #GstVaapiRotation.
1183    */
1184   g_properties[PROP_ROTATION] =
1185       g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION,
1186       "rotation",
1187       "The display rotation mode",
1188       GST_VAAPI_TYPE_ROTATION, DEFAULT_ROTATION, G_PARAM_READWRITE);
1189
1190   /**
1191    * GstVaapiDisplay:hue:
1192    *
1193    * The VA display hue, expressed as a float value. Range is -180.0
1194    * to 180.0. Default value is 0.0 and represents no modification.
1195    */
1196   g_properties[PROP_HUE] =
1197       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE,
1198       "hue", "The display hue value", -180.0, 180.0, 0.0, G_PARAM_READWRITE);
1199
1200   /**
1201    * GstVaapiDisplay:saturation:
1202    *
1203    * The VA display saturation, expressed as a float value. Range is
1204    * 0.0 to 2.0. Default value is 1.0 and represents no modification.
1205    */
1206   g_properties[PROP_SATURATION] =
1207       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION,
1208       "saturation",
1209       "The display saturation value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1210
1211   /**
1212    * GstVaapiDisplay:brightness:
1213    *
1214    * The VA display brightness, expressed as a float value. Range is
1215    * -1.0 to 1.0. Default value is 0.0 and represents no modification.
1216    */
1217   g_properties[PROP_BRIGHTNESS] =
1218       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
1219       "brightness",
1220       "The display brightness value", -1.0, 1.0, 0.0, G_PARAM_READWRITE);
1221
1222   /**
1223    * GstVaapiDisplay:contrast:
1224    *
1225    * The VA display contrast, expressed as a float value. Range is 0.0
1226    * to 2.0. Default value is 1.0 and represents no modification.
1227    */
1228   g_properties[PROP_CONTRAST] =
1229       g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST,
1230       "contrast",
1231       "The display contrast value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
1232
1233   /**
1234    * GstVaapiDisplay:va-display:
1235    *
1236    * The VA display handle, expressed as a #VADisplay.
1237    */
1238   g_properties[PROP_VA_DISPLAY] =
1239       g_param_spec_pointer ("va-display", "VADisplay",
1240       "VA Display handler", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
1241
1242   g_object_class_install_properties (object_class, N_PROPERTIES, g_properties);
1243   gst_type_mark_as_plugin_api (gst_vaapi_display_type_get_type (), 0);
1244 }
1245
1246 /**
1247  * gst_vaapi_display_config:
1248  * @display: instance of #GstVaapiDisplay
1249  * @init_type: type of initialization #GstVaapiDisplayInitType
1250  * @init_value: a pointer to the structure with the initialization
1251  * parameters
1252  *
1253  * Binds @display to the VA layer; otherwise it is just an empty
1254  * structure.
1255  *
1256  * Returns: the configured @display if it was configured correctly;
1257  * otherwise unrefs @display and returns %NULL.
1258  **/
1259 GstVaapiDisplay *
1260 gst_vaapi_display_config (GstVaapiDisplay * display,
1261     GstVaapiDisplayInitType init_type, gpointer init_value)
1262 {
1263   g_return_val_if_fail (display && GST_VAAPI_IS_DISPLAY (display), NULL);
1264
1265   if (!gst_vaapi_display_create (display, init_type, init_value))
1266     goto error;
1267   return display;
1268
1269   /* ERRORS */
1270 error:
1271   {
1272     gst_object_unref (display);
1273     return NULL;
1274   }
1275 }
1276
1277 /**
1278  * gst_vaapi_display_new_with_display:
1279  * @va_display: a #VADisplay
1280  *
1281  * Creates a new #GstVaapiDisplay, using @va_display as the VA
1282  * display.
1283  *
1284  * Return value: the newly created #GstVaapiDisplay object
1285  */
1286 GstVaapiDisplay *
1287 gst_vaapi_display_new_with_display (VADisplay va_display)
1288 {
1289   GstVaapiDisplayInfo info = {
1290     .va_display = va_display,
1291   };
1292
1293   return gst_vaapi_display_config (g_object_new (GST_TYPE_VAAPI_DISPLAY, NULL),
1294       GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info);
1295 }
1296
1297 /**
1298  * gst_vaapi_display_replace:
1299  * @old_display_ptr: a pointer to a #GstVaapiDisplay
1300  * @new_display: a #GstVaapiDisplay
1301  *
1302  * Atomically replaces the display display held in @old_display_ptr
1303  * with @new_display. This means that @old_display_ptr shall reference
1304  * a valid display. However, @new_display can be NULL.
1305  */
1306 void
1307 gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr,
1308     GstVaapiDisplay * new_display)
1309 {
1310   gst_object_replace ((GstObject **) old_display_ptr,
1311       (GstObject *) new_display);
1312 }
1313
1314 /**
1315  * gst_vaapi_display_lock:
1316  * @display: a #GstVaapiDisplay
1317  *
1318  * Locks @display. If @display is already locked by another thread,
1319  * the current thread will block until @display is unlocked by the
1320  * other thread.
1321  */
1322 void
1323 gst_vaapi_display_lock (GstVaapiDisplay * display)
1324 {
1325   GstVaapiDisplayClass *klass;
1326
1327   g_return_if_fail (display != NULL);
1328
1329   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1330   if (klass->lock)
1331     klass->lock (display);
1332 }
1333
1334 /**
1335  * gst_vaapi_display_unlock:
1336  * @display: a #GstVaapiDisplay
1337  *
1338  * Unlocks @display. If another thread is blocked in a
1339  * gst_vaapi_display_lock() call for @display, it will be woken and
1340  * can lock @display itself.
1341  */
1342 void
1343 gst_vaapi_display_unlock (GstVaapiDisplay * display)
1344 {
1345   GstVaapiDisplayClass *klass;
1346
1347   g_return_if_fail (display != NULL);
1348
1349   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1350   if (klass->unlock)
1351     klass->unlock (display);
1352 }
1353
1354 /**
1355  * gst_vaapi_display_sync:
1356  * @display: a #GstVaapiDisplay
1357  *
1358  * Flushes any requests queued for the windowing system and waits until
1359  * all requests have been handled. This is often used for making sure
1360  * that the display is synchronized with the current state of the program.
1361  *
1362  * This is most useful for X11. On windowing systems where requests are
1363  * handled synchronously, this function will do nothing.
1364  */
1365 void
1366 gst_vaapi_display_sync (GstVaapiDisplay * display)
1367 {
1368   GstVaapiDisplayClass *klass;
1369
1370   g_return_if_fail (display != NULL);
1371
1372   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1373   if (klass->sync)
1374     klass->sync (display);
1375   else if (klass->flush)
1376     klass->flush (display);
1377 }
1378
1379 /**
1380  * gst_vaapi_display_flush:
1381  * @display: a #GstVaapiDisplay
1382  *
1383  * Flushes any requests queued for the windowing system.
1384  *
1385  * This is most useful for X11. On windowing systems where requests
1386  * are handled synchronously, this function will do nothing.
1387  */
1388 void
1389 gst_vaapi_display_flush (GstVaapiDisplay * display)
1390 {
1391   GstVaapiDisplayClass *klass;
1392
1393   g_return_if_fail (display != NULL);
1394
1395   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
1396   if (klass->flush)
1397     klass->flush (display);
1398 }
1399
1400 /**
1401  * gst_vaapi_display_get_class_type:
1402  * @display: a #GstVaapiDisplay
1403  *
1404  * Returns the #GstVaapiDisplayType of @display. This is the type of
1405  * the object, thus the associated class, not the type of the VA
1406  * display.
1407  *
1408  * Return value: the #GstVaapiDisplayType
1409  */
1410 GstVaapiDisplayType
1411 gst_vaapi_display_get_class_type (GstVaapiDisplay * display)
1412 {
1413   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1414
1415   return GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display);
1416 }
1417
1418 /**
1419  * gst_vaapi_display_get_display_type:
1420  * @display: a #GstVaapiDisplay
1421  *
1422  * Returns the #GstVaapiDisplayType of the VA display bound to
1423  * @display. This is not the type of the @display object.
1424  *
1425  * Return value: the #GstVaapiDisplayType
1426  */
1427 GstVaapiDisplayType
1428 gst_vaapi_display_get_display_type (GstVaapiDisplay * display)
1429 {
1430   g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
1431
1432   return GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
1433 }
1434
1435 /**
1436  * gst_vaapi_display_get_display_type:
1437  * @display: a #GstVaapiDisplay
1438  *
1439  * Returns the @display name.
1440  *
1441  * Return value: the display name
1442  */
1443 const gchar *
1444 gst_vaapi_display_get_display_name (GstVaapiDisplay * display)
1445 {
1446   g_return_val_if_fail (display != NULL, NULL);
1447
1448   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display_name;
1449 }
1450
1451 /**
1452  * gst_vaapi_display_get_display:
1453  * @display: a #GstVaapiDisplay
1454  *
1455  * Returns the #VADisplay bound to @display.
1456  *
1457  * Return value: the #VADisplay
1458  */
1459 VADisplay
1460 gst_vaapi_display_get_display (GstVaapiDisplay * display)
1461 {
1462   g_return_val_if_fail (display != NULL, NULL);
1463
1464   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display;
1465 }
1466
1467 /**
1468  * gst_vaapi_display_get_width:
1469  * @display: a #GstVaapiDisplay
1470  *
1471  * Retrieves the width of a #GstVaapiDisplay.
1472  *
1473  * Return value: the width of the @display, in pixels
1474  */
1475 guint
1476 gst_vaapi_display_get_width (GstVaapiDisplay * display)
1477 {
1478   g_return_val_if_fail (display != NULL, 0);
1479
1480   gst_vaapi_display_ensure_screen_resolution (display);
1481
1482   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1483 }
1484
1485 /**
1486  * gst_vaapi_display_get_height:
1487  * @display: a #GstVaapiDisplay
1488  *
1489  * Retrieves the height of a #GstVaapiDisplay
1490  *
1491  * Return value: the height of the @display, in pixels
1492  */
1493 guint
1494 gst_vaapi_display_get_height (GstVaapiDisplay * display)
1495 {
1496   g_return_val_if_fail (display != NULL, 0);
1497
1498   gst_vaapi_display_ensure_screen_resolution (display);
1499
1500   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1501 }
1502
1503 /**
1504  * gst_vaapi_display_get_size:
1505  * @display: a #GstVaapiDisplay
1506  * @pwidth: return location for the width, or %NULL
1507  * @pheight: return location for the height, or %NULL
1508  *
1509  * Retrieves the dimensions of a #GstVaapiDisplay.
1510  */
1511 void
1512 gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth,
1513     guint * pheight)
1514 {
1515   g_return_if_fail (GST_VAAPI_DISPLAY (display));
1516
1517   gst_vaapi_display_ensure_screen_resolution (display);
1518
1519   if (pwidth)
1520     *pwidth = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
1521
1522   if (pheight)
1523     *pheight = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
1524 }
1525
1526 /**
1527  * gst_vaapi_display_get_pixel_aspect_ratio:
1528  * @display: a #GstVaapiDisplay
1529  * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
1530  * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
1531  *
1532  * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
1533  */
1534 void
1535 gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display,
1536     guint * par_n, guint * par_d)
1537 {
1538   g_return_if_fail (display != NULL);
1539
1540   gst_vaapi_display_ensure_screen_resolution (display);
1541
1542   if (par_n)
1543     *par_n = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_n;
1544
1545   if (par_d)
1546     *par_d = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_d;
1547 }
1548
1549 /**
1550  * gst_vaapi_display_has_video_processing:
1551  * @display: a #GstVaapiDisplay
1552  *
1553  * Checks whether the underlying VA driver implementation supports
1554  * video processing (VPP) acceleration.
1555  *
1556  * Returns: %TRUE if some VPP features are available
1557  */
1558 gboolean
1559 gst_vaapi_display_has_video_processing (GstVaapiDisplay * display)
1560 {
1561   g_return_val_if_fail (display != NULL, FALSE);
1562
1563   if (!ensure_profiles (display))
1564     return FALSE;
1565   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->has_vpp;
1566 }
1567
1568 /**
1569  * gst_vaapi_display_get_decode_profiles:
1570  * @display: a #GstVaapiDisplay
1571  *
1572  * Gets the supported profiles for decoding. The caller owns an extra
1573  * reference to the resulting array of #GstVaapiProfile elements, so
1574  * it shall be released with g_array_unref() after usage.
1575  *
1576  * Return value: a newly allocated #GArray, or %NULL if error or if
1577  *   decoding is not supported at all
1578  */
1579 GArray *
1580 gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display)
1581 {
1582   g_return_val_if_fail (display != NULL, NULL);
1583
1584   if (!ensure_profiles (display))
1585     return NULL;
1586   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders, 0);
1587 }
1588
1589 /**
1590  * gst_vaapi_display_has_decoder:
1591  * @display: a #GstVaapiDisplay
1592  * @profile: a #VAProfile
1593  * @entrypoint: a #GstVaaiEntrypoint
1594  *
1595  * Returns whether VA @display supports @profile for decoding at the
1596  * specified @entrypoint.
1597  *
1598  * Return value: %TRUE if VA @display supports @profile for decoding.
1599  */
1600 gboolean
1601 gst_vaapi_display_has_decoder (GstVaapiDisplay * display,
1602     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1603 {
1604   g_return_val_if_fail (display != NULL, FALSE);
1605
1606   if (!ensure_profiles (display))
1607     return FALSE;
1608   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders,
1609       profile, entrypoint);
1610 }
1611
1612 /**
1613  * gst_vaapi_display_get_encode_profiles:
1614  * @display: a #GstVaapiDisplay
1615  *
1616  * Gets the supported profiles for encoding. The caller owns an extra
1617  * reference to the resulting array of #GstVaapiProfile elements, so
1618  * it shall be released with g_array_unref() after usage.
1619  *
1620  * Return value: a newly allocated #GArray, or %NULL if error or if
1621  *   encoding is not supported at all
1622  */
1623 GArray *
1624 gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display)
1625 {
1626   g_return_val_if_fail (display != NULL, NULL);
1627
1628   if (!ensure_profiles (display))
1629     return NULL;
1630   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders, 0);
1631 }
1632
1633 /**
1634  * gst_vaapi_display_get_encode_profiles_by_codec:
1635  * @display: a #GstVaapiDisplay
1636  * @codec: a #GstVaapiCodec
1637  *
1638  * Gets the supported profiles which belongs to @codec for encoding.
1639  * The caller owns an extra reference to the resulting array of
1640  * #GstVaapiProfile elements, so it shall be released with g_array_unref()
1641  * after usage.
1642  *
1643  * Return value: a newly allocated #GArray, or %NULL if error or if
1644  *   no encoding profile is found specified by the @codec.
1645  */
1646 GArray *
1647 gst_vaapi_display_get_encode_profiles_by_codec (GstVaapiDisplay * display,
1648     GstVaapiCodec codec)
1649 {
1650   g_return_val_if_fail (display != NULL, NULL);
1651
1652   if (!ensure_profiles (display))
1653     return NULL;
1654   return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
1655       codec);
1656 }
1657
1658 /**
1659  * gst_vaapi_display_has_encoder:
1660  * @display: a #GstVaapiDisplay
1661  * @profile: a #VAProfile
1662  * @entrypoint: a #GstVaapiEntrypoint
1663  *
1664  * Returns whether VA @display supports @profile for encoding at the
1665  * specified @entrypoint.
1666  *
1667  * Return value: %TRUE if VA @display supports @profile for encoding.
1668  */
1669 gboolean
1670 gst_vaapi_display_has_encoder (GstVaapiDisplay * display,
1671     GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
1672 {
1673   g_return_val_if_fail (display != NULL, FALSE);
1674
1675   if (!ensure_profiles (display))
1676     return FALSE;
1677   return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
1678       profile, entrypoint);
1679 }
1680
1681 /**
1682  * gst_vaapi_display_get_image_formats:
1683  * @display: a #GstVaapiDisplay
1684  *
1685  * Gets the supported image formats for gst_vaapi_surface_get_image()
1686  * or gst_vaapi_surface_put_image().
1687  *
1688  * Note that this method does not necessarily map image formats
1689  * returned by vaQueryImageFormats(). The set of capabilities can be
1690  * stripped down, if gstreamer-vaapi does not support the format, or
1691  * expanded to cover compatible formats not exposed by the underlying
1692  * driver. e.g. I420 can be supported even if the driver only exposes
1693  * YV12.
1694  *
1695  * Note: the caller owns an extra reference to the resulting array of
1696  * #GstVideoFormat elements, so it shall be released with
1697  * g_array_unref() after usage.
1698  *
1699  * Return value: a newly allocated #GArray, or %NULL on error or if
1700  *   the set is empty
1701  */
1702 GArray *
1703 gst_vaapi_display_get_image_formats (GstVaapiDisplay * display)
1704 {
1705   g_return_val_if_fail (display != NULL, NULL);
1706
1707   if (!ensure_image_formats (display))
1708     return NULL;
1709   return get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->image_formats);
1710 }
1711
1712 /**
1713  * gst_vaapi_display_has_image_format:
1714  * @display: a #GstVaapiDisplay
1715  * @format: a #GstVideoFormat
1716  *
1717  * Returns whether VA @display supports @format image format.
1718  *
1719  * Return value: %TRUE if VA @display supports @format image format
1720  */
1721 gboolean
1722 gst_vaapi_display_has_image_format (GstVaapiDisplay * display,
1723     GstVideoFormat format)
1724 {
1725   GstVaapiDisplayPrivate *priv;
1726
1727   g_return_val_if_fail (display != NULL, FALSE);
1728   g_return_val_if_fail (format, FALSE);
1729
1730   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1731
1732   if (!ensure_image_formats (display))
1733     return FALSE;
1734   if (find_format (priv->image_formats, format))
1735     return TRUE;
1736
1737   /* XXX: try subpicture formats since some drivers could report a
1738    * set of VA image formats that is not a superset of the set of VA
1739    * subpicture formats
1740    */
1741   if (!ensure_subpicture_formats (display))
1742     return FALSE;
1743   return find_format (priv->subpicture_formats, format);
1744 }
1745
1746 /**
1747  * gst_vaapi_display_get_subpicture_formats:
1748  * @display: a #GstVaapiDisplay
1749  *
1750  * Gets the supported subpicture formats.
1751  *
1752  * Note that this method does not necessarily map subpicture formats
1753  * returned by vaQuerySubpictureFormats(). The set of capabilities can
1754  * be stripped down if gstreamer-vaapi does not support the
1755  * format. e.g. this is the case for paletted formats like IA44.
1756  *
1757  * Note: the caller owns an extra reference to the resulting array of
1758  * #GstVideoFormat elements, so it shall be released with
1759  * g_array_unref() after usage.
1760  *
1761  * Return value: a newly allocated #GArray, or %NULL on error of if
1762  *   the set is empty
1763  */
1764 GArray *
1765 gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display)
1766 {
1767   g_return_val_if_fail (display != NULL, NULL);
1768
1769   if (!ensure_subpicture_formats (display))
1770     return NULL;
1771   return
1772       get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->subpicture_formats);
1773 }
1774
1775 /**
1776  * gst_vaapi_display_has_subpicture_format:
1777  * @display: a #GstVaapiDisplay
1778  * @format: a #GstVideoFormat
1779  * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero
1780  *
1781  * Returns whether VA @display supports @format subpicture format with
1782  * the supplied @flags.
1783  *
1784  * Return value: %TRUE if VA @display supports @format subpicture format
1785  */
1786 gboolean
1787 gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display,
1788     GstVideoFormat format, guint * flags_ptr)
1789 {
1790   GstVaapiDisplayPrivate *priv;
1791   const GstVaapiFormatInfo *fip;
1792
1793   g_return_val_if_fail (display != NULL, FALSE);
1794   g_return_val_if_fail (format, FALSE);
1795
1796   priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1797
1798   if (!ensure_subpicture_formats (display))
1799     return FALSE;
1800
1801   fip = find_format_info (priv->subpicture_formats, format);
1802   if (!fip)
1803     return FALSE;
1804
1805   if (flags_ptr)
1806     *flags_ptr = fip->flags;
1807   return TRUE;
1808 }
1809
1810 /**
1811  * gst_vaapi_display_has_property:
1812  * @display: a #GstVaapiDisplay
1813  * @name: the property name to check
1814  *
1815  * Returns whether VA @display supports the requested property. The
1816  * check is performed against the property @name. So, the client
1817  * application may perform this check only once and cache this
1818  * information.
1819  *
1820  * Return value: %TRUE if VA @display supports property @name
1821  */
1822 gboolean
1823 gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name)
1824 {
1825   g_return_val_if_fail (display != NULL, FALSE);
1826   g_return_val_if_fail (name, FALSE);
1827
1828   if (!ensure_properties (display))
1829     return FALSE;
1830   return find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties,
1831       name) != NULL;
1832 }
1833
1834 static gboolean
1835 get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
1836     gint * value)
1837 {
1838   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1839   VADisplayAttribute attr = { 0, };
1840   VAStatus status;
1841
1842   attr.type = type;
1843   attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
1844   status = vaGetDisplayAttributes (priv->display, &attr, 1);
1845   if (!vaapi_check_status (status, "vaGetDisplayAttributes()"))
1846     return FALSE;
1847   *value = attr.value;
1848   return TRUE;
1849 }
1850
1851 static gboolean
1852 set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value)
1853 {
1854   GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
1855   VADisplayAttribute attr = { 0, };
1856   VAStatus status;
1857
1858   attr.type = type;
1859   attr.value = value;
1860   attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
1861   status = vaSetDisplayAttributes (priv->display, &attr, 1);
1862   if (!vaapi_check_status (status, "vaSetDisplayAttributes()"))
1863     return FALSE;
1864   return TRUE;
1865 }
1866
1867 static gboolean
1868 get_render_mode_VADisplayAttribRenderMode (GstVaapiDisplay * display,
1869     GstVaapiRenderMode * pmode)
1870 {
1871   gint modes, devices;
1872
1873   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1874     return FALSE;
1875   if (!devices)
1876     return FALSE;
1877   if (!get_attribute (display, VADisplayAttribRenderMode, &modes))
1878     return FALSE;
1879
1880   /* Favor "overlay" mode since it is the most restrictive one */
1881   if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY | VA_RENDER_MODE_EXTERNAL_OVERLAY))
1882     *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1883   else
1884     *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
1885   return TRUE;
1886 }
1887
1888 static gboolean
1889 get_render_mode_default (GstVaapiDisplay * display, GstVaapiRenderMode * pmode)
1890 {
1891   switch (GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display)) {
1892 #if USE_WAYLAND
1893     case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
1894       /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
1895       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1896       break;
1897 #endif
1898 #if USE_DRM
1899     case GST_VAAPI_DISPLAY_TYPE_DRM:
1900       /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
1901       *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
1902       break;
1903 #endif
1904     default:
1905       /* This includes VA/X11 and VA/GLX modes */
1906       *pmode = DEFAULT_RENDER_MODE;
1907       break;
1908   }
1909   return TRUE;
1910 }
1911
1912 /**
1913  * gst_vaapi_display_get_render_mode:
1914  * @display: a #GstVaapiDisplay
1915  * @pmode: return location for the VA @display rendering mode
1916  *
1917  * Returns the current VA @display rendering mode.
1918  *
1919  * Return value: %TRUE if VA @display rendering mode could be determined
1920  */
1921 gboolean
1922 gst_vaapi_display_get_render_mode (GstVaapiDisplay * display,
1923     GstVaapiRenderMode * pmode)
1924 {
1925   g_return_val_if_fail (display != NULL, FALSE);
1926
1927   /* Try with render-mode attribute */
1928   if (get_render_mode_VADisplayAttribRenderMode (display, pmode))
1929     return TRUE;
1930
1931   /* Default: determine from the display type */
1932   return get_render_mode_default (display, pmode);
1933 }
1934
1935 /**
1936  * gst_vaapi_display_set_render_mode:
1937  * @display: a #GstVaapiDisplay
1938  * @mode: the #GstVaapiRenderMode to set
1939  *
1940  * Sets the VA @display rendering mode to the supplied @mode. This
1941  * function returns %FALSE if the rendering mode could not be set,
1942  * e.g. run-time switching rendering mode is not supported.
1943  *
1944  * Return value: %TRUE if VA @display rendering @mode could be changed
1945  *   to the requested value
1946  */
1947 gboolean
1948 gst_vaapi_display_set_render_mode (GstVaapiDisplay * display,
1949     GstVaapiRenderMode mode)
1950 {
1951   gint modes, devices;
1952
1953   g_return_val_if_fail (display != NULL, FALSE);
1954
1955   if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
1956     return FALSE;
1957
1958   modes = 0;
1959   switch (mode) {
1960     case GST_VAAPI_RENDER_MODE_OVERLAY:
1961       if (devices & VA_RENDER_DEVICE_LOCAL)
1962         modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
1963       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1964         modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
1965       break;
1966     case GST_VAAPI_RENDER_MODE_TEXTURE:
1967       if (devices & VA_RENDER_DEVICE_LOCAL)
1968         modes |= VA_RENDER_MODE_LOCAL_GPU;
1969       if (devices & VA_RENDER_DEVICE_EXTERNAL)
1970         modes |= VA_RENDER_MODE_EXTERNAL_GPU;
1971       break;
1972   }
1973   if (!modes)
1974     return FALSE;
1975   if (!set_attribute (display, VADisplayAttribRenderMode, modes))
1976     return FALSE;
1977   return TRUE;
1978 }
1979
1980 /**
1981  * gst_vaapi_display_get_rotation:
1982  * @display: a #GstVaapiDisplay
1983  *
1984  * Returns the current VA @display rotation angle. If the VA driver
1985  * does not support "rotation" display attribute, then the display is
1986  * assumed to be un-rotated.
1987  *
1988  * Return value: the current #GstVaapiRotation value
1989  */
1990 GstVaapiRotation
1991 gst_vaapi_display_get_rotation (GstVaapiDisplay * display)
1992 {
1993   gint value;
1994
1995   g_return_val_if_fail (display != NULL, DEFAULT_ROTATION);
1996
1997   if (!get_attribute (display, VADisplayAttribRotation, &value))
1998     value = VA_ROTATION_NONE;
1999   return to_GstVaapiRotation (value);
2000 }
2001
2002 /**
2003  * gst_vaapi_display_set_rotation:
2004  * @display: a #GstVaapiDisplay
2005  * @rotation: the #GstVaapiRotation value to set
2006  *
2007  * Sets the VA @display rotation angle to the supplied @rotation
2008  * value. This function returns %FALSE if the rotation angle could not
2009  * be set, e.g. the VA driver does not allow to change the display
2010  * rotation angle.
2011  *
2012  * Return value: %TRUE if VA @display rotation angle could be changed
2013  *   to the requested value
2014  */
2015 gboolean
2016 gst_vaapi_display_set_rotation (GstVaapiDisplay * display,
2017     GstVaapiRotation rotation)
2018 {
2019   guint value;
2020
2021   g_return_val_if_fail (display != NULL, FALSE);
2022
2023   value = from_GstVaapiRotation (rotation);
2024   if (!set_attribute (display, VADisplayAttribRotation, value))
2025     return FALSE;
2026   return TRUE;
2027 }
2028
2029 /* Get color balance attributes */
2030 static gboolean
2031 get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v)
2032 {
2033   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
2034   const GstVaapiProperty *prop;
2035   const VADisplayAttribute *attr;
2036   gfloat out_value;
2037   gint value;
2038
2039   if (!ensure_properties (display))
2040     return FALSE;
2041
2042   if (!pspec)
2043     return FALSE;
2044
2045   prop = find_property_by_pspec (display, &pspec->parent_instance);
2046   if (!prop)
2047     return FALSE;
2048   attr = &prop->attribute;
2049
2050   if (!get_attribute (display, attr->type, &value))
2051     return FALSE;
2052
2053   /* Scale wrt. the medium ("default") value */
2054   out_value = pspec->default_value;
2055   if (value > attr->value)
2056     out_value += ((gfloat) (value - attr->value) /
2057         (attr->max_value - attr->value) *
2058         (pspec->maximum - pspec->default_value));
2059   else if (value < attr->value)
2060     out_value -= ((gfloat) (attr->value - value) /
2061         (attr->value - attr->min_value) *
2062         (pspec->default_value - pspec->minimum));
2063   *v = out_value;
2064   return TRUE;
2065 }
2066
2067 /* Set color balance attribute */
2068 static gboolean
2069 set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v)
2070 {
2071   GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
2072   const GstVaapiProperty *prop;
2073   const VADisplayAttribute *attr;
2074   gint value;
2075
2076   if (!ensure_properties (display))
2077     return FALSE;
2078
2079   if (!pspec)
2080     return FALSE;
2081
2082   prop = find_property_by_pspec (display, &pspec->parent_instance);
2083   if (!prop)
2084     return FALSE;
2085   attr = &prop->attribute;
2086
2087   /* Scale wrt. the medium ("default") value */
2088   value = attr->value;
2089   if (v > pspec->default_value)
2090     value += ((v - pspec->default_value) /
2091         (pspec->maximum - pspec->default_value) *
2092         (attr->max_value - attr->value));
2093   else if (v < pspec->default_value)
2094     value -= ((pspec->default_value - v) /
2095         (pspec->default_value - pspec->minimum) *
2096         (attr->value - attr->min_value));
2097   if (!set_attribute (display, attr->type, value))
2098     return FALSE;
2099   return TRUE;
2100 }
2101
2102 /**
2103  * gst_vaapi_display_get_vendor_string:
2104  * @display: a #GstVaapiDisplay
2105  *
2106  * Returns the VA driver vendor string attached to the supplied VA @display.
2107  * The @display owns the vendor string, do *not* de-allocate it.
2108  *
2109  * This function is thread safe.
2110  *
2111  * Return value: the current #GstVaapiRotation value
2112  */
2113 const gchar *
2114 gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display)
2115 {
2116   g_return_val_if_fail (display != NULL, NULL);
2117
2118   if (!ensure_vendor_string (display))
2119     return NULL;
2120   return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->vendor_string;
2121 }
2122
2123 /**
2124  * gst_vaapi_display_has_opengl:
2125  * @display: a #GstVaapiDisplay
2126  *
2127  * Returns wether the @display that was created does support OpenGL
2128  * context to be attached.
2129  *
2130  * This function is thread safe.
2131  *
2132  * Return value: %TRUE if the @display supports OpenGL context, %FALSE
2133  *   otherwise
2134  */
2135 gboolean
2136 gst_vaapi_display_has_opengl (GstVaapiDisplay * display)
2137 {
2138   GstVaapiDisplayClass *klass;
2139
2140   g_return_val_if_fail (display != NULL, FALSE);
2141
2142   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2143   return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX ||
2144       klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL);
2145 }
2146
2147 /**
2148  * gst_vaapi_display_reset_texture_map:
2149  * @display: a #GstVaapiDisplay
2150  *
2151  * Reset the internal #GstVaapiTextureMap if available.
2152  *
2153  * This function is thread safe.
2154  */
2155 void
2156 gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display)
2157 {
2158   GstVaapiDisplayClass *klass;
2159   GstVaapiTextureMap *map;
2160
2161   g_return_if_fail (display != NULL);
2162
2163   if (!gst_vaapi_display_has_opengl (display))
2164     return;
2165   klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
2166   if (!klass->get_texture_map)
2167     return;
2168   if ((map = klass->get_texture_map (display)))
2169     gst_vaapi_texture_map_reset (map);
2170 }
2171
2172 /**
2173  * gst_vaapi_display_get_driver_quirks:
2174  * @display: a #GstVaapiDisplay
2175  * @quirks: the #GstVaapiDriverQuirks bitwise to check
2176  *
2177  * Returns: %TRUE if @quirks are set in @display's driver
2178  **/
2179 gboolean
2180 gst_vaapi_display_has_driver_quirks (GstVaapiDisplay * display, guint quirks)
2181 {
2182   g_return_val_if_fail (display != NULL, FALSE);
2183
2184   return (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->driver_quirks & quirks);
2185 }