1 /* GStreamer
2 * Copyright (C) 2021 Igalia, S.L.
3 * Author: Víctor Jáquez <vjaquez@igalia.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "vasurfaceimage.h"
22
23 #include "gstvavideoformat.h"
24 #include <va/va.h>
25
26 gboolean
va_destroy_surfaces(GstVaDisplay * display,VASurfaceID * surfaces,gint num_surfaces)27 va_destroy_surfaces (GstVaDisplay * display, VASurfaceID * surfaces,
28 gint num_surfaces)
29 {
30 VADisplay dpy = gst_va_display_get_va_dpy (display);
31 VAStatus status;
32
33 g_return_val_if_fail (num_surfaces > 0, FALSE);
34
35 gst_va_display_lock (display);
36 status = vaDestroySurfaces (dpy, surfaces, num_surfaces);
37 gst_va_display_unlock (display);
38 if (status != VA_STATUS_SUCCESS) {
39 GST_ERROR ("vaDestroySurfaces: %s", vaErrorStr (status));
40 return FALSE;
41 }
42
43 return TRUE;
44
45 }
46
47 gboolean
va_create_surfaces(GstVaDisplay * display,guint rt_format,guint fourcc,guint width,guint height,gint usage_hint,VASurfaceAttribExternalBuffers * ext_buf,VASurfaceID * surfaces,guint num_surfaces)48 va_create_surfaces (GstVaDisplay * display, guint rt_format, guint fourcc,
49 guint width, guint height, gint usage_hint,
50 VASurfaceAttribExternalBuffers * ext_buf, VASurfaceID * surfaces,
51 guint num_surfaces)
52 {
53 VADisplay dpy = gst_va_display_get_va_dpy (display);
54 /* *INDENT-OFF* */
55 VASurfaceAttrib attrs[5] = {
56 {
57 .type = VASurfaceAttribUsageHint,
58 .flags = VA_SURFACE_ATTRIB_SETTABLE,
59 .value.type = VAGenericValueTypeInteger,
60 .value.value.i = usage_hint,
61 },
62 {
63 .type = VASurfaceAttribMemoryType,
64 .flags = VA_SURFACE_ATTRIB_SETTABLE,
65 .value.type = VAGenericValueTypeInteger,
66 .value.value.i = (ext_buf && ext_buf->num_buffers > 0)
67 ? VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME
68 : VA_SURFACE_ATTRIB_MEM_TYPE_VA,
69 },
70 };
71 /* *INDENT-ON* */
72 VAStatus status;
73 guint num_attrs = 2;
74
75 g_return_val_if_fail (num_surfaces > 0, FALSE);
76
77 if (fourcc > 0) {
78 /* *INDENT-OFF* */
79 attrs[num_attrs++] = (VASurfaceAttrib) {
80 .type = VASurfaceAttribPixelFormat,
81 .flags = VA_SURFACE_ATTRIB_SETTABLE,
82 .value.type = VAGenericValueTypeInteger,
83 .value.value.i = fourcc,
84 };
85 /* *INDENT-ON* */
86 }
87
88 if (ext_buf) {
89 /* *INDENT-OFF* */
90 attrs[num_attrs++] = (VASurfaceAttrib) {
91 .type = VASurfaceAttribExternalBufferDescriptor,
92 .flags = VA_SURFACE_ATTRIB_SETTABLE,
93 .value.type = VAGenericValueTypePointer,
94 .value.value.p = ext_buf,
95 };
96 /* *INDENT-ON* */
97 }
98
99 gst_va_display_lock (display);
100 status = vaCreateSurfaces (dpy, rt_format, width, height, surfaces,
101 num_surfaces, attrs, num_attrs);
102 gst_va_display_unlock (display);
103 if (status != VA_STATUS_SUCCESS) {
104 GST_ERROR ("vaCreateSurfaces: %s", vaErrorStr (status));
105 return FALSE;
106 }
107
108 return TRUE;
109 }
110
111 gboolean
va_export_surface_to_dmabuf(GstVaDisplay * display,VASurfaceID surface,guint32 flags,VADRMPRIMESurfaceDescriptor * desc)112 va_export_surface_to_dmabuf (GstVaDisplay * display, VASurfaceID surface,
113 guint32 flags, VADRMPRIMESurfaceDescriptor * desc)
114 {
115 VADisplay dpy = gst_va_display_get_va_dpy (display);
116 VAStatus status;
117
118 gst_va_display_lock (display);
119 status = vaExportSurfaceHandle (dpy, surface,
120 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, flags, desc);
121 gst_va_display_unlock (display);
122 if (status != VA_STATUS_SUCCESS) {
123 GST_ERROR ("vaExportSurfaceHandle: %s", vaErrorStr (status));
124 return FALSE;
125 }
126
127 return TRUE;
128 }
129
130 gboolean
va_destroy_image(GstVaDisplay * display,VAImageID image_id)131 va_destroy_image (GstVaDisplay * display, VAImageID image_id)
132 {
133 VADisplay dpy = gst_va_display_get_va_dpy (display);
134 VAStatus status;
135
136 gst_va_display_lock (display);
137 status = vaDestroyImage (dpy, image_id);
138 gst_va_display_unlock (display);
139 if (status != VA_STATUS_SUCCESS) {
140 GST_ERROR ("vaDestroyImage: %s", vaErrorStr (status));
141 return FALSE;
142 }
143 return TRUE;
144 }
145
146 gboolean
va_get_derive_image(GstVaDisplay * display,VASurfaceID surface,VAImage * image)147 va_get_derive_image (GstVaDisplay * display, VASurfaceID surface,
148 VAImage * image)
149 {
150 VADisplay dpy = gst_va_display_get_va_dpy (display);
151 VAStatus status;
152
153 gst_va_display_lock (display);
154 status = vaDeriveImage (dpy, surface, image);
155 gst_va_display_unlock (display);
156 if (status != VA_STATUS_SUCCESS) {
157 GST_WARNING ("vaDeriveImage: %s", vaErrorStr (status));
158 return FALSE;
159 }
160
161 return TRUE;
162 }
163
164 gboolean
va_create_image(GstVaDisplay * display,GstVideoFormat format,gint width,gint height,VAImage * image)165 va_create_image (GstVaDisplay * display, GstVideoFormat format, gint width,
166 gint height, VAImage * image)
167 {
168 VADisplay dpy = gst_va_display_get_va_dpy (display);
169 const VAImageFormat *va_format;
170 VAStatus status;
171
172 va_format = gst_va_image_format_from_video_format (format);
173 if (!va_format)
174 return FALSE;
175
176 gst_va_display_lock (display);
177 status =
178 vaCreateImage (dpy, (VAImageFormat *) va_format, width, height, image);
179 gst_va_display_unlock (display);
180 if (status != VA_STATUS_SUCCESS) {
181 GST_ERROR ("vaCreateImage: %s", vaErrorStr (status));
182 return FALSE;
183 }
184 return TRUE;
185 }
186
187 gboolean
va_get_image(GstVaDisplay * display,VASurfaceID surface,VAImage * image)188 va_get_image (GstVaDisplay * display, VASurfaceID surface, VAImage * image)
189 {
190 VADisplay dpy = gst_va_display_get_va_dpy (display);
191 VAStatus status;
192
193 gst_va_display_lock (display);
194 status = vaGetImage (dpy, surface, 0, 0, image->width, image->height,
195 image->image_id);
196 gst_va_display_unlock (display);
197 if (status != VA_STATUS_SUCCESS) {
198 GST_ERROR ("vaGetImage: %s", vaErrorStr (status));
199 return FALSE;
200 }
201
202 return TRUE;
203 }
204
205 gboolean
va_sync_surface(GstVaDisplay * display,VASurfaceID surface)206 va_sync_surface (GstVaDisplay * display, VASurfaceID surface)
207 {
208 VADisplay dpy = gst_va_display_get_va_dpy (display);
209 VAStatus status;
210
211 gst_va_display_lock (display);
212 status = vaSyncSurface (dpy, surface);
213 gst_va_display_unlock (display);
214 if (status != VA_STATUS_SUCCESS) {
215 GST_WARNING ("vaSyncSurface: %s", vaErrorStr (status));
216 return FALSE;
217 }
218 return TRUE;
219 }
220
221 gboolean
va_map_buffer(GstVaDisplay * display,VABufferID buffer,gpointer * data)222 va_map_buffer (GstVaDisplay * display, VABufferID buffer, gpointer * data)
223 {
224 VADisplay dpy = gst_va_display_get_va_dpy (display);
225 VAStatus status;
226
227 gst_va_display_lock (display);
228 status = vaMapBuffer (dpy, buffer, data);
229 gst_va_display_unlock (display);
230 if (status != VA_STATUS_SUCCESS) {
231 GST_WARNING ("vaMapBuffer: %s", vaErrorStr (status));
232 return FALSE;
233 }
234 return TRUE;
235 }
236
237 gboolean
va_unmap_buffer(GstVaDisplay * display,VABufferID buffer)238 va_unmap_buffer (GstVaDisplay * display, VABufferID buffer)
239 {
240 VADisplay dpy = gst_va_display_get_va_dpy (display);
241 VAStatus status;
242
243 gst_va_display_lock (display);
244 status = vaUnmapBuffer (dpy, buffer);
245 gst_va_display_unlock (display);
246 if (status != VA_STATUS_SUCCESS) {
247 GST_WARNING ("vaUnmapBuffer: %s", vaErrorStr (status));
248 return FALSE;
249 }
250 return TRUE;
251 }
252
253 gboolean
va_put_image(GstVaDisplay * display,VASurfaceID surface,VAImage * image)254 va_put_image (GstVaDisplay * display, VASurfaceID surface, VAImage * image)
255 {
256 VADisplay dpy = gst_va_display_get_va_dpy (display);
257 VAStatus status;
258
259 if (!va_sync_surface (display, surface))
260 return FALSE;
261
262 gst_va_display_lock (display);
263 status = vaPutImage (dpy, surface, image->image_id, 0, 0, image->width,
264 image->height, 0, 0, image->width, image->height);
265 gst_va_display_unlock (display);
266 if (status != VA_STATUS_SUCCESS) {
267 GST_ERROR ("vaPutImage: %s", vaErrorStr (status));
268 return FALSE;
269 }
270 return TRUE;
271 }
272
273 gboolean
va_ensure_image(GstVaDisplay * display,VASurfaceID surface,GstVideoInfo * info,VAImage * image,gboolean derived)274 va_ensure_image (GstVaDisplay * display, VASurfaceID surface,
275 GstVideoInfo * info, VAImage * image, gboolean derived)
276 {
277 gboolean ret = TRUE;
278
279 if (image->image_id != VA_INVALID_ID)
280 return TRUE;
281
282 if (!va_sync_surface (display, surface))
283 return FALSE;
284
285 if (derived) {
286 ret = va_get_derive_image (display, surface, image);
287 } else {
288 ret = va_create_image (display, GST_VIDEO_INFO_FORMAT (info),
289 GST_VIDEO_INFO_WIDTH (info), GST_VIDEO_INFO_HEIGHT (info), image);
290 }
291
292 return ret;
293 }
294
295 gboolean
va_check_surface(GstVaDisplay * display,VASurfaceID surface)296 va_check_surface (GstVaDisplay * display, VASurfaceID surface)
297 {
298 VADisplay dpy = gst_va_display_get_va_dpy (display);
299 VAStatus status;
300 VASurfaceStatus state;
301
302 gst_va_display_lock (display);
303 status = vaQuerySurfaceStatus (dpy, surface, &state);
304 gst_va_display_unlock (display);
305
306 if (status != VA_STATUS_SUCCESS)
307 GST_ERROR ("vaQuerySurfaceStatus: %s", vaErrorStr (status));
308
309 GST_LOG ("surface %#x status %d", surface, state);
310
311 return (status == VA_STATUS_SUCCESS);
312 }
313
314 gboolean
va_copy_surface(GstVaDisplay * display,VASurfaceID dst,VASurfaceID src)315 va_copy_surface (GstVaDisplay * display, VASurfaceID dst, VASurfaceID src)
316 {
317 #if VA_CHECK_VERSION (1, 12, 0)
318 VADisplay dpy = gst_va_display_get_va_dpy (display);
319 /* *INDENT-OFF* */
320 VACopyObject obj_src = {
321 .obj_type = VACopyObjectSurface,
322 .object = {
323 .surface_id = src,
324 },
325 };
326 VACopyObject obj_dst = {
327 .obj_type = VACopyObjectSurface,
328 .object = {
329 .surface_id = dst,
330 },
331 };
332 VACopyOption option = {
333 .bits = {
334 .va_copy_sync = VA_EXEC_SYNC,
335 .va_copy_mode = VA_EXEC_MODE_DEFAULT,
336 },
337 };
338 /* *INDENT-ON* */
339 VAStatus status;
340
341 gst_va_display_lock (display);
342 status = vaCopy (dpy, &obj_dst, &obj_src, option);
343 gst_va_display_unlock (display);
344 if (status != VA_STATUS_SUCCESS) {
345 GST_INFO ("vaCopy: %s", vaErrorStr (status));
346 return FALSE;
347 }
348 return TRUE;
349 #else
350 return FALSE;
351 #endif
352 }
353