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