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