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 "pipe/p_video_codec.h"
31
32 #include "util/u_memory.h"
33 #include "util/u_handle_table.h"
34 #include "util/u_rect.h"
35 #include "util/u_sampler.h"
36 #include "util/u_surface.h"
37 #include "util/u_video.h"
38 #include "util/set.h"
39
40 #include "vl/vl_compositor.h"
41 #include "vl/vl_video_buffer.h"
42 #include "vl/vl_winsys.h"
43
44 #include "va_private.h"
45
46 #ifdef _WIN32
47 #include "frontend/winsys_handle.h"
48 #include <va/va_win32.h>
49 #else
50 #include "frontend/drm_driver.h"
51 #include <va/va_drmcommon.h>
52 #include "drm-uapi/drm_fourcc.h"
53 #endif
54
55 static const enum pipe_format vpp_surface_formats[] = {
56 PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM,
57 PIPE_FORMAT_B8G8R8X8_UNORM, PIPE_FORMAT_R8G8B8X8_UNORM
58 };
59
60 VAStatus
vlVaCreateSurfaces(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surfaces)61 vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format,
62 int num_surfaces, VASurfaceID *surfaces)
63 {
64 return vlVaCreateSurfaces2(ctx, format, width, height, surfaces, num_surfaces,
65 NULL, 0);
66 }
67
68 VAStatus
vlVaDestroySurfaces(VADriverContextP ctx,VASurfaceID * surface_list,int num_surfaces)69 vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces)
70 {
71 vlVaDriver *drv;
72 int i;
73
74 if (!ctx)
75 return VA_STATUS_ERROR_INVALID_CONTEXT;
76
77 drv = VL_VA_DRIVER(ctx);
78 mtx_lock(&drv->mutex);
79 for (i = 0; i < num_surfaces; ++i) {
80 vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]);
81 if (!surf) {
82 mtx_unlock(&drv->mutex);
83 return VA_STATUS_ERROR_INVALID_SURFACE;
84 }
85 if (surf->buffer)
86 surf->buffer->destroy(surf->buffer);
87 if (surf->ctx) {
88 assert(_mesa_set_search(surf->ctx->surfaces, surf));
89 _mesa_set_remove_key(surf->ctx->surfaces, surf);
90 if (surf->fence && surf->ctx->decoder && surf->ctx->decoder->destroy_fence)
91 surf->ctx->decoder->destroy_fence(surf->ctx->decoder, surf->fence);
92 }
93 util_dynarray_fini(&surf->subpics);
94 FREE(surf);
95 handle_table_remove(drv->htab, surface_list[i]);
96 }
97 mtx_unlock(&drv->mutex);
98
99 return VA_STATUS_SUCCESS;
100 }
101
102 static VAStatus
_vlVaSyncSurface(VADriverContextP ctx,VASurfaceID render_target,uint64_t timeout_ns)103 _vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target, uint64_t timeout_ns)
104 {
105 vlVaDriver *drv;
106 vlVaContext *context;
107 vlVaSurface *surf;
108
109 if (!ctx)
110 return VA_STATUS_ERROR_INVALID_CONTEXT;
111
112 drv = VL_VA_DRIVER(ctx);
113 if (!drv)
114 return VA_STATUS_ERROR_INVALID_CONTEXT;
115
116 mtx_lock(&drv->mutex);
117 surf = handle_table_get(drv->htab, render_target);
118
119 if (!surf || !surf->buffer) {
120 mtx_unlock(&drv->mutex);
121 return VA_STATUS_ERROR_INVALID_SURFACE;
122 }
123
124 /* This is checked before getting the context below as
125 * surf->ctx is only set in begin_frame
126 * and not when the surface is created
127 * Some apps try to sync/map the surface right after creation and
128 * would get VA_STATUS_ERROR_INVALID_CONTEXT
129 */
130 if ((!surf->feedback) && (!surf->fence)) {
131 // No outstanding encode/decode operation: nothing to do.
132 mtx_unlock(&drv->mutex);
133 return VA_STATUS_SUCCESS;
134 }
135
136 context = surf->ctx;
137 if (!context) {
138 mtx_unlock(&drv->mutex);
139 return VA_STATUS_ERROR_INVALID_CONTEXT;
140 }
141
142 if (!context->decoder) {
143 mtx_unlock(&drv->mutex);
144 return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
145 }
146
147 if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
148 /* If driver does not implement get_processor_fence assume no
149 * async work needed to be waited on and return success
150 */
151 int ret = (context->decoder->get_processor_fence) ? 0 : 1;
152
153 if (context->decoder->get_processor_fence)
154 ret = context->decoder->get_processor_fence(context->decoder,
155 surf->fence, timeout_ns);
156
157 mtx_unlock(&drv->mutex);
158 // Assume that the GPU has hung otherwise.
159 return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT;
160 } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
161 int ret = 0;
162
163 if (context->decoder->get_decoder_fence)
164 ret = context->decoder->get_decoder_fence(context->decoder,
165 surf->fence, timeout_ns);
166
167 mtx_unlock(&drv->mutex);
168 // Assume that the GPU has hung otherwise.
169 return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT;
170 } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
171 if (!drv->pipe->screen->get_video_param(drv->pipe->screen,
172 context->decoder->profile,
173 context->decoder->entrypoint,
174 PIPE_VIDEO_CAP_REQUIRES_FLUSH_ON_END_FRAME)) {
175 if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) {
176 int frame_diff;
177 if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt)
178 frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt;
179 else
180 frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt;
181 if ((frame_diff == 0) &&
182 (surf->force_flushed == false) &&
183 (context->desc.h264enc.frame_num_cnt % 2 != 0)) {
184 context->decoder->flush(context->decoder);
185 context->first_single_submitted = true;
186 }
187 }
188 }
189 context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size), &(surf->coded_buf->extended_metadata));
190 surf->feedback = NULL;
191 surf->coded_buf->feedback = NULL;
192 surf->coded_buf->associated_encode_input_surf = VA_INVALID_ID;
193 }
194 mtx_unlock(&drv->mutex);
195 return VA_STATUS_SUCCESS;
196 }
197
198 VAStatus
vlVaSyncSurface(VADriverContextP ctx,VASurfaceID render_target)199 vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target)
200 {
201 return _vlVaSyncSurface(ctx, render_target, VA_TIMEOUT_INFINITE);
202 }
203
204 #if VA_CHECK_VERSION(1, 15, 0)
205 VAStatus
vlVaSyncSurface2(VADriverContextP ctx,VASurfaceID surface,uint64_t timeout_ns)206 vlVaSyncSurface2(VADriverContextP ctx, VASurfaceID surface, uint64_t timeout_ns)
207 {
208 return _vlVaSyncSurface(ctx, surface, timeout_ns);
209 }
210 #endif
211
212 VAStatus
vlVaQuerySurfaceStatus(VADriverContextP ctx,VASurfaceID render_target,VASurfaceStatus * status)213 vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status)
214 {
215 vlVaDriver *drv;
216 vlVaSurface *surf;
217 vlVaContext *context;
218
219 if (!ctx)
220 return VA_STATUS_ERROR_INVALID_CONTEXT;
221
222 drv = VL_VA_DRIVER(ctx);
223 if (!drv)
224 return VA_STATUS_ERROR_INVALID_CONTEXT;
225
226 mtx_lock(&drv->mutex);
227
228 surf = handle_table_get(drv->htab, render_target);
229 if (!surf || !surf->buffer) {
230 mtx_unlock(&drv->mutex);
231 return VA_STATUS_ERROR_INVALID_SURFACE;
232 }
233
234 /* This is checked before getting the context below as
235 * surf->ctx is only set in begin_frame
236 * and not when the surface is created
237 * Some apps try to sync/map the surface right after creation and
238 * would get VA_STATUS_ERROR_INVALID_CONTEXT
239 */
240 if ((!surf->feedback) && (!surf->fence)) {
241 // No outstanding encode/decode operation: nothing to do.
242 *status = VASurfaceReady;
243 mtx_unlock(&drv->mutex);
244 return VA_STATUS_SUCCESS;
245 }
246
247 context = surf->ctx;
248 if (!context) {
249 mtx_unlock(&drv->mutex);
250 return VA_STATUS_ERROR_INVALID_CONTEXT;
251 }
252
253 if (!context->decoder) {
254 mtx_unlock(&drv->mutex);
255 return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
256 }
257
258 if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
259 if(surf->feedback == NULL)
260 *status=VASurfaceReady;
261 else
262 *status=VASurfaceRendering;
263 } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_BITSTREAM) {
264 int ret = 0;
265
266 if (context->decoder->get_decoder_fence)
267 ret = context->decoder->get_decoder_fence(context->decoder,
268 surf->fence, 0);
269
270 if (ret)
271 *status = VASurfaceReady;
272 else
273 /* An approach could be to just tell the client that this is not
274 * implemented, but this breaks other code. Compromise by at least
275 * conservatively setting the status to VASurfaceRendering if we can't
276 * query the hardware. Note that we _must_ set the status here, otherwise
277 * it comes out of the function unchanged. As we are returning
278 * VA_STATUS_SUCCESS, the client would be within his/her rights to use a
279 * potentially uninitialized/invalid status value unknowingly.
280 */
281 *status = VASurfaceRendering;
282 } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_PROCESSING) {
283 /* If driver does not implement get_processor_fence assume no
284 * async work needed to be waited on and return surface ready
285 */
286 int ret = (context->decoder->get_processor_fence) ? 0 : 1;
287
288 if (context->decoder->get_processor_fence)
289 ret = context->decoder->get_processor_fence(context->decoder,
290 surf->fence, 0);
291 if (ret)
292 *status = VASurfaceReady;
293 else
294 *status = VASurfaceRendering;
295 }
296
297 mtx_unlock(&drv->mutex);
298
299 return VA_STATUS_SUCCESS;
300 }
301
302 VAStatus
vlVaQuerySurfaceError(VADriverContextP ctx,VASurfaceID render_target,VAStatus error_status,void ** error_info)303 vlVaQuerySurfaceError(VADriverContextP ctx, VASurfaceID render_target, VAStatus error_status, void **error_info)
304 {
305 if (!ctx)
306 return VA_STATUS_ERROR_INVALID_CONTEXT;
307
308 return VA_STATUS_ERROR_UNIMPLEMENTED;
309 }
310
311 static void
upload_sampler(struct pipe_context * pipe,struct pipe_sampler_view * dst,const struct pipe_box * dst_box,const void * src,unsigned src_stride,unsigned src_x,unsigned src_y)312 upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst,
313 const struct pipe_box *dst_box, const void *src, unsigned src_stride,
314 unsigned src_x, unsigned src_y)
315 {
316 struct pipe_transfer *transfer;
317 void *map;
318
319 map = pipe->texture_map(pipe, dst->texture, 0, PIPE_MAP_WRITE,
320 dst_box, &transfer);
321 if (!map)
322 return;
323
324 util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0,
325 dst_box->width, dst_box->height,
326 src, src_stride, src_x, src_y);
327
328 pipe->texture_unmap(pipe, transfer);
329 }
330
331 static VAStatus
vlVaPutSubpictures(vlVaSurface * surf,vlVaDriver * drv,struct pipe_surface * surf_draw,struct u_rect * dirty_area,struct u_rect * src_rect,struct u_rect * dst_rect)332 vlVaPutSubpictures(vlVaSurface *surf, vlVaDriver *drv,
333 struct pipe_surface *surf_draw, struct u_rect *dirty_area,
334 struct u_rect *src_rect, struct u_rect *dst_rect)
335 {
336 vlVaSubpicture *sub;
337 int i;
338
339 if (!(surf->subpics.data || surf->subpics.size))
340 return VA_STATUS_SUCCESS;
341
342 for (i = 0; i < surf->subpics.size/sizeof(vlVaSubpicture *); i++) {
343 struct pipe_blend_state blend;
344 void *blend_state;
345 vlVaBuffer *buf;
346 struct pipe_box box;
347 struct u_rect *s, *d, sr, dr, c;
348 int sw, sh, dw, dh;
349
350 sub = ((vlVaSubpicture **)surf->subpics.data)[i];
351 if (!sub)
352 continue;
353
354 buf = handle_table_get(drv->htab, sub->image->buf);
355 if (!buf)
356 return VA_STATUS_ERROR_INVALID_IMAGE;
357
358 box.x = 0;
359 box.y = 0;
360 box.z = 0;
361 box.width = sub->dst_rect.x1 - sub->dst_rect.x0;
362 box.height = sub->dst_rect.y1 - sub->dst_rect.y0;
363 box.depth = 1;
364
365 s = &sub->src_rect;
366 d = &sub->dst_rect;
367 sw = s->x1 - s->x0;
368 sh = s->y1 - s->y0;
369 dw = d->x1 - d->x0;
370 dh = d->y1 - d->y0;
371 c.x0 = MAX2(d->x0, s->x0);
372 c.y0 = MAX2(d->y0, s->y0);
373 c.x1 = MIN2(d->x0 + dw, src_rect->x1);
374 c.y1 = MIN2(d->y0 + dh, src_rect->y1);
375 sr.x0 = s->x0 + (c.x0 - d->x0)*(sw/(float)dw);
376 sr.y0 = s->y0 + (c.y0 - d->y0)*(sh/(float)dh);
377 sr.x1 = s->x0 + (c.x1 - d->x0)*(sw/(float)dw);
378 sr.y1 = s->y0 + (c.y1 - d->y0)*(sh/(float)dh);
379
380 s = src_rect;
381 d = dst_rect;
382 sw = s->x1 - s->x0;
383 sh = s->y1 - s->y0;
384 dw = d->x1 - d->x0;
385 dh = d->y1 - d->y0;
386 dr.x0 = d->x0 + c.x0*(dw/(float)sw);
387 dr.y0 = d->y0 + c.y0*(dh/(float)sh);
388 dr.x1 = d->x0 + c.x1*(dw/(float)sw);
389 dr.y1 = d->y0 + c.y1*(dh/(float)sh);
390
391 memset(&blend, 0, sizeof(blend));
392 blend.independent_blend_enable = 0;
393 blend.rt[0].blend_enable = 1;
394 blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
395 blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
396 blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
397 blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
398 blend.rt[0].rgb_func = PIPE_BLEND_ADD;
399 blend.rt[0].alpha_func = PIPE_BLEND_ADD;
400 blend.rt[0].colormask = PIPE_MASK_RGBA;
401 blend.logicop_enable = 0;
402 blend.logicop_func = PIPE_LOGICOP_CLEAR;
403 blend.dither = 0;
404 blend_state = drv->pipe->create_blend_state(drv->pipe, &blend);
405
406 vl_compositor_clear_layers(&drv->cstate);
407 vl_compositor_set_layer_blend(&drv->cstate, 0, blend_state, false);
408 upload_sampler(drv->pipe, sub->sampler, &box, buf->data,
409 sub->image->pitches[0], 0, 0);
410 vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, sub->sampler,
411 &sr, NULL, NULL);
412 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dr);
413 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, false);
414 drv->pipe->delete_blend_state(drv->pipe, blend_state);
415 }
416
417 return VA_STATUS_SUCCESS;
418 }
419
420 VAStatus
vlVaPutSurface(VADriverContextP ctx,VASurfaceID surface_id,void * draw,short srcx,short srcy,unsigned short srcw,unsigned short srch,short destx,short desty,unsigned short destw,unsigned short desth,VARectangle * cliprects,unsigned int number_cliprects,unsigned int flags)421 vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy,
422 unsigned short srcw, unsigned short srch, short destx, short desty,
423 unsigned short destw, unsigned short desth, VARectangle *cliprects,
424 unsigned int number_cliprects, unsigned int flags)
425 {
426 vlVaDriver *drv;
427 vlVaSurface *surf;
428 struct pipe_screen *screen;
429 struct pipe_resource *tex;
430 struct pipe_surface surf_templ, *surf_draw;
431 struct vl_screen *vscreen;
432 struct u_rect src_rect, *dirty_area;
433 struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
434 enum pipe_format format;
435 VAStatus status;
436
437 if (!ctx)
438 return VA_STATUS_ERROR_INVALID_CONTEXT;
439
440 drv = VL_VA_DRIVER(ctx);
441 mtx_lock(&drv->mutex);
442 surf = handle_table_get(drv->htab, surface_id);
443 if (!surf) {
444 mtx_unlock(&drv->mutex);
445 return VA_STATUS_ERROR_INVALID_SURFACE;
446 }
447
448 screen = drv->pipe->screen;
449 vscreen = drv->vscreen;
450
451 tex = vscreen->texture_from_drawable(vscreen, draw);
452 if (!tex) {
453 mtx_unlock(&drv->mutex);
454 return VA_STATUS_ERROR_INVALID_DISPLAY;
455 }
456
457 dirty_area = vscreen->get_dirty_area(vscreen);
458
459 memset(&surf_templ, 0, sizeof(surf_templ));
460 surf_templ.format = tex->format;
461 surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ);
462 if (!surf_draw) {
463 pipe_resource_reference(&tex, NULL);
464 mtx_unlock(&drv->mutex);
465 return VA_STATUS_ERROR_INVALID_DISPLAY;
466 }
467
468 src_rect.x0 = srcx;
469 src_rect.y0 = srcy;
470 src_rect.x1 = srcw + srcx;
471 src_rect.y1 = srch + srcy;
472
473 format = surf->buffer->buffer_format;
474
475 vl_compositor_clear_layers(&drv->cstate);
476
477 if (format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
478 format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM ||
479 format == PIPE_FORMAT_L8_UNORM || format == PIPE_FORMAT_Y8_400_UNORM) {
480 struct pipe_sampler_view **views;
481
482 views = surf->buffer->get_sampler_view_planes(surf->buffer);
483 vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, views[0], &src_rect, NULL, NULL);
484 } else
485 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
486
487 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
488 vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true);
489
490 status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect);
491 if (status) {
492 mtx_unlock(&drv->mutex);
493 return status;
494 }
495
496 /* flush before calling flush_frontbuffer so that rendering is flushed
497 * to back buffer so the texture can be copied in flush_frontbuffer
498 */
499 drv->pipe->flush(drv->pipe, NULL, 0);
500
501 screen->flush_frontbuffer(screen, drv->pipe, tex, 0, 0,
502 vscreen->get_private(vscreen), NULL);
503
504
505 pipe_resource_reference(&tex, NULL);
506 pipe_surface_reference(&surf_draw, NULL);
507 mtx_unlock(&drv->mutex);
508
509 return VA_STATUS_SUCCESS;
510 }
511
512 VAStatus
vlVaLockSurface(VADriverContextP ctx,VASurfaceID surface,unsigned int * fourcc,unsigned int * luma_stride,unsigned int * chroma_u_stride,unsigned int * chroma_v_stride,unsigned int * luma_offset,unsigned int * chroma_u_offset,unsigned int * chroma_v_offset,unsigned int * buffer_name,void ** buffer)513 vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc,
514 unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride,
515 unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset,
516 unsigned int *buffer_name, void **buffer)
517 {
518 if (!ctx)
519 return VA_STATUS_ERROR_INVALID_CONTEXT;
520
521 return VA_STATUS_ERROR_UNIMPLEMENTED;
522 }
523
524 VAStatus
vlVaUnlockSurface(VADriverContextP ctx,VASurfaceID surface)525 vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface)
526 {
527 if (!ctx)
528 return VA_STATUS_ERROR_INVALID_CONTEXT;
529
530 return VA_STATUS_ERROR_UNIMPLEMENTED;
531 }
532
533 VAStatus
vlVaQuerySurfaceAttributes(VADriverContextP ctx,VAConfigID config_id,VASurfaceAttrib * attrib_list,unsigned int * num_attribs)534 vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
535 VASurfaceAttrib *attrib_list, unsigned int *num_attribs)
536 {
537 vlVaDriver *drv;
538 vlVaConfig *config;
539 VASurfaceAttrib *attribs;
540 struct pipe_screen *pscreen;
541 int i, j;
542
543 STATIC_ASSERT(ARRAY_SIZE(vpp_surface_formats) <= VL_VA_MAX_IMAGE_FORMATS);
544
545 if (config_id == VA_INVALID_ID)
546 return VA_STATUS_ERROR_INVALID_CONFIG;
547
548 if (!attrib_list && !num_attribs)
549 return VA_STATUS_ERROR_INVALID_PARAMETER;
550
551 if (!attrib_list) {
552 *num_attribs = VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount;
553 return VA_STATUS_SUCCESS;
554 }
555
556 if (!ctx)
557 return VA_STATUS_ERROR_INVALID_CONTEXT;
558
559 drv = VL_VA_DRIVER(ctx);
560
561 if (!drv)
562 return VA_STATUS_ERROR_INVALID_CONTEXT;
563
564 mtx_lock(&drv->mutex);
565 config = handle_table_get(drv->htab, config_id);
566 mtx_unlock(&drv->mutex);
567
568 if (!config)
569 return VA_STATUS_ERROR_INVALID_CONFIG;
570
571 pscreen = VL_VA_PSCREEN(ctx);
572
573 if (!pscreen)
574 return VA_STATUS_ERROR_INVALID_CONTEXT;
575
576 attribs = CALLOC(VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount,
577 sizeof(VASurfaceAttrib));
578
579 if (!attribs)
580 return VA_STATUS_ERROR_ALLOCATION_FAILED;
581
582 i = 0;
583
584 /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN
585 * only for VAEntrypointVideoProc. */
586 if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) {
587 if (config->rt_format & VA_RT_FORMAT_RGB32) {
588 for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) {
589 attribs[i].type = VASurfaceAttribPixelFormat;
590 attribs[i].value.type = VAGenericValueTypeInteger;
591 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
592 attribs[i].value.value.i = PipeFormatToVaFourcc(vpp_surface_formats[j]);
593 i++;
594 }
595 }
596 }
597
598 if (config->rt_format & VA_RT_FORMAT_YUV420) {
599 attribs[i].type = VASurfaceAttribPixelFormat;
600 attribs[i].value.type = VAGenericValueTypeInteger;
601 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
602 attribs[i].value.value.i = VA_FOURCC_NV12;
603 i++;
604 }
605
606 if (config->rt_format & VA_RT_FORMAT_YUV420_10 ||
607 (config->rt_format & VA_RT_FORMAT_YUV420 &&
608 config->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE)) {
609 attribs[i].type = VASurfaceAttribPixelFormat;
610 attribs[i].value.type = VAGenericValueTypeInteger;
611 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
612 attribs[i].value.value.i = VA_FOURCC_P010;
613 i++;
614 attribs[i].type = VASurfaceAttribPixelFormat;
615 attribs[i].value.type = VAGenericValueTypeInteger;
616 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
617 attribs[i].value.value.i = VA_FOURCC_P016;
618 i++;
619 }
620
621 if (config->profile == PIPE_VIDEO_PROFILE_JPEG_BASELINE) {
622 if (config->rt_format & VA_RT_FORMAT_YUV400) {
623 attribs[i].type = VASurfaceAttribPixelFormat;
624 attribs[i].value.type = VAGenericValueTypeInteger;
625 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
626 attribs[i].value.value.i = VA_FOURCC_Y800;
627 i++;
628 }
629
630 if (config->rt_format & VA_RT_FORMAT_YUV422) {
631 attribs[i].type = VASurfaceAttribPixelFormat;
632 attribs[i].value.type = VAGenericValueTypeInteger;
633 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
634 attribs[i].value.value.i = VA_FOURCC_YUY2;
635 i++;
636 }
637
638 if (config->rt_format & VA_RT_FORMAT_YUV444) {
639 attribs[i].type = VASurfaceAttribPixelFormat;
640 attribs[i].value.type = VAGenericValueTypeInteger;
641 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
642 attribs[i].value.value.i = VA_FOURCC_444P;
643 i++;
644 }
645 if (config->rt_format & VA_RT_FORMAT_RGBP) {
646 attribs[i].type = VASurfaceAttribPixelFormat;
647 attribs[i].value.type = VAGenericValueTypeInteger;
648 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
649 attribs[i].value.value.i = VA_FOURCC_RGBP;
650 i++;
651 }
652 }
653
654 attribs[i].type = VASurfaceAttribMemoryType;
655 attribs[i].value.type = VAGenericValueTypeInteger;
656 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
657 attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA |
658 #ifdef _WIN32
659 VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE |
660 VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE;
661 #else
662 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME |
663 VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2;
664 #endif
665 i++;
666
667 attribs[i].type = VASurfaceAttribExternalBufferDescriptor;
668 attribs[i].value.type = VAGenericValueTypePointer;
669 attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
670 attribs[i].value.value.p = NULL; /* ignore */
671 i++;
672
673 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
674 if (drv->pipe->create_video_buffer_with_modifiers) {
675 attribs[i].type = VASurfaceAttribDRMFormatModifiers;
676 attribs[i].value.type = VAGenericValueTypePointer;
677 attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
678 attribs[i].value.value.p = NULL; /* ignore */
679 i++;
680 }
681 #endif
682
683 /* If VPP supported entry, use the max dimensions cap values, if not fallback to this below */
684 if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING ||
685 pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
686 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
687 PIPE_VIDEO_CAP_SUPPORTED))
688 {
689 unsigned min_width, min_height;
690 min_width = pscreen->get_video_param(pscreen,
691 config->profile, config->entrypoint,
692 PIPE_VIDEO_CAP_MIN_WIDTH);
693 min_height = pscreen->get_video_param(pscreen,
694 config->profile, config->entrypoint,
695 PIPE_VIDEO_CAP_MIN_HEIGHT);
696
697 if (min_width > 0 && min_height > 0) {
698 attribs[i].type = VASurfaceAttribMinWidth;
699 attribs[i].value.type = VAGenericValueTypeInteger;
700 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
701 attribs[i].value.value.i = min_width;
702 i++;
703
704 attribs[i].type = VASurfaceAttribMinHeight;
705 attribs[i].value.type = VAGenericValueTypeInteger;
706 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
707 attribs[i].value.value.i = min_height;
708 i++;
709 }
710
711 attribs[i].type = VASurfaceAttribMaxWidth;
712 attribs[i].value.type = VAGenericValueTypeInteger;
713 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
714 attribs[i].value.value.i =
715 pscreen->get_video_param(pscreen,
716 config->profile, config->entrypoint,
717 PIPE_VIDEO_CAP_MAX_WIDTH);
718 i++;
719
720 attribs[i].type = VASurfaceAttribMaxHeight;
721 attribs[i].value.type = VAGenericValueTypeInteger;
722 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
723 attribs[i].value.value.i =
724 pscreen->get_video_param(pscreen,
725 config->profile, config->entrypoint,
726 PIPE_VIDEO_CAP_MAX_HEIGHT);
727 i++;
728 } else {
729 attribs[i].type = VASurfaceAttribMaxWidth;
730 attribs[i].value.type = VAGenericValueTypeInteger;
731 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
732 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
733 i++;
734
735 attribs[i].type = VASurfaceAttribMaxHeight;
736 attribs[i].value.type = VAGenericValueTypeInteger;
737 attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
738 attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
739 i++;
740 }
741
742 if (i > *num_attribs) {
743 *num_attribs = i;
744 FREE(attribs);
745 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
746 }
747
748 *num_attribs = i;
749 memcpy(attrib_list, attribs, i * sizeof(VASurfaceAttrib));
750 FREE(attribs);
751
752 return VA_STATUS_SUCCESS;
753 }
754
755 #ifndef _WIN32
756 static VAStatus
surface_from_external_memory(VADriverContextP ctx,vlVaSurface * surface,VASurfaceAttribExternalBuffers * memory_attribute,unsigned index,struct pipe_video_buffer * templat)757 surface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface,
758 VASurfaceAttribExternalBuffers *memory_attribute,
759 unsigned index, struct pipe_video_buffer *templat)
760 {
761 vlVaDriver *drv;
762 struct pipe_screen *pscreen;
763 struct pipe_resource res_templ;
764 struct winsys_handle whandle;
765 struct pipe_resource *resources[VL_NUM_COMPONENTS];
766 enum pipe_format resource_formats[VL_NUM_COMPONENTS];
767 VAStatus result;
768 int i;
769
770 pscreen = VL_VA_PSCREEN(ctx);
771 drv = VL_VA_DRIVER(ctx);
772
773 if (!memory_attribute || !memory_attribute->buffers ||
774 index > memory_attribute->num_buffers)
775 return VA_STATUS_ERROR_INVALID_PARAMETER;
776
777 if (surface->templat.width != memory_attribute->width ||
778 surface->templat.height != memory_attribute->height ||
779 memory_attribute->num_planes < 1)
780 return VA_STATUS_ERROR_INVALID_PARAMETER;
781
782 if (memory_attribute->num_planes > VL_NUM_COMPONENTS)
783 return VA_STATUS_ERROR_INVALID_PARAMETER;
784
785 vl_get_video_buffer_formats(pscreen, templat->buffer_format, resource_formats);
786
787 memset(&res_templ, 0, sizeof(res_templ));
788 res_templ.target = PIPE_TEXTURE_2D;
789 res_templ.last_level = 0;
790 res_templ.depth0 = 1;
791 res_templ.array_size = 1;
792 res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
793 res_templ.usage = PIPE_USAGE_DEFAULT;
794
795 memset(&whandle, 0, sizeof(struct winsys_handle));
796 whandle.type = WINSYS_HANDLE_TYPE_FD;
797 whandle.handle = memory_attribute->buffers[index];
798 whandle.modifier = DRM_FORMAT_MOD_INVALID;
799 whandle.format = templat->buffer_format;
800
801 // Create a resource for each plane.
802 memset(resources, 0, sizeof resources);
803 for (i = 0; i < memory_attribute->num_planes; i++) {
804 unsigned num_planes = util_format_get_num_planes(templat->buffer_format);
805
806 res_templ.format = resource_formats[i];
807 if (res_templ.format == PIPE_FORMAT_NONE) {
808 if (i < num_planes) {
809 result = VA_STATUS_ERROR_INVALID_PARAMETER;
810 goto fail;
811 } else {
812 continue;
813 }
814 }
815
816 res_templ.width0 = util_format_get_plane_width(templat->buffer_format, i,
817 memory_attribute->width);
818 res_templ.height0 = util_format_get_plane_height(templat->buffer_format, i,
819 memory_attribute->height);
820
821 whandle.stride = memory_attribute->pitches[i];
822 whandle.offset = memory_attribute->offsets[i];
823 resources[i] = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
824 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
825 if (!resources[i]) {
826 result = VA_STATUS_ERROR_ALLOCATION_FAILED;
827 goto fail;
828 }
829 }
830
831 surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
832 if (!surface->buffer) {
833 result = VA_STATUS_ERROR_ALLOCATION_FAILED;
834 goto fail;
835 }
836 return VA_STATUS_SUCCESS;
837
838 fail:
839 for (i = 0; i < VL_NUM_COMPONENTS; i++)
840 pipe_resource_reference(&resources[i], NULL);
841 return result;
842 }
843
844 static VAStatus
surface_from_prime_2(VADriverContextP ctx,vlVaSurface * surface,VADRMPRIMESurfaceDescriptor * desc,struct pipe_video_buffer * templat)845 surface_from_prime_2(VADriverContextP ctx, vlVaSurface *surface,
846 VADRMPRIMESurfaceDescriptor *desc,
847 struct pipe_video_buffer *templat)
848 {
849 vlVaDriver *drv;
850 struct pipe_screen *pscreen;
851 struct pipe_resource res_templ;
852 struct winsys_handle whandle;
853 struct pipe_resource *resources[VL_NUM_COMPONENTS];
854 enum pipe_format resource_formats[VL_NUM_COMPONENTS];
855 unsigned num_format_planes, expected_planes, input_planes, plane;
856 VAStatus result;
857
858 num_format_planes = util_format_get_num_planes(templat->buffer_format);
859 pscreen = VL_VA_PSCREEN(ctx);
860 drv = VL_VA_DRIVER(ctx);
861
862 if (!desc || desc->num_layers >= 4 ||desc->num_objects == 0)
863 return VA_STATUS_ERROR_INVALID_PARAMETER;
864
865 if (surface->templat.width != desc->width ||
866 surface->templat.height != desc->height ||
867 desc->num_layers < 1)
868 return VA_STATUS_ERROR_INVALID_PARAMETER;
869
870 if (desc->num_layers > VL_NUM_COMPONENTS)
871 return VA_STATUS_ERROR_INVALID_PARAMETER;
872
873 input_planes = 0;
874 for (unsigned i = 0; i < desc->num_layers; ++i) {
875 if (desc->layers[i].num_planes == 0 || desc->layers[i].num_planes > 4)
876 return VA_STATUS_ERROR_INVALID_PARAMETER;
877
878 for (unsigned j = 0; j < desc->layers[i].num_planes; ++j)
879 if (desc->layers[i].object_index[j] >= desc->num_objects)
880 return VA_STATUS_ERROR_INVALID_PARAMETER;
881
882 input_planes += desc->layers[i].num_planes;
883 }
884
885 expected_planes = num_format_planes;
886 if (desc->objects[0].drm_format_modifier != DRM_FORMAT_MOD_INVALID &&
887 pscreen->is_dmabuf_modifier_supported &&
888 pscreen->is_dmabuf_modifier_supported(pscreen, desc->objects[0].drm_format_modifier,
889 templat->buffer_format, NULL) &&
890 pscreen->get_dmabuf_modifier_planes)
891 expected_planes = pscreen->get_dmabuf_modifier_planes(pscreen, desc->objects[0].drm_format_modifier,
892 templat->buffer_format);
893
894 if (input_planes != expected_planes)
895 return VA_STATUS_ERROR_INVALID_PARAMETER;
896
897 vl_get_video_buffer_formats(pscreen, templat->buffer_format, resource_formats);
898
899 memset(&res_templ, 0, sizeof(res_templ));
900 res_templ.target = PIPE_TEXTURE_2D;
901 res_templ.last_level = 0;
902 res_templ.depth0 = 1;
903 res_templ.array_size = 1;
904 res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
905 res_templ.usage = PIPE_USAGE_DEFAULT;
906 res_templ.format = templat->buffer_format;
907
908 memset(&whandle, 0, sizeof(struct winsys_handle));
909 whandle.type = WINSYS_HANDLE_TYPE_FD;
910 whandle.format = templat->buffer_format;
911 whandle.modifier = desc->objects[0].drm_format_modifier;
912
913 // Create a resource for each plane.
914 memset(resources, 0, sizeof resources);
915
916 /* This does a backwards walk to set the next pointers. It interleaves so
917 * that the main planes always come first and then the first compression metadata
918 * plane of each main plane etc. */
919 plane = input_planes - 1;
920 for (int layer_plane = 3; layer_plane >= 0; --layer_plane) {
921 for (int layer = desc->num_layers - 1; layer >= 0; --layer) {
922 if (layer_plane >= desc->layers[layer].num_planes)
923 continue;
924
925 if (plane < num_format_planes)
926 res_templ.format = resource_formats[plane];
927
928 res_templ.width0 = util_format_get_plane_width(templat->buffer_format, plane,
929 desc->width);
930 res_templ.height0 = util_format_get_plane_height(templat->buffer_format, plane,
931 desc->height);
932 whandle.stride = desc->layers[layer].pitch[layer_plane];
933 whandle.offset = desc->layers[layer].offset[layer_plane];
934 whandle.handle = desc->objects[desc->layers[layer].object_index[layer_plane]].fd;
935 whandle.plane = plane;
936
937 resources[plane] = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
938 PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE);
939 if (!resources[plane]) {
940 result = VA_STATUS_ERROR_ALLOCATION_FAILED;
941 goto fail;
942 }
943
944 /* After the resource gets created the resource now owns the next reference. */
945 res_templ.next = NULL;
946
947 if (plane)
948 pipe_resource_reference(&res_templ.next, resources[plane]);
949 --plane;
950 }
951 }
952
953 surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
954 if (!surface->buffer) {
955 result = VA_STATUS_ERROR_ALLOCATION_FAILED;
956 goto fail;
957 }
958 return VA_STATUS_SUCCESS;
959
960 fail:
961 pipe_resource_reference(&res_templ.next, NULL);
962 for (int i = 0; i < VL_NUM_COMPONENTS; i++)
963 pipe_resource_reference(&resources[i], NULL);
964 return result;
965 }
966 #else
967 static VAStatus
surface_from_external_win32_memory(VADriverContextP ctx,vlVaSurface * surface,int memory_type,void * res_handle,struct pipe_video_buffer * templat)968 surface_from_external_win32_memory(VADriverContextP ctx, vlVaSurface *surface,
969 int memory_type, void *res_handle,
970 struct pipe_video_buffer *templat)
971 {
972 vlVaDriver *drv;
973 struct pipe_screen *pscreen;
974 struct winsys_handle whandle;
975 VAStatus result;
976
977 pscreen = VL_VA_PSCREEN(ctx);
978 drv = VL_VA_DRIVER(ctx);
979
980 templat->buffer_format = surface->templat.buffer_format;
981 templat->width = surface->templat.width;
982 templat->height = surface->templat.height;
983
984 memset(&whandle, 0, sizeof(whandle));
985 whandle.format = surface->templat.buffer_format;
986 if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE) {
987 whandle.type = WINSYS_HANDLE_TYPE_FD;
988 whandle.handle = res_handle;
989 } else if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE) {
990 whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
991 whandle.com_obj = res_handle;
992 } else {
993 return VA_STATUS_ERROR_INVALID_PARAMETER;
994 }
995
996 surface->buffer = drv->pipe->video_buffer_from_handle(drv->pipe, templat, &whandle, PIPE_USAGE_DEFAULT);
997 if (!surface->buffer) {
998 result = VA_STATUS_ERROR_ALLOCATION_FAILED;
999 goto fail;
1000 }
1001 return VA_STATUS_SUCCESS;
1002
1003 fail:
1004 return result;
1005 }
1006
1007 #endif
1008
1009 VAStatus
vlVaHandleSurfaceAllocate(vlVaDriver * drv,vlVaSurface * surface,struct pipe_video_buffer * templat,const uint64_t * modifiers,unsigned int modifiers_count)1010 vlVaHandleSurfaceAllocate(vlVaDriver *drv, vlVaSurface *surface,
1011 struct pipe_video_buffer *templat,
1012 const uint64_t *modifiers,
1013 unsigned int modifiers_count)
1014 {
1015 struct pipe_surface **surfaces;
1016 unsigned i;
1017
1018 if (modifiers_count > 0) {
1019 if (!drv->pipe->create_video_buffer_with_modifiers)
1020 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
1021 surface->buffer =
1022 drv->pipe->create_video_buffer_with_modifiers(drv->pipe, templat,
1023 modifiers,
1024 modifiers_count);
1025 } else {
1026 surface->buffer = drv->pipe->create_video_buffer(drv->pipe, templat);
1027 }
1028 if (!surface->buffer)
1029 return VA_STATUS_ERROR_ALLOCATION_FAILED;
1030
1031 surfaces = surface->buffer->get_surfaces(surface->buffer);
1032 for (i = 0; i < VL_MAX_SURFACES; ++i) {
1033 union pipe_color_union c;
1034 memset(&c, 0, sizeof(c));
1035
1036 if (!surfaces[i])
1037 continue;
1038
1039 if (i > !!surface->buffer->interlaced)
1040 c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
1041
1042 drv->pipe->clear_render_target(drv->pipe, surfaces[i], &c, 0, 0,
1043 surfaces[i]->width, surfaces[i]->height,
1044 false);
1045 }
1046 drv->pipe->flush(drv->pipe, NULL, 0);
1047
1048 return VA_STATUS_SUCCESS;
1049 }
1050
1051 VAStatus
vlVaCreateSurfaces2(VADriverContextP ctx,unsigned int format,unsigned int width,unsigned int height,VASurfaceID * surfaces,unsigned int num_surfaces,VASurfaceAttrib * attrib_list,unsigned int num_attribs)1052 vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
1053 unsigned int width, unsigned int height,
1054 VASurfaceID *surfaces, unsigned int num_surfaces,
1055 VASurfaceAttrib *attrib_list, unsigned int num_attribs)
1056 {
1057 vlVaDriver *drv;
1058 VASurfaceAttribExternalBuffers *memory_attribute;
1059 #ifdef _WIN32
1060 void **win32_handles;
1061 #else
1062 VADRMPRIMESurfaceDescriptor *prime_desc = NULL;
1063 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
1064 const VADRMFormatModifierList *modifier_list;
1065 #endif
1066 #endif
1067 struct pipe_video_buffer templat;
1068 struct pipe_screen *pscreen;
1069 int i;
1070 int memory_type;
1071 int expected_fourcc;
1072 VAStatus vaStatus;
1073 vlVaSurface *surf;
1074 bool protected;
1075 const uint64_t *modifiers;
1076 unsigned int modifiers_count;
1077
1078 if (!ctx)
1079 return VA_STATUS_ERROR_INVALID_CONTEXT;
1080
1081 if (!(width && height))
1082 return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
1083
1084 drv = VL_VA_DRIVER(ctx);
1085
1086 if (!drv)
1087 return VA_STATUS_ERROR_INVALID_CONTEXT;
1088
1089 pscreen = VL_VA_PSCREEN(ctx);
1090
1091 if (!pscreen)
1092 return VA_STATUS_ERROR_INVALID_CONTEXT;
1093
1094 /* Default. */
1095 memory_attribute = NULL;
1096 memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
1097 expected_fourcc = 0;
1098 modifiers = NULL;
1099 modifiers_count = 0;
1100
1101 for (i = 0; i < num_attribs && attrib_list; i++) {
1102 if (!(attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE))
1103 continue;
1104
1105 switch (attrib_list[i].type) {
1106 case VASurfaceAttribPixelFormat:
1107 if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1108 return VA_STATUS_ERROR_INVALID_PARAMETER;
1109 expected_fourcc = attrib_list[i].value.value.i;
1110 break;
1111 case VASurfaceAttribMemoryType:
1112 if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1113 return VA_STATUS_ERROR_INVALID_PARAMETER;
1114
1115 switch (attrib_list[i].value.value.i) {
1116 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1117
1118 #ifdef _WIN32
1119 case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1120 case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1121 #else
1122 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1123 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1124 #endif
1125 memory_type = attrib_list[i].value.value.i;
1126 break;
1127 default:
1128 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1129 }
1130 break;
1131 case VASurfaceAttribExternalBufferDescriptor:
1132 if (attrib_list[i].value.type != VAGenericValueTypePointer)
1133 return VA_STATUS_ERROR_INVALID_PARAMETER;
1134 #ifndef _WIN32
1135 if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
1136 prime_desc = (VADRMPRIMESurfaceDescriptor *)attrib_list[i].value.value.p;
1137 #else
1138 else if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE ||
1139 memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1140 win32_handles = (void**) attrib_list[i].value.value.p;
1141 #endif
1142 else
1143 memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
1144 break;
1145 #ifndef _WIN32
1146 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
1147 case VASurfaceAttribDRMFormatModifiers:
1148 if (attrib_list[i].value.type != VAGenericValueTypePointer)
1149 return VA_STATUS_ERROR_INVALID_PARAMETER;
1150 modifier_list = attrib_list[i].value.value.p;
1151 if (modifier_list != NULL) {
1152 modifiers = modifier_list->modifiers;
1153 modifiers_count = modifier_list->num_modifiers;
1154 }
1155 break;
1156 #endif
1157 #endif
1158 case VASurfaceAttribUsageHint:
1159 if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1160 return VA_STATUS_ERROR_INVALID_PARAMETER;
1161 break;
1162 default:
1163 return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
1164 }
1165 }
1166
1167 protected = format & VA_RT_FORMAT_PROTECTED;
1168 format &= ~VA_RT_FORMAT_PROTECTED;
1169
1170 if (VA_RT_FORMAT_YUV420 != format &&
1171 VA_RT_FORMAT_YUV422 != format &&
1172 VA_RT_FORMAT_YUV444 != format &&
1173 VA_RT_FORMAT_YUV400 != format &&
1174 VA_RT_FORMAT_YUV420_10BPP != format &&
1175 VA_RT_FORMAT_RGBP != format &&
1176 VA_RT_FORMAT_RGB32 != format) {
1177 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
1178 }
1179
1180 switch (memory_type) {
1181 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1182 break;
1183 #ifdef _WIN32
1184 case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1185 case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1186 if (!win32_handles)
1187 return VA_STATUS_ERROR_INVALID_PARAMETER;
1188 break;
1189 #else
1190 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1191 if (!memory_attribute)
1192 return VA_STATUS_ERROR_INVALID_PARAMETER;
1193 if (modifiers)
1194 return VA_STATUS_ERROR_INVALID_PARAMETER;
1195
1196 expected_fourcc = memory_attribute->pixel_format;
1197 break;
1198 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1199 if (!prime_desc)
1200 return VA_STATUS_ERROR_INVALID_PARAMETER;
1201
1202 expected_fourcc = prime_desc->fourcc;
1203 break;
1204 #endif
1205 default:
1206 assert(0);
1207 }
1208
1209 memset(&templat, 0, sizeof(templat));
1210
1211 templat.buffer_format = pscreen->get_video_param(
1212 pscreen,
1213 PIPE_VIDEO_PROFILE_UNKNOWN,
1214 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
1215 PIPE_VIDEO_CAP_PREFERED_FORMAT
1216 );
1217
1218 if (modifiers)
1219 templat.interlaced = false;
1220 else
1221 templat.interlaced =
1222 pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1223 PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
1224 PIPE_VIDEO_CAP_PREFERS_INTERLACED);
1225
1226 if (expected_fourcc) {
1227 enum pipe_format expected_format = VaFourccToPipeFormat(expected_fourcc);
1228
1229 #ifndef _WIN32
1230 if (expected_format != templat.buffer_format || memory_attribute || prime_desc)
1231 #else
1232 if (expected_format != templat.buffer_format || memory_attribute)
1233 #endif
1234 templat.interlaced = 0;
1235
1236 templat.buffer_format = expected_format;
1237 }
1238
1239 templat.width = width;
1240 templat.height = height;
1241 if (protected)
1242 templat.bind |= PIPE_BIND_PROTECTED;
1243
1244 memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID));
1245
1246 mtx_lock(&drv->mutex);
1247 for (i = 0; i < num_surfaces; i++) {
1248 surf = CALLOC(1, sizeof(vlVaSurface));
1249 if (!surf) {
1250 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
1251 goto no_res;
1252 }
1253
1254 surf->templat = templat;
1255
1256 switch (memory_type) {
1257 case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1258 /* The application will clear the TILING flag when the surface is
1259 * intended to be exported as dmabuf. Adding shared flag because not
1260 * null memory_attribute means VASurfaceAttribExternalBuffers is used.
1261 */
1262 if (memory_attribute &&
1263 !(memory_attribute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING))
1264 templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED;
1265
1266 vaStatus = vlVaHandleSurfaceAllocate(drv, surf, &templat, modifiers,
1267 modifiers_count);
1268 if (vaStatus != VA_STATUS_SUCCESS)
1269 goto free_surf;
1270 break;
1271
1272 #ifdef _WIN32
1273 case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1274 case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1275 vaStatus = surface_from_external_win32_memory(ctx, surf, memory_type, win32_handles[i], &templat);
1276 if (vaStatus != VA_STATUS_SUCCESS)
1277 goto free_surf;
1278 break;
1279 #else
1280 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1281 vaStatus = surface_from_external_memory(ctx, surf, memory_attribute, i, &templat);
1282 if (vaStatus != VA_STATUS_SUCCESS)
1283 goto free_surf;
1284 break;
1285
1286 case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1287 vaStatus = surface_from_prime_2(ctx, surf, prime_desc, &templat);
1288 if (vaStatus != VA_STATUS_SUCCESS)
1289 goto free_surf;
1290 break;
1291 #endif
1292 default:
1293 assert(0);
1294 }
1295
1296 util_dynarray_init(&surf->subpics, NULL);
1297 surfaces[i] = handle_table_add(drv->htab, surf);
1298 if (!surfaces[i]) {
1299 vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
1300 goto destroy_surf;
1301 }
1302 }
1303 mtx_unlock(&drv->mutex);
1304
1305 return VA_STATUS_SUCCESS;
1306
1307 destroy_surf:
1308 surf->buffer->destroy(surf->buffer);
1309
1310 free_surf:
1311 FREE(surf);
1312
1313 no_res:
1314 mtx_unlock(&drv->mutex);
1315 if (i)
1316 vlVaDestroySurfaces(ctx, surfaces, i);
1317
1318 return vaStatus;
1319 }
1320
1321 VAStatus
vlVaQueryVideoProcFilters(VADriverContextP ctx,VAContextID context,VAProcFilterType * filters,unsigned int * num_filters)1322 vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context,
1323 VAProcFilterType *filters, unsigned int *num_filters)
1324 {
1325 unsigned int num = 0;
1326
1327 if (!ctx)
1328 return VA_STATUS_ERROR_INVALID_CONTEXT;
1329
1330 if (!num_filters || !filters)
1331 return VA_STATUS_ERROR_INVALID_PARAMETER;
1332
1333 filters[num++] = VAProcFilterDeinterlacing;
1334
1335 *num_filters = num;
1336
1337 return VA_STATUS_SUCCESS;
1338 }
1339
1340 VAStatus
vlVaQueryVideoProcFilterCaps(VADriverContextP ctx,VAContextID context,VAProcFilterType type,void * filter_caps,unsigned int * num_filter_caps)1341 vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context,
1342 VAProcFilterType type, void *filter_caps,
1343 unsigned int *num_filter_caps)
1344 {
1345 unsigned int i;
1346
1347 if (!ctx)
1348 return VA_STATUS_ERROR_INVALID_CONTEXT;
1349
1350 if (!filter_caps || !num_filter_caps)
1351 return VA_STATUS_ERROR_INVALID_PARAMETER;
1352
1353 i = 0;
1354
1355 switch (type) {
1356 case VAProcFilterNone:
1357 break;
1358 case VAProcFilterDeinterlacing: {
1359 VAProcFilterCapDeinterlacing *deint = filter_caps;
1360
1361 if (*num_filter_caps < 3) {
1362 *num_filter_caps = 3;
1363 return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
1364 }
1365
1366 deint[i++].type = VAProcDeinterlacingBob;
1367 deint[i++].type = VAProcDeinterlacingWeave;
1368 deint[i++].type = VAProcDeinterlacingMotionAdaptive;
1369 break;
1370 }
1371
1372 case VAProcFilterNoiseReduction:
1373 case VAProcFilterSharpening:
1374 case VAProcFilterColorBalance:
1375 case VAProcFilterSkinToneEnhancement:
1376 return VA_STATUS_ERROR_UNIMPLEMENTED;
1377 default:
1378 assert(0);
1379 }
1380
1381 *num_filter_caps = i;
1382
1383 return VA_STATUS_SUCCESS;
1384 }
1385
1386 static VAProcColorStandardType vpp_input_color_standards[] = {
1387 VAProcColorStandardBT601,
1388 VAProcColorStandardBT709
1389 };
1390
1391 static VAProcColorStandardType vpp_output_color_standards[] = {
1392 VAProcColorStandardBT601,
1393 VAProcColorStandardBT709
1394 };
1395
1396 VAStatus
vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx,VAContextID context,VABufferID * filters,unsigned int num_filters,VAProcPipelineCaps * pipeline_cap)1397 vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
1398 VABufferID *filters, unsigned int num_filters,
1399 VAProcPipelineCaps *pipeline_cap)
1400 {
1401 unsigned int i = 0;
1402
1403 if (!ctx)
1404 return VA_STATUS_ERROR_INVALID_CONTEXT;
1405
1406 if (!pipeline_cap)
1407 return VA_STATUS_ERROR_INVALID_PARAMETER;
1408
1409 if (num_filters && !filters)
1410 return VA_STATUS_ERROR_INVALID_PARAMETER;
1411
1412 pipeline_cap->pipeline_flags = 0;
1413 pipeline_cap->filter_flags = 0;
1414 pipeline_cap->num_forward_references = 0;
1415 pipeline_cap->num_backward_references = 0;
1416 pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards);
1417 pipeline_cap->input_color_standards = vpp_input_color_standards;
1418 pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
1419 pipeline_cap->output_color_standards = vpp_output_color_standards;
1420
1421 struct pipe_screen *pscreen = VL_VA_PSCREEN(ctx);
1422 uint32_t pipe_orientation_flags = pscreen->get_video_param(pscreen,
1423 PIPE_VIDEO_PROFILE_UNKNOWN,
1424 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1425 PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES);
1426
1427 pipeline_cap->rotation_flags = VA_ROTATION_NONE;
1428 if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_90)
1429 pipeline_cap->rotation_flags |= (1 << VA_ROTATION_90);
1430 if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_180)
1431 pipeline_cap->rotation_flags |= (1 << VA_ROTATION_180);
1432 if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_270)
1433 pipeline_cap->rotation_flags |= (1 << VA_ROTATION_270);
1434
1435 pipeline_cap->mirror_flags = VA_MIRROR_NONE;
1436 if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL)
1437 pipeline_cap->mirror_flags |= VA_MIRROR_HORIZONTAL;
1438 if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_VERTICAL)
1439 pipeline_cap->mirror_flags |= VA_MIRROR_VERTICAL;
1440
1441 pipeline_cap->max_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1442 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1443 PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH);
1444
1445 pipeline_cap->max_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1446 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1447 PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT);
1448
1449 pipeline_cap->min_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1450 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1451 PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH);
1452
1453 pipeline_cap->min_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1454 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1455 PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT);
1456
1457 pipeline_cap->max_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1458 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1459 PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH);
1460
1461 pipeline_cap->max_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1462 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1463 PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT);
1464
1465 pipeline_cap->min_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1466 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1467 PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH);
1468
1469 pipeline_cap->min_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1470 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1471 PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT);
1472
1473 uint32_t pipe_blend_modes = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1474 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1475 PIPE_VIDEO_CAP_VPP_BLEND_MODES);
1476
1477 pipeline_cap->blend_flags = 0;
1478 if (pipe_blend_modes & PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA)
1479 pipeline_cap->blend_flags |= VA_BLEND_GLOBAL_ALPHA;
1480
1481 for (i = 0; i < num_filters; i++) {
1482 vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]);
1483 VAProcFilterParameterBufferBase *filter;
1484
1485 if (!buf || buf->type != VAProcFilterParameterBufferType)
1486 return VA_STATUS_ERROR_INVALID_BUFFER;
1487
1488 filter = buf->data;
1489 switch (filter->type) {
1490 case VAProcFilterDeinterlacing: {
1491 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
1492 if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) {
1493 pipeline_cap->num_forward_references = 2;
1494 pipeline_cap->num_backward_references = 1;
1495 }
1496 break;
1497 }
1498 default:
1499 return VA_STATUS_ERROR_UNIMPLEMENTED;
1500 }
1501 }
1502
1503 return VA_STATUS_SUCCESS;
1504 }
1505
1506 #ifndef _WIN32
pipe_format_to_drm_format(enum pipe_format format)1507 static uint32_t pipe_format_to_drm_format(enum pipe_format format)
1508 {
1509 switch (format) {
1510 case PIPE_FORMAT_R8_UNORM:
1511 return DRM_FORMAT_R8;
1512 case PIPE_FORMAT_R8G8_UNORM:
1513 return DRM_FORMAT_GR88;
1514 case PIPE_FORMAT_R16_UNORM:
1515 return DRM_FORMAT_R16;
1516 case PIPE_FORMAT_R16G16_UNORM:
1517 return DRM_FORMAT_GR1616;
1518 case PIPE_FORMAT_B8G8R8A8_UNORM:
1519 return DRM_FORMAT_ARGB8888;
1520 case PIPE_FORMAT_R8G8B8A8_UNORM:
1521 return DRM_FORMAT_ABGR8888;
1522 case PIPE_FORMAT_B8G8R8X8_UNORM:
1523 return DRM_FORMAT_XRGB8888;
1524 case PIPE_FORMAT_R8G8B8X8_UNORM:
1525 return DRM_FORMAT_XBGR8888;
1526 case PIPE_FORMAT_NV12:
1527 return DRM_FORMAT_NV12;
1528 case PIPE_FORMAT_P010:
1529 return DRM_FORMAT_P010;
1530 case PIPE_FORMAT_YUYV:
1531 case PIPE_FORMAT_R8G8_R8B8_UNORM:
1532 return DRM_FORMAT_YUYV;
1533 default:
1534 return DRM_FORMAT_INVALID;
1535 }
1536 }
1537 #endif
1538
1539 #if VA_CHECK_VERSION(1, 1, 0)
1540 VAStatus
vlVaExportSurfaceHandle(VADriverContextP ctx,VASurfaceID surface_id,uint32_t mem_type,uint32_t flags,void * descriptor)1541 vlVaExportSurfaceHandle(VADriverContextP ctx,
1542 VASurfaceID surface_id,
1543 uint32_t mem_type,
1544 uint32_t flags,
1545 void *descriptor)
1546 {
1547 vlVaDriver *drv;
1548 vlVaSurface *surf;
1549 struct pipe_surface **surfaces;
1550 struct pipe_screen *screen;
1551 VAStatus ret;
1552 unsigned int usage;
1553
1554 #ifdef _WIN32
1555 if ((mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1556 && (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE))
1557 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1558
1559 if ((flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) == 0)
1560 return VA_STATUS_ERROR_INVALID_SURFACE;
1561 #else
1562 int i, p;
1563 if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
1564 return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1565 #endif
1566
1567 drv = VL_VA_DRIVER(ctx);
1568 screen = VL_VA_PSCREEN(ctx);
1569 mtx_lock(&drv->mutex);
1570
1571 surf = handle_table_get(drv->htab, surface_id);
1572 if (!surf || !surf->buffer) {
1573 mtx_unlock(&drv->mutex);
1574 return VA_STATUS_ERROR_INVALID_SURFACE;
1575 }
1576
1577 if (surf->buffer->interlaced) {
1578 struct pipe_video_buffer *interlaced = surf->buffer;
1579 struct u_rect src_rect, dst_rect;
1580
1581 surf->templat.interlaced = false;
1582
1583 ret = vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0);
1584 if (ret != VA_STATUS_SUCCESS) {
1585 mtx_unlock(&drv->mutex);
1586 return VA_STATUS_ERROR_ALLOCATION_FAILED;
1587 }
1588
1589 src_rect.x0 = dst_rect.x0 = 0;
1590 src_rect.y0 = dst_rect.y0 = 0;
1591 src_rect.x1 = dst_rect.x1 = surf->templat.width;
1592 src_rect.y1 = dst_rect.y1 = surf->templat.height;
1593
1594 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
1595 interlaced, surf->buffer,
1596 &src_rect, &dst_rect,
1597 VL_COMPOSITOR_WEAVE);
1598 if (interlaced->codec && interlaced->codec->update_decoder_target)
1599 interlaced->codec->update_decoder_target(interlaced->codec, interlaced, surf->buffer);
1600
1601 interlaced->destroy(interlaced);
1602 }
1603
1604 surfaces = surf->buffer->get_surfaces(surf->buffer);
1605
1606 usage = 0;
1607 if (flags & VA_EXPORT_SURFACE_WRITE_ONLY)
1608 usage |= PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1609
1610 #ifdef _WIN32
1611 struct winsys_handle whandle;
1612 memset(&whandle, 0, sizeof(struct winsys_handle));
1613 struct pipe_resource *resource = surfaces[0]->texture;
1614
1615 if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1616 whandle.type = WINSYS_HANDLE_TYPE_FD;
1617 else if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1618 whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
1619
1620 if (!screen->resource_get_handle(screen, drv->pipe, resource,
1621 &whandle, usage)) {
1622 ret = VA_STATUS_ERROR_INVALID_SURFACE;
1623 goto fail;
1624 }
1625
1626 if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1627 *(HANDLE**)descriptor = whandle.handle;
1628 else if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1629 *(void**) descriptor = whandle.com_obj;
1630
1631 #else
1632 VADRMPRIMESurfaceDescriptor *desc = descriptor;
1633 desc->fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
1634 desc->width = surf->templat.width;
1635 desc->height = surf->templat.height;
1636
1637 for (p = 0; p < ARRAY_SIZE(desc->objects); p++) {
1638 struct winsys_handle whandle;
1639 struct pipe_resource *resource;
1640 uint32_t drm_format;
1641
1642 if (!surfaces[p])
1643 break;
1644
1645 resource = surfaces[p]->texture;
1646
1647 drm_format = pipe_format_to_drm_format(resource->format);
1648 if (drm_format == DRM_FORMAT_INVALID) {
1649 ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1650 goto fail;
1651 }
1652
1653 memset(&whandle, 0, sizeof(whandle));
1654 whandle.type = WINSYS_HANDLE_TYPE_FD;
1655
1656 if (!screen->resource_get_handle(screen, drv->pipe, resource,
1657 &whandle, usage)) {
1658 ret = VA_STATUS_ERROR_INVALID_SURFACE;
1659 goto fail;
1660 }
1661
1662 desc->objects[p].fd = (int)whandle.handle;
1663 /* As per VADRMPRIMESurfaceDescriptor documentation, size must be the
1664 * "Total size of this object (may include regions which are not part
1665 * of the surface)."" */
1666 desc->objects[p].size = (uint32_t) whandle.size;
1667 desc->objects[p].drm_format_modifier = whandle.modifier;
1668
1669 if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) {
1670 desc->layers[0].object_index[p] = p;
1671 desc->layers[0].offset[p] = whandle.offset;
1672 desc->layers[0].pitch[p] = whandle.stride;
1673 } else {
1674 desc->layers[p].drm_format = drm_format;
1675 desc->layers[p].num_planes = 1;
1676 desc->layers[p].object_index[0] = p;
1677 desc->layers[p].offset[0] = whandle.offset;
1678 desc->layers[p].pitch[0] = whandle.stride;
1679 }
1680 }
1681
1682 desc->num_objects = p;
1683
1684 if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) {
1685 uint32_t drm_format = pipe_format_to_drm_format(surf->buffer->buffer_format);
1686 if (drm_format == DRM_FORMAT_INVALID) {
1687 ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1688 goto fail;
1689 }
1690
1691 desc->num_layers = 1;
1692 desc->layers[0].drm_format = drm_format;
1693 desc->layers[0].num_planes = p;
1694 } else {
1695 desc->num_layers = p;
1696 }
1697 #endif
1698
1699 mtx_unlock(&drv->mutex);
1700
1701 return VA_STATUS_SUCCESS;
1702
1703 fail:
1704 #ifndef _WIN32
1705 for (i = 0; i < p; i++)
1706 close(desc->objects[i].fd);
1707 #else
1708 if(whandle.handle)
1709 CloseHandle(whandle.handle);
1710 #endif
1711
1712 mtx_unlock(&drv->mutex);
1713
1714 return ret;
1715 }
1716 #endif
1717