xref: /aosp_15_r20/external/mesa3d/src/gallium/frontends/va/buffer.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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 "vl/vl_winsys.h"
35 
36 #include "va_private.h"
37 
38 #ifdef _WIN32
39 #include <va/va_win32.h>
40 #endif
41 
42 #ifndef VA_MAPBUFFER_FLAG_DEFAULT
43 #define VA_MAPBUFFER_FLAG_DEFAULT 0
44 #define VA_MAPBUFFER_FLAG_READ    1
45 #define VA_MAPBUFFER_FLAG_WRITE   2
46 #endif
47 
48 VAStatus
vlVaCreateBuffer(VADriverContextP ctx,VAContextID context,VABufferType type,unsigned int size,unsigned int num_elements,void * data,VABufferID * buf_id)49 vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type,
50                  unsigned int size, unsigned int num_elements, void *data,
51                  VABufferID *buf_id)
52 {
53    vlVaDriver *drv;
54    vlVaBuffer *buf;
55 
56    if (!ctx)
57       return VA_STATUS_ERROR_INVALID_CONTEXT;
58 
59    buf = CALLOC(1, sizeof(vlVaBuffer));
60    if (!buf)
61       return VA_STATUS_ERROR_ALLOCATION_FAILED;
62 
63    buf->type = type;
64    buf->size = size;
65    buf->num_elements = num_elements;
66 
67    if (buf->type == VAEncCodedBufferType)
68       buf->data = CALLOC(1, sizeof(VACodedBufferSegment));
69    else
70       buf->data = MALLOC(size * num_elements);
71 
72    if (!buf->data) {
73       FREE(buf);
74       return VA_STATUS_ERROR_ALLOCATION_FAILED;
75    }
76 
77    if (data)
78       memcpy(buf->data, data, size * num_elements);
79 
80    drv = VL_VA_DRIVER(ctx);
81    mtx_lock(&drv->mutex);
82    *buf_id = handle_table_add(drv->htab, buf);
83    mtx_unlock(&drv->mutex);
84 
85    return VA_STATUS_SUCCESS;
86 }
87 
88 VAStatus
vlVaBufferSetNumElements(VADriverContextP ctx,VABufferID buf_id,unsigned int num_elements)89 vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id,
90                          unsigned int num_elements)
91 {
92    vlVaDriver *drv;
93    vlVaBuffer *buf;
94 
95    if (!ctx)
96       return VA_STATUS_ERROR_INVALID_CONTEXT;
97 
98    drv = VL_VA_DRIVER(ctx);
99    mtx_lock(&drv->mutex);
100    buf = handle_table_get(drv->htab, buf_id);
101    mtx_unlock(&drv->mutex);
102    if (!buf)
103       return VA_STATUS_ERROR_INVALID_BUFFER;
104 
105    if (buf->derived_surface.resource)
106       return VA_STATUS_ERROR_INVALID_BUFFER;
107 
108    buf->data = REALLOC(buf->data, buf->size * buf->num_elements,
109                        buf->size * num_elements);
110    buf->num_elements = num_elements;
111 
112    if (!buf->data)
113       return VA_STATUS_ERROR_ALLOCATION_FAILED;
114 
115    return VA_STATUS_SUCCESS;
116 }
117 
118 VAStatus
vlVaMapBuffer(VADriverContextP ctx,VABufferID buf_id,void ** pbuff)119 vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff)
120 {
121    return vlVaMapBuffer2(ctx, buf_id, pbuff, VA_MAPBUFFER_FLAG_DEFAULT);
122 }
123 
vlVaMapBuffer2(VADriverContextP ctx,VABufferID buf_id,void ** pbuff,uint32_t flags)124 VAStatus vlVaMapBuffer2(VADriverContextP ctx, VABufferID buf_id,
125                         void **pbuff, uint32_t flags)
126 {
127    vlVaDriver *drv;
128    vlVaBuffer *buf;
129 
130    if (!ctx)
131       return VA_STATUS_ERROR_INVALID_CONTEXT;
132 
133    drv = VL_VA_DRIVER(ctx);
134    if (!drv)
135       return VA_STATUS_ERROR_INVALID_CONTEXT;
136 
137    if (!pbuff)
138       return VA_STATUS_ERROR_INVALID_PARAMETER;
139 
140    mtx_lock(&drv->mutex);
141    buf = handle_table_get(drv->htab, buf_id);
142    if (!buf || buf->export_refcount > 0) {
143       mtx_unlock(&drv->mutex);
144       return VA_STATUS_ERROR_INVALID_BUFFER;
145    }
146 
147    if (buf->derived_surface.resource) {
148       struct pipe_resource *resource;
149       struct pipe_box box;
150       unsigned usage = 0;
151       void *(*map_func)(struct pipe_context *,
152              struct pipe_resource *resource,
153              unsigned level,
154              unsigned usage,  /* a combination of PIPE_MAP_x */
155              const struct pipe_box *,
156              struct pipe_transfer **out_transfer);
157 
158       memset(&box, 0, sizeof(box));
159       resource = buf->derived_surface.resource;
160       box.width = resource->width0;
161       box.height = resource->height0;
162       box.depth = resource->depth0;
163 
164       if (resource->target == PIPE_BUFFER)
165          map_func = drv->pipe->buffer_map;
166       else
167          map_func = drv->pipe->texture_map;
168 
169       if (flags == VA_MAPBUFFER_FLAG_DEFAULT) {
170          /* For VAImageBufferType, use PIPE_MAP_WRITE for now,
171           * PIPE_MAP_READ_WRITE degradate perf with two copies when map/unmap. */
172          if (buf->type == VAEncCodedBufferType)
173             usage = PIPE_MAP_READ;
174          else
175             usage = PIPE_MAP_WRITE;
176 
177          /* Map decoder and postproc surfaces also for reading. */
178          if (buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM ||
179              buf->derived_surface.entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING)
180             usage |= PIPE_MAP_READ;
181       }
182 
183       if (flags & VA_MAPBUFFER_FLAG_READ)
184          usage |= PIPE_MAP_READ;
185       if (flags & VA_MAPBUFFER_FLAG_WRITE)
186          usage |= PIPE_MAP_WRITE;
187 
188       assert(usage);
189 
190       *pbuff = map_func(drv->pipe, resource, 0, usage,
191                         &box, &buf->derived_surface.transfer);
192       mtx_unlock(&drv->mutex);
193 
194       if (!buf->derived_surface.transfer || !*pbuff)
195          return VA_STATUS_ERROR_INVALID_BUFFER;
196 
197       if (buf->type == VAEncCodedBufferType) {
198          VACodedBufferSegment* curr_buf_ptr = (VACodedBufferSegment*) buf->data;
199 
200          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_ENCODE_RESULT) &&
201              (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_FAILED)) {
202             curr_buf_ptr->status = VA_CODED_BUF_STATUS_BAD_BITSTREAM;
203             return VA_STATUS_ERROR_OPERATION_FAILED;
204          }
205 
206          curr_buf_ptr->status = (buf->extended_metadata.average_frame_qp & VA_CODED_BUF_STATUS_PICTURE_AVE_QP_MASK);
207          if (buf->extended_metadata.encode_result & PIPE_VIDEO_FEEDBACK_METADATA_ENCODE_FLAG_MAX_FRAME_SIZE_OVERFLOW)
208             curr_buf_ptr->status |= VA_CODED_BUF_STATUS_FRAME_SIZE_OVERFLOW;
209 
210          if ((buf->extended_metadata.present_metadata & PIPE_VIDEO_FEEDBACK_METADATA_TYPE_CODEC_UNIT_LOCATION) == 0) {
211             curr_buf_ptr->buf = *pbuff;
212             curr_buf_ptr->size = buf->coded_size;
213             *pbuff = buf->data;
214          } else {
215             uint8_t* compressed_bitstream_data = *pbuff;
216             *pbuff = buf->data;
217 
218             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count - 1; i++) {
219                if (!curr_buf_ptr->next)
220                   curr_buf_ptr->next = CALLOC(1, sizeof(VACodedBufferSegment));
221                if (!curr_buf_ptr->next)
222                   return VA_STATUS_ERROR_ALLOCATION_FAILED;
223                curr_buf_ptr = curr_buf_ptr->next;
224             }
225             if (curr_buf_ptr->next) {
226                VACodedBufferSegment *node = curr_buf_ptr->next;
227                while (node) {
228                   VACodedBufferSegment *next = node->next;
229                   FREE(node);
230                   node = next;
231                }
232             }
233             curr_buf_ptr->next = NULL;
234 
235             curr_buf_ptr = buf->data;
236             for (size_t i = 0; i < buf->extended_metadata.codec_unit_metadata_count; i++) {
237                curr_buf_ptr->size = buf->extended_metadata.codec_unit_metadata[i].size;
238                curr_buf_ptr->buf = compressed_bitstream_data + buf->extended_metadata.codec_unit_metadata[i].offset;
239                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_MAX_SLICE_SIZE_OVERFLOW)
240                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK;
241                if (buf->extended_metadata.codec_unit_metadata[i].flags & PIPE_VIDEO_CODEC_UNIT_LOCATION_FLAG_SINGLE_NALU)
242                   curr_buf_ptr->status |= VA_CODED_BUF_STATUS_SINGLE_NALU;
243 
244                curr_buf_ptr = curr_buf_ptr->next;
245             }
246          }
247       }
248    } else {
249       mtx_unlock(&drv->mutex);
250       *pbuff = buf->data;
251    }
252 
253    return VA_STATUS_SUCCESS;
254 }
255 
256 VAStatus
vlVaUnmapBuffer(VADriverContextP ctx,VABufferID buf_id)257 vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id)
258 {
259    vlVaDriver *drv;
260    vlVaBuffer *buf;
261    struct pipe_resource *resource;
262 
263    if (!ctx)
264       return VA_STATUS_ERROR_INVALID_CONTEXT;
265 
266    drv = VL_VA_DRIVER(ctx);
267    if (!drv)
268       return VA_STATUS_ERROR_INVALID_CONTEXT;
269 
270    mtx_lock(&drv->mutex);
271    buf = handle_table_get(drv->htab, buf_id);
272    if (!buf || buf->export_refcount > 0) {
273       mtx_unlock(&drv->mutex);
274       return VA_STATUS_ERROR_INVALID_BUFFER;
275    }
276 
277    resource = buf->derived_surface.resource;
278    if (resource) {
279       void (*unmap_func)(struct pipe_context *pipe,
280                          struct pipe_transfer *transfer);
281 
282       if (!buf->derived_surface.transfer) {
283          mtx_unlock(&drv->mutex);
284          return VA_STATUS_ERROR_INVALID_BUFFER;
285       }
286 
287       if (resource->target == PIPE_BUFFER)
288          unmap_func = pipe_buffer_unmap;
289       else
290          unmap_func = pipe_texture_unmap;
291 
292       unmap_func(drv->pipe, buf->derived_surface.transfer);
293       buf->derived_surface.transfer = NULL;
294 
295       if (buf->type == VAImageBufferType)
296          drv->pipe->flush(drv->pipe, NULL, 0);
297    }
298    mtx_unlock(&drv->mutex);
299 
300    return VA_STATUS_SUCCESS;
301 }
302 
303 VAStatus
vlVaDestroyBuffer(VADriverContextP ctx,VABufferID buf_id)304 vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id)
305 {
306    vlVaDriver *drv;
307    vlVaBuffer *buf;
308 
309    if (!ctx)
310       return VA_STATUS_ERROR_INVALID_CONTEXT;
311 
312    drv = VL_VA_DRIVER(ctx);
313    mtx_lock(&drv->mutex);
314    buf = handle_table_get(drv->htab, buf_id);
315    if (!buf) {
316       mtx_unlock(&drv->mutex);
317       return VA_STATUS_ERROR_INVALID_BUFFER;
318    }
319 
320    if (buf->derived_surface.resource) {
321       pipe_resource_reference(&buf->derived_surface.resource, NULL);
322 
323       if (buf->derived_image_buffer)
324          buf->derived_image_buffer->destroy(buf->derived_image_buffer);
325    }
326 
327    if (buf->type == VAEncCodedBufferType) {
328       VACodedBufferSegment* node = buf->data;
329       while (node) {
330          VACodedBufferSegment* next = (VACodedBufferSegment*) node->next;
331          FREE(node);
332          node = next;
333       }
334    } else {
335       FREE(buf->data);
336    }
337 
338    FREE(buf);
339    handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id);
340    mtx_unlock(&drv->mutex);
341 
342    return VA_STATUS_SUCCESS;
343 }
344 
345 VAStatus
vlVaBufferInfo(VADriverContextP ctx,VABufferID buf_id,VABufferType * type,unsigned int * size,unsigned int * num_elements)346 vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type,
347                unsigned int *size, unsigned int *num_elements)
348 {
349    vlVaDriver *drv;
350    vlVaBuffer *buf;
351 
352    if (!ctx)
353       return VA_STATUS_ERROR_INVALID_CONTEXT;
354 
355    drv = VL_VA_DRIVER(ctx);
356    mtx_lock(&drv->mutex);
357    buf = handle_table_get(drv->htab, buf_id);
358    mtx_unlock(&drv->mutex);
359    if (!buf)
360       return VA_STATUS_ERROR_INVALID_BUFFER;
361 
362    *type = buf->type;
363    *size = buf->size;
364    *num_elements = buf->num_elements;
365 
366    return VA_STATUS_SUCCESS;
367 }
368 
369 VAStatus
vlVaAcquireBufferHandle(VADriverContextP ctx,VABufferID buf_id,VABufferInfo * out_buf_info)370 vlVaAcquireBufferHandle(VADriverContextP ctx, VABufferID buf_id,
371                         VABufferInfo *out_buf_info)
372 {
373    vlVaDriver *drv;
374    uint32_t i;
375    uint32_t mem_type;
376    vlVaBuffer *buf ;
377    struct pipe_screen *screen;
378 
379    /* List of supported memory types, in preferred order. */
380    static const uint32_t mem_types[] = {
381 #ifdef _WIN32
382       VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE,
383       VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE,
384 #else
385       VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME,
386 #endif
387       0
388    };
389 
390    if (!ctx)
391       return VA_STATUS_ERROR_INVALID_CONTEXT;
392 
393    drv = VL_VA_DRIVER(ctx);
394    screen = VL_VA_PSCREEN(ctx);
395    mtx_lock(&drv->mutex);
396    buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id);
397    mtx_unlock(&drv->mutex);
398 
399    if (!buf)
400       return VA_STATUS_ERROR_INVALID_BUFFER;
401 
402    /* Only VA surface|image like buffers are supported for now .*/
403    if (buf->type != VAImageBufferType)
404       return VA_STATUS_ERROR_UNSUPPORTED_BUFFERTYPE;
405 
406    if (!out_buf_info)
407       return VA_STATUS_ERROR_INVALID_PARAMETER;
408 
409    if (!out_buf_info->mem_type)
410       mem_type = mem_types[0];
411    else {
412       mem_type = 0;
413       for (i = 0; mem_types[i] != 0; i++) {
414          if (out_buf_info->mem_type & mem_types[i]) {
415             mem_type = out_buf_info->mem_type;
416             break;
417          }
418       }
419       if (!mem_type)
420          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
421    }
422 
423    if (!buf->derived_surface.resource)
424       return VA_STATUS_ERROR_INVALID_BUFFER;
425 
426    if (buf->export_refcount > 0) {
427       if (buf->export_state.mem_type != mem_type)
428          return VA_STATUS_ERROR_INVALID_PARAMETER;
429    } else {
430       VABufferInfo * const buf_info = &buf->export_state;
431 
432       switch (mem_type) {
433 #ifdef _WIN32
434       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
435       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
436 #else
437       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
438 #endif
439       {
440          struct winsys_handle whandle;
441 
442          mtx_lock(&drv->mutex);
443          drv->pipe->flush(drv->pipe, NULL, 0);
444 
445          memset(&whandle, 0, sizeof(whandle));
446          whandle.type = WINSYS_HANDLE_TYPE_FD;
447 
448 #ifdef _WIN32
449          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
450             whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
451 #endif
452          if (!screen->resource_get_handle(screen, drv->pipe,
453                                           buf->derived_surface.resource,
454                                           &whandle, PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE)) {
455             mtx_unlock(&drv->mutex);
456             return VA_STATUS_ERROR_INVALID_BUFFER;
457          }
458 
459          mtx_unlock(&drv->mutex);
460 
461          buf_info->handle = (intptr_t)whandle.handle;
462 
463 #ifdef _WIN32
464          if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
465             buf_info->handle = (intptr_t)whandle.com_obj;
466 #endif
467          break;
468       }
469       default:
470          return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
471       }
472 
473       buf_info->type = buf->type;
474       buf_info->mem_type = mem_type;
475       buf_info->mem_size = buf->num_elements * buf->size;
476    }
477 
478    buf->export_refcount++;
479 
480    *out_buf_info = buf->export_state;
481 
482    return VA_STATUS_SUCCESS;
483 }
484 
485 VAStatus
vlVaReleaseBufferHandle(VADriverContextP ctx,VABufferID buf_id)486 vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id)
487 {
488    vlVaDriver *drv;
489    vlVaBuffer *buf;
490 
491    if (!ctx)
492       return VA_STATUS_ERROR_INVALID_CONTEXT;
493 
494    drv = VL_VA_DRIVER(ctx);
495    mtx_lock(&drv->mutex);
496    buf = handle_table_get(drv->htab, buf_id);
497    mtx_unlock(&drv->mutex);
498 
499    if (!buf)
500       return VA_STATUS_ERROR_INVALID_BUFFER;
501 
502    if (buf->export_refcount == 0)
503       return VA_STATUS_ERROR_INVALID_BUFFER;
504 
505    if (--buf->export_refcount == 0) {
506       VABufferInfo * const buf_info = &buf->export_state;
507 
508       switch (buf_info->mem_type) {
509 #ifdef _WIN32
510       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
511          // Do nothing for this case.
512          break;
513       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
514          CloseHandle((HANDLE) buf_info->handle);
515       break;
516 #else
517       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
518          close((intptr_t)buf_info->handle);
519          break;
520 #endif
521       default:
522          return VA_STATUS_ERROR_INVALID_BUFFER;
523       }
524 
525       buf_info->mem_type = 0;
526    }
527 
528    return VA_STATUS_SUCCESS;
529 }
530 
531 #if VA_CHECK_VERSION(1, 15, 0)
532 VAStatus
vlVaSyncBuffer(VADriverContextP ctx,VABufferID buf_id,uint64_t timeout_ns)533 vlVaSyncBuffer(VADriverContextP ctx, VABufferID buf_id, uint64_t timeout_ns)
534 {
535    vlVaDriver *drv;
536    vlVaContext *context;
537    vlVaBuffer *buf;
538 
539    if (!ctx)
540       return VA_STATUS_ERROR_INVALID_CONTEXT;
541 
542    drv = VL_VA_DRIVER(ctx);
543    if (!drv)
544       return VA_STATUS_ERROR_INVALID_CONTEXT;
545 
546    /* Some apps like ffmpeg check for vaSyncBuffer to be present
547       to do async enqueuing of multiple vaEndPicture encode calls
548       before calling vaSyncBuffer with a pre-defined latency
549       If vaSyncBuffer is not implemented, they fallback to the
550       usual synchronous pairs of { vaEndPicture + vaSyncSurface }
551 
552       As this might require the driver to support multiple
553       operations and/or store multiple feedback values before sync
554       fallback to backward compatible behaviour unless driver
555       explicitly supports PIPE_VIDEO_CAP_ENC_SUPPORTS_ASYNC_OPERATION
556    */
557    if (!drv->pipe->screen->get_video_param(drv->pipe->screen,
558                               PIPE_VIDEO_PROFILE_UNKNOWN,
559                               PIPE_VIDEO_ENTRYPOINT_ENCODE,
560                               PIPE_VIDEO_CAP_ENC_SUPPORTS_ASYNC_OPERATION))
561       return VA_STATUS_ERROR_UNIMPLEMENTED;
562 
563    mtx_lock(&drv->mutex);
564    buf = handle_table_get(drv->htab, buf_id);
565 
566    if (!buf) {
567       mtx_unlock(&drv->mutex);
568       return VA_STATUS_ERROR_INVALID_BUFFER;
569    }
570 
571    if (!buf->feedback) {
572       /* No outstanding operation: nothing to do. */
573       mtx_unlock(&drv->mutex);
574       return VA_STATUS_SUCCESS;
575    }
576 
577    context = handle_table_get(drv->htab, buf->ctx);
578    if (!context) {
579       mtx_unlock(&drv->mutex);
580       return VA_STATUS_ERROR_INVALID_CONTEXT;
581    }
582 
583    vlVaSurface* surf = handle_table_get(drv->htab, buf->associated_encode_input_surf);
584 
585    if ((buf->feedback) && (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)) {
586       if (surf && context->decoder->get_feedback_fence &&
587           !context->decoder->get_feedback_fence(context->decoder, surf->fence, timeout_ns)) {
588          mtx_unlock(&drv->mutex);
589          return VA_STATUS_ERROR_TIMEDOUT;
590       }
591       context->decoder->get_feedback(context->decoder, buf->feedback, &(buf->coded_size), &(buf->extended_metadata));
592       buf->feedback = NULL;
593       /* Also mark the associated render target (encode source texture) surface as done
594          in case they call vaSyncSurface on it to avoid getting the feedback twice*/
595       if(surf)
596       {
597          surf->feedback = NULL;
598          buf->associated_encode_input_surf = VA_INVALID_ID;
599       }
600    }
601 
602    mtx_unlock(&drv->mutex);
603    return VA_STATUS_SUCCESS;
604 }
605 #endif
606