• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4  * Copyright 2014 Advanced Micro Devices, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "pipe/p_screen.h"
30 #include "frontend/drm_driver.h"
31 #include "util/u_memory.h"
32 #include "util/u_handle_table.h"
33 #include "util/u_transfer.h"
34 #include "util/set.h"
35 #include "vl/vl_winsys.h"
36 
37 #include "va_private.h"
38 
39 #ifdef _WIN32
40 #include <va/va_win32.h>
41 #endif
42 
43 #ifndef VA_MAPBUFFER_FLAG_DEFAULT
44 #define VA_MAPBUFFER_FLAG_DEFAULT 0
45 #define VA_MAPBUFFER_FLAG_READ    1
46 #define VA_MAPBUFFER_FLAG_WRITE   2
47 #endif
48 
49 VAStatus
vlVaCreateBuffer(VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void * data,VABufferID * buf_id)50 vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type,
51                  unsigned int size, unsigned int num_elements, void *data,
52                  VABufferID *buf_id)
53 {
54    vlVaDriver *drv;
55    vlVaBuffer *buf;
56 
57    if (!ctx)
58       return VA_STATUS_ERROR_INVALID_CONTEXT;
59 
60    buf = CALLOC(1, sizeof(vlVaBuffer));
61    if (!buf)
62       return VA_STATUS_ERROR_ALLOCATION_FAILED;
63 
64    buf->type = type;
65    buf->size = size;
66    buf->num_elements = num_elements;
67 
68    if (buf->type == VAEncCodedBufferType)
69       buf->data = CALLOC(1, sizeof(VACodedBufferSegment));
70    else
71       buf->data = MALLOC(size * num_elements);
72 
73    if (!buf->data) {
74       FREE(buf);
75       return VA_STATUS_ERROR_ALLOCATION_FAILED;
76    }
77 
78    if (data)
79       memcpy(buf->data, data, size * num_elements);
80 
81    drv = VL_VA_DRIVER(ctx);
82    mtx_lock(&drv->mutex);
83    *buf_id = handle_table_add(drv->htab, buf);
84    mtx_unlock(&drv->mutex);
85 
86    return VA_STATUS_SUCCESS;
87 }
88 
89 VAStatus
vlVaBufferSetNumElements(VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements)90 vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id,
91                          unsigned int num_elements)
92 {
93    vlVaDriver *drv;
94    vlVaBuffer *buf;
95 
96    if (!ctx)
97       return VA_STATUS_ERROR_INVALID_CONTEXT;
98 
99    drv = VL_VA_DRIVER(ctx);
100    mtx_lock(&drv->mutex);
101    buf = handle_table_get(drv->htab, buf_id);
102    mtx_unlock(&drv->mutex);
103    if (!buf)
104       return VA_STATUS_ERROR_INVALID_BUFFER;
105 
106    if (buf->derived_surface.resource)
107       return VA_STATUS_ERROR_INVALID_BUFFER;
108 
109    buf->data = REALLOC(buf->data, buf->size * buf->num_elements,
110                        buf->size * num_elements);
111    buf->num_elements = num_elements;
112 
113    if (!buf->data)
114       return VA_STATUS_ERROR_ALLOCATION_FAILED;
115 
116    return VA_STATUS_SUCCESS;
117 }
118 
119 VAStatus
vlVaMapBuffer(VADriverContextP ctx,VABufferID buf_id,void ** pbuff)120 vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
121 {
122    return vlVaMapBuffer2(ctx, buf_id, pbuff, VA_MAPBUFFER_FLAG_DEFAULT);
123 }
124 
vlVaMapBuffer2(VADriverContextP ctx,VABufferID buf_id,void ** pbuff,uint32_t flags)125 VAStatus vlVaMapBuffer2(VADriverContextP ctx, VABufferID buf_id,
126                         void **pbuff, uint32_t flags)
127 {
128    vlVaDriver *drv;
129    vlVaBuffer *buf;
130 
131    if (!ctx)
132       return VA_STATUS_ERROR_INVALID_CONTEXT;
133 
134    drv = VL_VA_DRIVER(ctx);
135    if (!drv)
136       return VA_STATUS_ERROR_INVALID_CONTEXT;
137 
138    if (!pbuff)
139       return VA_STATUS_ERROR_INVALID_PARAMETER;
140 
141    mtx_lock(&drv->mutex);
142    buf = handle_table_get(drv->htab, buf_id);
143    if (!buf || buf->export_refcount > 0) {
144       mtx_unlock(&drv->mutex);
145       return VA_STATUS_ERROR_INVALID_BUFFER;
146    }
147 
148    if (buf->type == VAEncCodedBufferType)
149       vlVaGetBufferFeedback(buf);
150 
151    if (buf->derived_surface.resource) {
152       struct pipe_resource *resource;
153       struct pipe_box box;
154       unsigned usage = 0;
155       void *(*map_func)(struct pipe_context *,
156              struct pipe_resource *resource,
157              unsigned level,
158              unsigned usage,  /* a combination of PIPE_MAP_x */
159              const struct pipe_box *,
160              struct pipe_transfer **out_transfer);
161 
162       memset(&box, 0, sizeof(box));
163       resource = buf->derived_surface.resource;
164       box.width = resource->width0;
165       box.height = resource->height0;
166       box.depth = resource->depth0;
167 
168       if (resource->target == PIPE_BUFFER)
169          map_func = drv->pipe->buffer_map;
170       else
171          map_func = drv->pipe->texture_map;
172 
173       if (flags == VA_MAPBUFFER_FLAG_DEFAULT) {
174          /* For VAImageBufferType, use PIPE_MAP_WRITE for now,
175           * PIPE_MAP_READ_WRITE degradate perf with two copies when map/unmap. */
176          if (buf->type == VAEncCodedBufferType)
177             usage = PIPE_MAP_READ;
178          else
179             usage = PIPE_MAP_WRITE;
180 
181          /* Map decoder and postproc surfaces also for reading. */
182          if (buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM ||
183              buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING)
184             usage |= PIPE_MAP_READ;
185       }
186 
187       if (flags & VA_MAPBUFFER_FLAG_READ)
188          usage |= PIPE_MAP_READ;
189       if (flags & VA_MAPBUFFER_FLAG_WRITE)
190          usage |= PIPE_MAP_WRITE;
191 
192       assert(usage);
193 
194       *pbuff = map_func(drv->pipe, resource, 0, usage,
195                         &box, &buf->derived_surface.transfer);
196       mtx_unlock(&drv->mutex);
197 
198       if (!buf->derived_surface.transfer || !*pbuff)
199          return VA_STATUS_ERROR_INVALID_BUFFER;
200 
201       if (buf->type == VAEncCodedBufferType) {
202          VACodedBufferSegment* curr_buf_ptr = (VACodedBufferSegment*) buf->data;
203 
204          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_ENCODE_RESULT) &&
205              (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED)) {
206             curr_buf_ptr->status = VA_CODED_BUF_STATUS_BAD_BITSTREAM;
207             return VA_STATUS_ERROR_OPERATION_FAILED;
208          }
209 
210          curr_buf_ptr->status = (buf->extended_metadata.average_frame_qp & VA_CODED_BUF_STATUS_PICTURE_AVE_QP_MASK);
211          if (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_MAX_FRAME_SIZE_OVERFLOW)
212             curr_buf_ptr->status |= VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW;
213 
214          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_CODEC_UNIT_LOCATION) == 0) {
215             curr_buf_ptr->buf = *pbuff;
216             curr_buf_ptr->size = buf->coded_size;
217             *pbuff = buf->data;
218          } else {
219             uint8_t* compressed_bitstream_data = *pbuff;
220             *pbuff = buf->data;
221 
222             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count - 1; i++) {
223                if (!curr_buf_ptr->next)
224                   curr_buf_ptr->next = CALLOC(1, sizeof(VACodedBufferSegment));
225                if (!curr_buf_ptr->next)
226                   return VA_STATUS_ERROR_ALLOCATION_FAILED;
227                curr_buf_ptr = curr_buf_ptr->next;
228             }
229             if (curr_buf_ptr->next) {
230                VACodedBufferSegment *node = curr_buf_ptr->next;
231                while (node) {
232                   VACodedBufferSegment *next = node->next;
233                   FREE(node);
234                   node = next;
235                }
236             }
237             curr_buf_ptr->next = NULL;
238 
239             curr_buf_ptr = buf->data;
240             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count; i++) {
241                curr_buf_ptr->size = buf->extended_metadata.codec_unit_metadata[i].size;
242                curr_buf_ptr->buf = compressed_bitstream_data + buf->extended_metadata.codec_unit_metadata[i].offset;
243                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_MAX_SLICE_SIZE_OVERFLOW)
244                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
245                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_SINGLE_NALU)
246                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SINGLE_NALU;
247 
248                curr_buf_ptr = curr_buf_ptr->next;
249             }
250          }
251       }
252    } else {
253       mtx_unlock(&drv->mutex);
254       *pbuff = buf->data;
255    }
256 
257    return VA_STATUS_SUCCESS;
258 }
259 
260 VAStatus
vlVaUnmapBuffer(VADriverContextP ctx,VABufferID buf_id)261 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
262 {
263    vlVaDriver *drv;
264    vlVaBuffer *buf;
265    struct pipe_resource *resource;
266 
267    if (!ctx)
268       return VA_STATUS_ERROR_INVALID_CONTEXT;
269 
270    drv = VL_VA_DRIVER(ctx);
271    if (!drv)
272       return VA_STATUS_ERROR_INVALID_CONTEXT;
273 
274    mtx_lock(&drv->mutex);
275    buf = handle_table_get(drv->htab, buf_id);
276    if (!buf || buf->export_refcount > 0) {
277       mtx_unlock(&drv->mutex);
278       return VA_STATUS_ERROR_INVALID_BUFFER;
279    }
280 
281    resource = buf->derived_surface.resource;
282    if (resource) {
283       void (*unmap_func)(struct pipe_context *pipe,
284                          struct pipe_transfer *transfer);
285 
286       if (!buf->derived_surface.transfer) {
287          mtx_unlock(&drv->mutex);
288          return VA_STATUS_ERROR_INVALID_BUFFER;
289       }
290 
291       if (resource->target == PIPE_BUFFER)
292          unmap_func = pipe_buffer_unmap;
293       else
294          unmap_func = pipe_texture_unmap;
295 
296       unmap_func(drv->pipe, buf->derived_surface.transfer);
297       buf->derived_surface.transfer = NULL;
298 
299       if (buf->type == VAImageBufferType)
300          drv->pipe->flush(drv->pipe, NULL, 0);
301    }
302    mtx_unlock(&drv->mutex);
303 
304    return VA_STATUS_SUCCESS;
305 }
306 
307 VAStatus
vlVaDestroyBuffer(VADriverContextP ctx,VABufferID buf_id)308 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
309 {
310    vlVaDriver *drv;
311    vlVaBuffer *buf;
312 
313    if (!ctx)
314       return VA_STATUS_ERROR_INVALID_CONTEXT;
315 
316    drv = VL_VA_DRIVER(ctx);
317    mtx_lock(&drv->mutex);
318    buf = handle_table_get(drv->htab, buf_id);
319    if (!buf) {
320       mtx_unlock(&drv->mutex);
321       return VA_STATUS_ERROR_INVALID_BUFFER;
322    }
323 
324    if (buf->derived_surface.resource) {
325       pipe_resource_reference(&buf->derived_surface.resource, NULL);
326 
327       if (buf->derived_image_buffer)
328          buf->derived_image_buffer->destroy(buf->derived_image_buffer);
329    }
330 
331    if (buf->type == VAEncCodedBufferType) {
332       VACodedBufferSegment* node = buf->data;
333       while (node) {
334          VACodedBufferSegment* next = (VACodedBufferSegment*) node->next;
335          FREE(node);
336          node = next;
337       }
338    } else {
339       FREE(buf->data);
340    }
341 
342    if (buf->ctx) {
343       assert(_mesa_set_search(buf->ctx->buffers, buf));
344       _mesa_set_remove_key(buf->ctx->buffers, buf);
345       vlVaGetBufferFeedback(buf);
346       if (buf->fence && buf->ctx->decoder && buf->ctx->decoder->destroy_fence)
347          buf->ctx->decoder->destroy_fence(buf->ctx->decoder, buf->fence);
348    }
349 
350    if (buf->coded_surf)
351       buf->coded_surf->coded_buf = NULL;
352 
353    FREE(buf);
354    handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id);
355    mtx_unlock(&drv->mutex);
356 
357    return VA_STATUS_SUCCESS;
358 }
359 
360 VAStatus
vlVaBufferInfo(VADriverContextP ctx,VABufferID buf_id,VABufferType * type,unsigned int * size,unsigned int * num_elements)361 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type,
362                unsigned int *size, unsigned int *num_elements)
363 {
364    vlVaDriver *drv;
365    vlVaBuffer *buf;
366 
367    if (!ctx)
368       return VA_STATUS_ERROR_INVALID_CONTEXT;
369 
370    drv = VL_VA_DRIVER(ctx);
371    mtx_lock(&drv->mutex);
372    buf = handle_table_get(drv->htab, buf_id);
373    mtx_unlock(&drv->mutex);
374    if (!buf)
375       return VA_STATUS_ERROR_INVALID_BUFFER;
376 
377    *type = buf->type;
378    *size = buf->size;
379    *num_elements = buf->num_elements;
380 
381    return VA_STATUS_SUCCESS;
382 }
383 
384 VAStatus
vlVaAcquireBufferHandle(VADriverContextP ctx,VABufferID buf_id,VABufferInfo * out_buf_info)385 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
386                         VABufferInfo *out_buf_info)
387 {
388    vlVaDriver *drv;
389    uint32_t i;
390    uint32_t mem_type;
391    vlVaBuffer *buf ;
392    struct pipe_screen *screen;
393 
394    /* List of supported memory types, in preferred order. */
395    static const uint32_t mem_types[] = {
396 #ifdef _WIN32
397       VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE,
398       VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE,
399 #else
400       VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
401 #endif
402       0
403    };
404 
405    if (!ctx)
406       return VA_STATUS_ERROR_INVALID_CONTEXT;
407 
408    drv = VL_VA_DRIVER(ctx);
409    screen = VL_VA_PSCREEN(ctx);
410    mtx_lock(&drv->mutex);
411    buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
412    mtx_unlock(&drv->mutex);
413 
414    if (!buf)
415       return VA_STATUS_ERROR_INVALID_BUFFER;
416 
417    /* Only VA surface|image like buffers are supported for now .*/
418    if (buf->type != VAImageBufferType)
419       return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
420 
421    if (!out_buf_info)
422       return VA_STATUS_ERROR_INVALID_PARAMETER;
423 
424    if (!out_buf_info->mem_type)
425       mem_type = mem_types[0];
426    else {
427       mem_type = 0;
428       for (i = 0; mem_types[i] != 0; i++) {
429          if (out_buf_info->mem_type & mem_types[i]) {
430             mem_type = out_buf_info->mem_type;
431             break;
432          }
433       }
434       if (!mem_type)
435          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
436    }
437 
438    if (!buf->derived_surface.resource)
439       return VA_STATUS_ERROR_INVALID_BUFFER;
440 
441    if (buf->export_refcount > 0) {
442       if (buf->export_state.mem_type != mem_type)
443          return VA_STATUS_ERROR_INVALID_PARAMETER;
444    } else {
445       VABufferInfo * const buf_info = &buf->export_state;
446 
447       switch (mem_type) {
448 #ifdef _WIN32
449       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
450       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
451 #else
452       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
453 #endif
454       {
455          struct winsys_handle whandle;
456 
457          mtx_lock(&drv->mutex);
458          drv->pipe->flush(drv->pipe, NULL, 0);
459 
460          memset(&whandle, 0, sizeof(whandle));
461          whandle.type = WINSYS_HANDLE_TYPE_FD;
462 
463 #ifdef _WIN32
464          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
465             whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
466 #endif
467          if (!screen->resource_get_handle(screen, drv->pipe,
468                                           buf->derived_surface.resource,
469                                           &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) {
470             mtx_unlock(&drv->mutex);
471             return VA_STATUS_ERROR_INVALID_BUFFER;
472          }
473 
474          mtx_unlock(&drv->mutex);
475 
476          buf_info->handle = (intptr_t)whandle.handle;
477 
478 #ifdef _WIN32
479          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
480             buf_info->handle = (intptr_t)whandle.com_obj;
481 #endif
482          break;
483       }
484       default:
485          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
486       }
487 
488       buf_info->type = buf->type;
489       buf_info->mem_type = mem_type;
490       buf_info->mem_size = buf->num_elements * buf->size;
491    }
492 
493    buf->export_refcount++;
494 
495    *out_buf_info = buf->export_state;
496 
497    return VA_STATUS_SUCCESS;
498 }
499 
500 VAStatus
vlVaReleaseBufferHandle(VADriverContextP ctx,VABufferID buf_id)501 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
502 {
503    vlVaDriver *drv;
504    vlVaBuffer *buf;
505 
506    if (!ctx)
507       return VA_STATUS_ERROR_INVALID_CONTEXT;
508 
509    drv = VL_VA_DRIVER(ctx);
510    mtx_lock(&drv->mutex);
511    buf = handle_table_get(drv->htab, buf_id);
512    mtx_unlock(&drv->mutex);
513 
514    if (!buf)
515       return VA_STATUS_ERROR_INVALID_BUFFER;
516 
517    if (buf->export_refcount == 0)
518       return VA_STATUS_ERROR_INVALID_BUFFER;
519 
520    if (--buf->export_refcount == 0) {
521       VABufferInfo * const buf_info = &buf->export_state;
522 
523       switch (buf_info->mem_type) {
524 #ifdef _WIN32
525       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
526          // Do nothing for this case.
527          break;
528       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
529          CloseHandle((HANDLE) buf_info->handle);
530       break;
531 #else
532       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
533          close((intptr_t)buf_info->handle);
534          break;
535 #endif
536       default:
537          return VA_STATUS_ERROR_INVALID_BUFFER;
538       }
539 
540       buf_info->mem_type = 0;
541    }
542 
543    return VA_STATUS_SUCCESS;
544 }
545 
546 #if VA_CHECK_VERSION(1, 15, 0)
547 VAStatus
vlVaSyncBuffer(VADriverContextP ctx,VABufferID buf_id,uint64_t timeout_ns)548 vlVaSyncBuffer(VADriverContextP ctx, VABufferID buf_id, uint64_t timeout_ns)
549 {
550    vlVaDriver *drv;
551    vlVaContext *context;
552    vlVaBuffer *buf;
553 
554    if (!ctx)
555       return VA_STATUS_ERROR_INVALID_CONTEXT;
556 
557    drv = VL_VA_DRIVER(ctx);
558    if (!drv)
559       return VA_STATUS_ERROR_INVALID_CONTEXT;
560 
561    mtx_lock(&drv->mutex);
562    buf = handle_table_get(drv->htab, buf_id);
563 
564    if (!buf) {
565       mtx_unlock(&drv->mutex);
566       return VA_STATUS_ERROR_INVALID_BUFFER;
567    }
568 
569    if (!buf->fence) {
570       /* No outstanding operation: nothing to do. */
571       mtx_unlock(&drv->mutex);
572       return VA_STATUS_SUCCESS;
573    }
574 
575    context = buf->ctx;
576    if (!context) {
577       mtx_unlock(&drv->mutex);
578       return VA_STATUS_ERROR_INVALID_CONTEXT;
579    }
580 
581    if (!context->decoder) {
582       mtx_unlock(&drv->mutex);
583       return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
584    }
585 
586    int ret = context->decoder->fence_wait(context->decoder, buf->fence, timeout_ns);
587    mtx_unlock(&drv->mutex);
588    return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT;
589 }
590 #endif
591 
vlVaGetBufferFeedback(vlVaBuffer * buf)592 void vlVaGetBufferFeedback(vlVaBuffer *buf)
593 {
594    if (!buf->ctx || !buf->ctx->decoder || !buf->feedback)
595       return;
596 
597    buf->ctx->decoder->get_feedback(buf->ctx->decoder, buf->feedback,
598                                    &buf->coded_size, &buf->extended_metadata);
599    buf->feedback = NULL;
600 }
601