• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2010 Thomas Balling Sørensen & Orasanu Lucian.
4  * Copyright 2014 Advanced Micro Devices, Inc.
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a
8  * copy of this software and associated documentation files (the
9  * "Software"), to deal in the Software without restriction, including
10  * without limitation the rights to use, copy, modify, merge, publish,
11  * distribute, sub license, and/or sell copies of the Software, and to
12  * permit persons to whom the Software is furnished to do so, subject to
13  * the following conditions:
14  *
15  * The above copyright notice and this permission notice (including the
16  * next paragraph) shall be included in all copies or substantial portions
17  * of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
22  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
23  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26  *
27  **************************************************************************/
28 
29 #include "pipe/p_screen.h"
30 #include "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 #ifndef VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3
56 #define VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3      0x08000000
57 #endif
58 
59 VAStatus
vlVaCreateSurfaces(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surfaces)60 vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format,
61                    int num_surfaces, VASurfaceID *surfaces)
62 {
63    return vlVaCreateSurfaces2(ctx, format, width, height, surfaces, num_surfaces,
64                               NULL, 0);
65 }
66 
67 static void
vlVaRemoveDpbSurface(vlVaSurface * surf,VASurfaceID id)68 vlVaRemoveDpbSurface(vlVaSurface *surf, VASurfaceID id)
69 {
70    assert(surf->ctx->templat.entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE);
71 
72    switch (u_reduce_video_profile(surf->ctx->templat.profile)) {
73    case PIPE_VIDEO_FORMAT_MPEG4_AVC:
74       for (unsigned i = 0; i < surf->ctx->desc.h264enc.dpb_size; i++) {
75          if (surf->ctx->desc.h264enc.dpb[i].id == id) {
76             memset(&surf->ctx->desc.h264enc.dpb[i], 0, sizeof(surf->ctx->desc.h264enc.dpb[i]));
77             break;
78          }
79       }
80       break;
81    case PIPE_VIDEO_FORMAT_HEVC:
82       for (unsigned i = 0; i < surf->ctx->desc.h265enc.dpb_size; i++) {
83          if (surf->ctx->desc.h265enc.dpb[i].id == id) {
84             memset(&surf->ctx->desc.h265enc.dpb[i], 0, sizeof(surf->ctx->desc.h265enc.dpb[i]));
85             break;
86          }
87       }
88       break;
89    case PIPE_VIDEO_FORMAT_AV1:
90       for (unsigned i = 0; i < surf->ctx->desc.av1enc.dpb_size; i++) {
91          if (surf->ctx->desc.av1enc.dpb[i].id == id) {
92             memset(&surf->ctx->desc.av1enc.dpb[i], 0, sizeof(surf->ctx->desc.av1enc.dpb[i]));
93             break;
94          }
95       }
96       break;
97    default:
98       assert(false);
99       break;
100    }
101 }
102 
103 VAStatus
vlVaDestroySurfaces(VADriverContextP ctx,VASurfaceID * surface_list,int num_surfaces)104 vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces)
105 {
106    vlVaDriver *drv;
107    int i;
108 
109    if (!ctx)
110       return VA_STATUS_ERROR_INVALID_CONTEXT;
111 
112    drv = VL_VA_DRIVER(ctx);
113    mtx_lock(&drv->mutex);
114    for (i = 0; i < num_surfaces; ++i) {
115       vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]);
116       if (!surf) {
117          mtx_unlock(&drv->mutex);
118          return VA_STATUS_ERROR_INVALID_SURFACE;
119       }
120       if (surf->buffer)
121          surf->buffer->destroy(surf->buffer);
122       if (surf->ctx) {
123          assert(_mesa_set_search(surf->ctx->surfaces, surf));
124          _mesa_set_remove_key(surf->ctx->surfaces, surf);
125          if (surf->fence && surf->ctx->decoder && surf->ctx->decoder->destroy_fence)
126             surf->ctx->decoder->destroy_fence(surf->ctx->decoder, surf->fence);
127          if (surf->is_dpb)
128             vlVaRemoveDpbSurface(surf, surface_list[i]);
129       }
130       if (drv->last_efc_surface) {
131          vlVaSurface *efc_surf = drv->last_efc_surface;
132          if (efc_surf == surf || efc_surf->efc_surface == surf) {
133             efc_surf->efc_surface = NULL;
134             drv->last_efc_surface = NULL;
135             drv->efc_count = -1;
136          }
137       }
138       if (surf->coded_buf)
139          surf->coded_buf->coded_surf = NULL;
140       util_dynarray_fini(&surf->subpics);
141       FREE(surf);
142       handle_table_remove(drv->htab, surface_list[i]);
143    }
144    mtx_unlock(&drv->mutex);
145 
146    return VA_STATUS_SUCCESS;
147 }
148 
149 static VAStatus
_vlVaSyncSurface(VADriverContextP ctx,VASurfaceID render_target,uint64_t timeout_ns)150 _vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target, uint64_t timeout_ns)
151 {
152    vlVaDriver *drv;
153    vlVaContext *context;
154    vlVaSurface *surf;
155    struct pipe_fence_handle *fence;
156 
157    if (!ctx)
158       return VA_STATUS_ERROR_INVALID_CONTEXT;
159 
160    drv = VL_VA_DRIVER(ctx);
161    if (!drv)
162       return VA_STATUS_ERROR_INVALID_CONTEXT;
163 
164    mtx_lock(&drv->mutex);
165    surf = handle_table_get(drv->htab, render_target);
166    if (!surf) {
167       mtx_unlock(&drv->mutex);
168       return VA_STATUS_ERROR_INVALID_SURFACE;
169    }
170 
171    if (surf->coded_buf) {
172       context = surf->coded_buf->ctx;
173       fence = surf->coded_buf->fence;
174    } else {
175       context = surf->ctx;
176       fence = surf->fence;
177    }
178 
179    /* This is checked before getting the context below as
180     * surf->ctx is only set in begin_frame
181     * and not when the surface is created
182     * Some apps try to sync/map the surface right after creation and
183     * would get VA_STATUS_ERROR_INVALID_CONTEXT
184     */
185    if (!surf->buffer || !fence) {
186       // No outstanding encode/decode operation: nothing to do.
187       mtx_unlock(&drv->mutex);
188       return VA_STATUS_SUCCESS;
189    }
190 
191    if (!context) {
192       mtx_unlock(&drv->mutex);
193       return VA_STATUS_ERROR_INVALID_CONTEXT;
194    }
195 
196    if (!context->decoder) {
197       mtx_unlock(&drv->mutex);
198       return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
199    }
200 
201    int ret = context->decoder->fence_wait(context->decoder, fence, timeout_ns);
202    mtx_unlock(&drv->mutex);
203    return ret ? VA_STATUS_SUCCESS : VA_STATUS_ERROR_TIMEDOUT;
204 }
205 
206 VAStatus
vlVaSyncSurface(VADriverContextP ctx,VASurfaceID render_target)207 vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target)
208 {
209    return _vlVaSyncSurface(ctx, render_target, VA_TIMEOUT_INFINITE);
210 }
211 
212 #if VA_CHECK_VERSION(1, 15, 0)
213 VAStatus
vlVaSyncSurface2(VADriverContextP ctx,VASurfaceID surface,uint64_t timeout_ns)214 vlVaSyncSurface2(VADriverContextP ctx, VASurfaceID surface, uint64_t timeout_ns)
215 {
216    return _vlVaSyncSurface(ctx, surface, timeout_ns);
217 }
218 #endif
219 
220 VAStatus
vlVaQuerySurfaceStatus(VADriverContextP ctx,VASurfaceID render_target,VASurfaceStatus * status)221 vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status)
222 {
223    vlVaDriver *drv;
224    vlVaSurface *surf;
225    vlVaContext *context;
226    struct pipe_fence_handle *fence;
227 
228    if (!ctx)
229       return VA_STATUS_ERROR_INVALID_CONTEXT;
230 
231    drv = VL_VA_DRIVER(ctx);
232    if (!drv)
233       return VA_STATUS_ERROR_INVALID_CONTEXT;
234 
235    mtx_lock(&drv->mutex);
236 
237    surf = handle_table_get(drv->htab, render_target);
238    if (!surf) {
239       mtx_unlock(&drv->mutex);
240       return VA_STATUS_ERROR_INVALID_SURFACE;
241    }
242 
243    if (surf->coded_buf) {
244       context = surf->coded_buf->ctx;
245       fence = surf->coded_buf->fence;
246    } else {
247       context = surf->ctx;
248       fence = surf->fence;
249    }
250 
251    /* This is checked before getting the context below as
252     * surf->ctx is only set in begin_frame
253     * and not when the surface is created
254     * Some apps try to sync/map the surface right after creation and
255     * would get VA_STATUS_ERROR_INVALID_CONTEXT
256     */
257    if (!surf->buffer || !fence) {
258       // No outstanding encode/decode operation: nothing to do.
259       *status = VASurfaceReady;
260       mtx_unlock(&drv->mutex);
261       return VA_STATUS_SUCCESS;
262    }
263 
264    if (!context) {
265       mtx_unlock(&drv->mutex);
266       return VA_STATUS_ERROR_INVALID_CONTEXT;
267    }
268 
269    if (!context->decoder) {
270       mtx_unlock(&drv->mutex);
271       return VA_STATUS_ERROR_UNSUPPORTED_ENTRYPOINT;
272    }
273 
274    int ret = context->decoder->fence_wait(context->decoder, fence, 0);
275    mtx_unlock(&drv->mutex);
276 
277    if (ret)
278       *status = VASurfaceReady;
279    else
280       *status = VASurfaceRendering;
281 
282    return VA_STATUS_SUCCESS;
283 }
284 
285 VAStatus
vlVaQuerySurfaceError(VADriverContextP ctx,VASurfaceID render_target,VAStatus error_status,void ** error_info)286 vlVaQuerySurfaceError(VADriverContextP ctx, VASurfaceID render_target, VAStatus error_status, void **error_info)
287 {
288    if (!ctx)
289       return VA_STATUS_ERROR_INVALID_CONTEXT;
290 
291    return VA_STATUS_ERROR_UNIMPLEMENTED;
292 }
293 
294 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)295 upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst,
296                const struct pipe_box *dst_box, const void *src, unsigned src_stride,
297                unsigned src_x, unsigned src_y)
298 {
299    struct pipe_transfer *transfer;
300    void *map;
301 
302    map = pipe->texture_map(pipe, dst->texture, 0, PIPE_MAP_WRITE,
303                             dst_box, &transfer);
304    if (!map)
305       return;
306 
307    util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0,
308                   dst_box->width, dst_box->height,
309                   src, src_stride, src_x, src_y);
310 
311    pipe->texture_unmap(pipe, transfer);
312 }
313 
314 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)315 vlVaPutSubpictures(vlVaSurface *surf, vlVaDriver *drv,
316                    struct pipe_surface *surf_draw, struct u_rect *dirty_area,
317                    struct u_rect *src_rect, struct u_rect *dst_rect)
318 {
319    vlVaSubpicture *sub;
320    int i;
321 
322    for (i = 0; i < surf->subpics.size/sizeof(vlVaSubpicture *); i++) {
323       struct pipe_blend_state blend;
324       void *blend_state = NULL;
325       vlVaBuffer *buf;
326       struct pipe_box box;
327       struct u_rect *s, *d, sr, dr, c;
328       int sw, sh, dw, dh;
329 
330       sub = ((vlVaSubpicture **)surf->subpics.data)[i];
331       if (!sub)
332          continue;
333 
334       buf = handle_table_get(drv->htab, sub->image->buf);
335       if (!buf)
336          return VA_STATUS_ERROR_INVALID_IMAGE;
337 
338       box.x = 0;
339       box.y = 0;
340       box.z = 0;
341       box.width = sub->dst_rect.x1 - sub->dst_rect.x0;
342       box.height = sub->dst_rect.y1 - sub->dst_rect.y0;
343       box.depth = 1;
344 
345       s = &sub->src_rect;
346       d = &sub->dst_rect;
347       sw = s->x1 - s->x0;
348       sh = s->y1 - s->y0;
349       dw = d->x1 - d->x0;
350       dh = d->y1 - d->y0;
351       c.x0 = MAX2(d->x0, s->x0);
352       c.y0 = MAX2(d->y0, s->y0);
353       c.x1 = MIN2(d->x0 + dw, src_rect->x1);
354       c.y1 = MIN2(d->y0 + dh, src_rect->y1);
355       sr.x0 = s->x0 + (c.x0 - d->x0)*(sw/(float)dw);
356       sr.y0 = s->y0 + (c.y0 - d->y0)*(sh/(float)dh);
357       sr.x1 = s->x0 + (c.x1 - d->x0)*(sw/(float)dw);
358       sr.y1 = s->y0 + (c.y1 - d->y0)*(sh/(float)dh);
359 
360       s = src_rect;
361       d = dst_rect;
362       sw = s->x1 - s->x0;
363       sh = s->y1 - s->y0;
364       dw = d->x1 - d->x0;
365       dh = d->y1 - d->y0;
366       dr.x0 = d->x0 + c.x0*(dw/(float)sw);
367       dr.y0 = d->y0 + c.y0*(dh/(float)sh);
368       dr.x1 = d->x0 + c.x1*(dw/(float)sw);
369       dr.y1 = d->y0 + c.y1*(dh/(float)sh);
370 
371       vl_compositor_clear_layers(&drv->cstate);
372       if (drv->pipe->create_blend_state) {
373          memset(&blend, 0, sizeof(blend));
374          blend.independent_blend_enable = 0;
375          blend.rt[0].blend_enable = 1;
376          blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
377          blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
378          blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
379          blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
380          blend.rt[0].rgb_func = PIPE_BLEND_ADD;
381          blend.rt[0].alpha_func = PIPE_BLEND_ADD;
382          blend.rt[0].colormask = PIPE_MASK_RGBA;
383          blend.logicop_enable = 0;
384          blend.logicop_func = PIPE_LOGICOP_CLEAR;
385          blend.dither = 0;
386          blend_state = drv->pipe->create_blend_state(drv->pipe, &blend);
387          vl_compositor_set_layer_blend(&drv->cstate, 0, blend_state, false);
388       }
389       upload_sampler(drv->pipe, sub->sampler, &box, buf->data,
390                      sub->image->pitches[0], 0, 0);
391       vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, sub->sampler,
392                                    &sr, NULL, NULL);
393       vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dr);
394       vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, false);
395       if (blend_state)
396          drv->pipe->delete_blend_state(drv->pipe, blend_state);
397    }
398 
399    return VA_STATUS_SUCCESS;
400 }
401 
402 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)403 vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy,
404                unsigned short srcw, unsigned short srch, short destx, short desty,
405                unsigned short destw, unsigned short desth, VARectangle *cliprects,
406                unsigned int number_cliprects,  unsigned int flags)
407 {
408    vlVaDriver *drv;
409    vlVaSurface *surf;
410    struct pipe_screen *screen;
411    struct pipe_resource *tex;
412    struct pipe_surface surf_templ, *surf_draw;
413    struct vl_screen *vscreen;
414    struct u_rect src_rect, *dirty_area;
415    struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
416    enum pipe_format format;
417    VAStatus status;
418    enum VL_CSC_COLOR_STANDARD color_standard;
419 
420    if (!ctx)
421       return VA_STATUS_ERROR_INVALID_CONTEXT;
422 
423    drv = VL_VA_DRIVER(ctx);
424    mtx_lock(&drv->mutex);
425    surf = handle_table_get(drv->htab, surface_id);
426    vlVaGetSurfaceBuffer(drv, surf);
427    if (!surf || !surf->buffer) {
428       mtx_unlock(&drv->mutex);
429       return VA_STATUS_ERROR_INVALID_SURFACE;
430    }
431 
432    screen = drv->pipe->screen;
433    vscreen = drv->vscreen;
434 
435    tex = vscreen->texture_from_drawable(vscreen, draw);
436    if (!tex) {
437       mtx_unlock(&drv->mutex);
438       return VA_STATUS_ERROR_INVALID_DISPLAY;
439    }
440 
441    dirty_area = vscreen->get_dirty_area(vscreen);
442 
443    memset(&surf_templ, 0, sizeof(surf_templ));
444    surf_templ.format = tex->format;
445    surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ);
446    if (!surf_draw) {
447       pipe_resource_reference(&tex, NULL);
448       mtx_unlock(&drv->mutex);
449       return VA_STATUS_ERROR_INVALID_DISPLAY;
450    }
451 
452    src_rect.x0 = srcx;
453    src_rect.y0 = srcy;
454    src_rect.x1 = srcw + srcx;
455    src_rect.y1 = srch + srcy;
456 
457    format = surf->buffer->buffer_format;
458 
459    if (flags & VA_SRC_BT601)
460       color_standard = VL_CSC_COLOR_STANDARD_BT_601;
461    else if (flags & VA_SRC_SMPTE_240)
462       color_standard = VL_CSC_COLOR_STANDARD_SMPTE_240M;
463    else
464       color_standard = VL_CSC_COLOR_STANDARD_BT_709;
465 
466    vl_csc_get_matrix(color_standard, NULL, true, &drv->csc);
467    vl_compositor_set_csc_matrix(&drv->cstate, (const vl_csc_matrix *)&drv->csc, 1.0f, 0.0f);
468 
469    vl_compositor_clear_layers(&drv->cstate);
470 
471    if (format == PIPE_FORMAT_B8G8R8A8_UNORM || format == PIPE_FORMAT_B8G8R8X8_UNORM ||
472        format == PIPE_FORMAT_R8G8B8A8_UNORM || format == PIPE_FORMAT_R8G8B8X8_UNORM ||
473        format == PIPE_FORMAT_B10G10R10A2_UNORM || format == PIPE_FORMAT_B10G10R10X2_UNORM ||
474        format == PIPE_FORMAT_R10G10B10A2_UNORM || format == PIPE_FORMAT_R10G10B10X2_UNORM ||
475        format == PIPE_FORMAT_L8_UNORM || format == PIPE_FORMAT_Y8_400_UNORM) {
476       struct pipe_sampler_view **views;
477 
478       views = surf->buffer->get_sampler_view_planes(surf->buffer);
479       vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, views[0], &src_rect, NULL, NULL);
480    } else
481       vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
482 
483    vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
484    vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true);
485 
486    status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect);
487    if (status) {
488       mtx_unlock(&drv->mutex);
489       return status;
490    }
491 
492    if (drv->pipe->flush_resource)
493       drv->pipe->flush_resource(drv->pipe, tex);
494 
495    /* flush before calling flush_frontbuffer so that rendering is flushed
496     * to back buffer so the texture can be copied in flush_frontbuffer
497     */
498    drv->pipe->flush(drv->pipe, NULL, 0);
499 
500    screen->flush_frontbuffer(screen, drv->pipe, tex, 0, 0,
501                              vscreen->get_private(vscreen), 0, NULL);
502 
503 
504    pipe_resource_reference(&tex, NULL);
505    pipe_surface_reference(&surf_draw, NULL);
506    mtx_unlock(&drv->mutex);
507 
508    return VA_STATUS_SUCCESS;
509 }
510 
511 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)512 vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc,
513                 unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride,
514                 unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset,
515                 unsigned int *buffer_name, void **buffer)
516 {
517    if (!ctx)
518       return VA_STATUS_ERROR_INVALID_CONTEXT;
519 
520    return VA_STATUS_ERROR_UNIMPLEMENTED;
521 }
522 
523 VAStatus
vlVaUnlockSurface(VADriverContextP ctx,VASurfaceID surface)524 vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface)
525 {
526    if (!ctx)
527       return VA_STATUS_ERROR_INVALID_CONTEXT;
528 
529    return VA_STATUS_ERROR_UNIMPLEMENTED;
530 }
531 
532 static void
vlVaAddSurfaceFormat(struct pipe_screen * screen,vlVaConfig * config,enum pipe_format format,VASurfaceAttrib * attrib,int * i)533 vlVaAddSurfaceFormat(struct pipe_screen *screen, vlVaConfig *config,
534                      enum pipe_format format, VASurfaceAttrib *attrib, int *i)
535 {
536    if (!screen->is_video_format_supported(screen, format, config->profile, config->entrypoint))
537       return;
538 
539    attrib[*i].type = VASurfaceAttribPixelFormat;
540    attrib[*i].value.type = VAGenericValueTypeInteger;
541    attrib[*i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
542    attrib[*i].value.value.i = PipeFormatToVaFourcc(format);
543    (*i)++;
544 }
545 
546 VAStatus
vlVaQuerySurfaceAttributes(VADriverContextP ctx,VAConfigID config_id,VASurfaceAttrib * attrib_list,unsigned int * num_attribs)547 vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
548                            VASurfaceAttrib *attrib_list, unsigned int *num_attribs)
549 {
550    vlVaDriver *drv;
551    vlVaConfig *config;
552    VASurfaceAttrib *attribs;
553    struct pipe_screen *pscreen;
554    int i;
555 
556    if (config_id == VA_INVALID_ID)
557       return VA_STATUS_ERROR_INVALID_CONFIG;
558 
559    if (!attrib_list && !num_attribs)
560       return VA_STATUS_ERROR_INVALID_PARAMETER;
561 
562    if (!attrib_list) {
563       *num_attribs = VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount;
564       return VA_STATUS_SUCCESS;
565    }
566 
567    if (!ctx)
568       return VA_STATUS_ERROR_INVALID_CONTEXT;
569 
570    drv = VL_VA_DRIVER(ctx);
571 
572    if (!drv)
573       return VA_STATUS_ERROR_INVALID_CONTEXT;
574 
575    mtx_lock(&drv->mutex);
576    config = handle_table_get(drv->htab, config_id);
577    mtx_unlock(&drv->mutex);
578 
579    if (!config)
580       return VA_STATUS_ERROR_INVALID_CONFIG;
581 
582    pscreen = VL_VA_PSCREEN(ctx);
583 
584    if (!pscreen)
585       return VA_STATUS_ERROR_INVALID_CONTEXT;
586 
587    attribs = CALLOC(VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount,
588                     sizeof(VASurfaceAttrib));
589 
590    if (!attribs)
591       return VA_STATUS_ERROR_ALLOCATION_FAILED;
592 
593    i = 0;
594 
595    if (config->rt_format & VA_RT_FORMAT_YUV420) {
596       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_NV12, attribs, &i);
597       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_YV12, attribs, &i);
598       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_IYUV, attribs, &i);
599    }
600 
601    if (config->rt_format & VA_RT_FORMAT_YUV420_10) {
602       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_P010, attribs, &i);
603       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_P016, attribs, &i);
604    }
605 
606    if (config->rt_format & VA_RT_FORMAT_YUV420_12)
607       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_P012, attribs, &i);
608 
609    if (config->rt_format & VA_RT_FORMAT_YUV400)
610       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_Y8_400_UNORM, attribs, &i);
611 
612    if (config->rt_format & VA_RT_FORMAT_YUV422) {
613       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_UYVY, attribs, &i);
614       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_YUYV, attribs, &i);
615       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_Y8_U8_V8_440_UNORM, attribs, &i);
616    }
617 
618    if (config->rt_format & VA_RT_FORMAT_YUV444)
619       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_Y8_U8_V8_444_UNORM, attribs, &i);
620 
621    if (config->rt_format & VA_RT_FORMAT_RGBP)
622       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_R8_G8_B8_UNORM, attribs, &i);
623 
624    if (config->rt_format & VA_RT_FORMAT_RGB32) {
625       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_R8G8B8A8_UNORM, attribs, &i);
626       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_B8G8R8A8_UNORM, attribs, &i);
627       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_R8G8B8X8_UNORM, attribs, &i);
628       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_B8G8R8X8_UNORM, attribs, &i);
629    }
630 
631    if (config->rt_format & VA_RT_FORMAT_RGB32_10) {
632       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_R10G10B10A2_UNORM, attribs, &i);
633       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_B10G10R10A2_UNORM, attribs, &i);
634       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_R10G10B10X2_UNORM, attribs, &i);
635       vlVaAddSurfaceFormat(pscreen, config, PIPE_FORMAT_B10G10R10X2_UNORM, attribs, &i);
636    }
637 
638    attribs[i].type = VASurfaceAttribMemoryType;
639    attribs[i].value.type = VAGenericValueTypeInteger;
640    attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
641    attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA |
642 #ifdef _WIN32
643          VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE |
644          VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE;
645 #else
646          VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME |
647 #if VA_CHECK_VERSION(1, 21, 0)
648          VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3 |
649 #endif
650          VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2;
651 #endif
652    i++;
653 
654    attribs[i].type = VASurfaceAttribExternalBufferDescriptor;
655    attribs[i].value.type = VAGenericValueTypePointer;
656    attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
657    attribs[i].value.value.p = NULL; /* ignore */
658    i++;
659 
660 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
661    if (drv->pipe->create_video_buffer_with_modifiers) {
662       attribs[i].type = VASurfaceAttribDRMFormatModifiers;
663       attribs[i].value.type = VAGenericValueTypePointer;
664       attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
665       attribs[i].value.value.p = NULL; /* ignore */
666       i++;
667    }
668 #endif
669 
670    /* If VPP supported entry, use the max dimensions cap values, if not fallback to this below */
671    if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_PROCESSING ||
672        pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
673                                 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
674                                 PIPE_VIDEO_CAP_SUPPORTED))
675    {
676       unsigned min_width, min_height;
677       min_width = pscreen->get_video_param(pscreen,
678                                   config->profile, config->entrypoint,
679                                   PIPE_VIDEO_CAP_MIN_WIDTH);
680       min_height = pscreen->get_video_param(pscreen,
681                                   config->profile, config->entrypoint,
682                                   PIPE_VIDEO_CAP_MIN_HEIGHT);
683 
684       if (min_width > 0 && min_height > 0) {
685          attribs[i].type = VASurfaceAttribMinWidth;
686          attribs[i].value.type = VAGenericValueTypeInteger;
687          attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
688          attribs[i].value.value.i = min_width;
689          i++;
690 
691          attribs[i].type = VASurfaceAttribMinHeight;
692          attribs[i].value.type = VAGenericValueTypeInteger;
693          attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
694          attribs[i].value.value.i = min_height;
695          i++;
696       }
697 
698       attribs[i].type = VASurfaceAttribMaxWidth;
699       attribs[i].value.type = VAGenericValueTypeInteger;
700       attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
701       attribs[i].value.value.i =
702          pscreen->get_video_param(pscreen,
703                                   config->profile, config->entrypoint,
704                                   PIPE_VIDEO_CAP_MAX_WIDTH);
705       i++;
706 
707       attribs[i].type = VASurfaceAttribMaxHeight;
708       attribs[i].value.type = VAGenericValueTypeInteger;
709       attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
710       attribs[i].value.value.i =
711          pscreen->get_video_param(pscreen,
712                                   config->profile, config->entrypoint,
713                                   PIPE_VIDEO_CAP_MAX_HEIGHT);
714       i++;
715 #if VA_CHECK_VERSION(1, 21, 0)
716       int surface_alignment =
717          pscreen->get_video_param(pscreen,
718                                   config->profile, config->entrypoint,
719                                   PIPE_VIDEO_CAP_ENC_SURFACE_ALIGNMENT);
720       if (surface_alignment > 0) {
721          attribs[i].type = VASurfaceAttribAlignmentSize;
722          attribs[i].value.type = VAGenericValueTypeInteger;
723          attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
724          attribs[i].value.value.i = surface_alignment;
725          i++;
726       }
727 #endif
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(VADriverContextP ctx,vlVaSurface * surface,VADRMPRIMESurfaceDescriptor * desc,int mem_type,struct pipe_video_buffer * templat)845 surface_from_prime(VADriverContextP ctx, vlVaSurface *surface,
846                    VADRMPRIMESurfaceDescriptor *desc, int mem_type,
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    if (drv->pipe->screen->get_video_param(drv->pipe->screen,
1032                                           PIPE_VIDEO_PROFILE_UNKNOWN,
1033                                           PIPE_VIDEO_ENTRYPOINT_UNKNOWN,
1034                                           PIPE_VIDEO_CAP_SKIP_CLEAR_SURFACE))
1035       return VA_STATUS_SUCCESS;
1036 
1037    surfaces = surface->buffer->get_surfaces(surface->buffer);
1038    if (surfaces) {
1039       for (i = 0; i < VL_MAX_SURFACES; ++i) {
1040          union pipe_color_union c;
1041          memset(&c, 0, sizeof(c));
1042 
1043          if (!surfaces[i])
1044             continue;
1045 
1046          if (i > !!surface->buffer->interlaced)
1047             c.f[0] = c.f[1] = c.f[2] = c.f[3] = 0.5f;
1048 
1049          drv->pipe->clear_render_target(drv->pipe, surfaces[i], &c, 0, 0,
1050                   surfaces[i]->width, surfaces[i]->height,
1051                   false);
1052       }
1053       drv->pipe->flush(drv->pipe, NULL, 0);
1054    }
1055 
1056    return VA_STATUS_SUCCESS;
1057 }
1058 
1059 struct pipe_video_buffer *
vlVaGetSurfaceBuffer(vlVaDriver * drv,vlVaSurface * surface)1060 vlVaGetSurfaceBuffer(vlVaDriver *drv, vlVaSurface *surface)
1061 {
1062    if (!surface)
1063       return NULL;
1064    if (surface->buffer)
1065       return surface->buffer;
1066    vlVaHandleSurfaceAllocate(drv, surface, &surface->templat, NULL, 0);
1067    return surface->buffer;
1068 }
1069 
1070 static int
rt_format_to_fourcc(uint32_t format)1071 rt_format_to_fourcc(uint32_t format)
1072 {
1073    switch (format) {
1074    case VA_RT_FORMAT_YUV420:
1075       return VA_FOURCC_NV12;
1076    case VA_RT_FORMAT_YUV420_10:
1077       return VA_FOURCC_P010;
1078    case VA_RT_FORMAT_YUV420_12:
1079       return VA_FOURCC_P012;
1080    case VA_RT_FORMAT_YUV422:
1081       return VA_FOURCC_YUY2;
1082    case VA_RT_FORMAT_YUV444:
1083       return VA_FOURCC_444P;
1084    case VA_RT_FORMAT_YUV400:
1085       return VA_FOURCC_Y800;
1086    case VA_RT_FORMAT_RGBP:
1087       return VA_FOURCC_RGBP;
1088    case VA_RT_FORMAT_RGB32:
1089       return VA_FOURCC_BGRA;
1090    case VA_RT_FORMAT_RGB32_10:
1091       return VA_FOURCC_X2R10G10B10;
1092    default:
1093       return 0;
1094    }
1095 }
1096 
1097 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)1098 vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
1099                     unsigned int width, unsigned int height,
1100                     VASurfaceID *surfaces, unsigned int num_surfaces,
1101                     VASurfaceAttrib *attrib_list, unsigned int num_attribs)
1102 {
1103    vlVaDriver *drv;
1104    VASurfaceAttribExternalBuffers *memory_attribute;
1105 #ifdef _WIN32
1106    void **win32_handles;
1107 #else
1108    VADRMPRIMESurfaceDescriptor *prime_desc = NULL;
1109 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
1110    const VADRMFormatModifierList *modifier_list;
1111 #endif
1112 #endif
1113    struct pipe_video_buffer templat = {0};
1114    struct pipe_screen *pscreen;
1115    int i;
1116    int memory_type;
1117    int expected_fourcc;
1118    VAStatus vaStatus;
1119    vlVaSurface *surf;
1120    bool protected;
1121    const uint64_t *modifiers;
1122    unsigned int modifiers_count;
1123 
1124    if (!ctx)
1125       return VA_STATUS_ERROR_INVALID_CONTEXT;
1126 
1127    if (!(width && height))
1128       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
1129 
1130    drv = VL_VA_DRIVER(ctx);
1131 
1132    if (!drv)
1133       return VA_STATUS_ERROR_INVALID_CONTEXT;
1134 
1135    pscreen = VL_VA_PSCREEN(ctx);
1136 
1137    if (!pscreen)
1138       return VA_STATUS_ERROR_INVALID_CONTEXT;
1139 
1140    /* Default. */
1141    memory_attribute = NULL;
1142    memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
1143    expected_fourcc = 0;
1144    modifiers = NULL;
1145    modifiers_count = 0;
1146 
1147    protected = format & VA_RT_FORMAT_PROTECTED;
1148    format &= ~VA_RT_FORMAT_PROTECTED;
1149 
1150    expected_fourcc = rt_format_to_fourcc(format);
1151    if (!expected_fourcc)
1152       return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
1153 
1154    for (i = 0; i < num_attribs && attrib_list; i++) {
1155       if (!(attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE))
1156          continue;
1157 
1158       switch (attrib_list[i].type) {
1159       case VASurfaceAttribPixelFormat:
1160          if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1161             return VA_STATUS_ERROR_INVALID_PARAMETER;
1162          expected_fourcc = attrib_list[i].value.value.i;
1163          break;
1164       case VASurfaceAttribMemoryType:
1165          if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1166             return VA_STATUS_ERROR_INVALID_PARAMETER;
1167 
1168          switch (attrib_list[i].value.value.i) {
1169          case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1170 
1171 #ifdef _WIN32
1172          case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1173          case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1174 #else
1175          case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1176          case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1177          case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3:
1178 #endif
1179             memory_type = attrib_list[i].value.value.i;
1180             break;
1181          default:
1182             return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1183          }
1184          break;
1185       case VASurfaceAttribExternalBufferDescriptor:
1186          if (attrib_list[i].value.type != VAGenericValueTypePointer)
1187             return VA_STATUS_ERROR_INVALID_PARAMETER;
1188 #ifndef _WIN32
1189          if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 ||
1190              memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3)
1191             prime_desc = (VADRMPRIMESurfaceDescriptor *)attrib_list[i].value.value.p;
1192 #else
1193          else if (memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE ||
1194                   memory_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1195             win32_handles = (void**) attrib_list[i].value.value.p;
1196 #endif
1197          else
1198             memory_attribute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
1199          break;
1200 #ifndef _WIN32
1201 #ifdef HAVE_VA_SURFACE_ATTRIB_DRM_FORMAT_MODIFIERS
1202       case VASurfaceAttribDRMFormatModifiers:
1203          if (attrib_list[i].value.type != VAGenericValueTypePointer)
1204             return VA_STATUS_ERROR_INVALID_PARAMETER;
1205          modifier_list = attrib_list[i].value.value.p;
1206          if (modifier_list != NULL) {
1207             modifiers = modifier_list->modifiers;
1208             modifiers_count = modifier_list->num_modifiers;
1209          }
1210          break;
1211 #endif
1212 #endif
1213       case VASurfaceAttribUsageHint:
1214          if (attrib_list[i].value.type != VAGenericValueTypeInteger)
1215             return VA_STATUS_ERROR_INVALID_PARAMETER;
1216          break;
1217       default:
1218          return VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
1219       }
1220    }
1221 
1222    switch (memory_type) {
1223    case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1224       break;
1225 #ifdef _WIN32
1226          case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1227          case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1228          if (!win32_handles)
1229             return VA_STATUS_ERROR_INVALID_PARAMETER;
1230          break;
1231 #else
1232    case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1233       if (!memory_attribute)
1234          return VA_STATUS_ERROR_INVALID_PARAMETER;
1235       if (modifiers)
1236          return VA_STATUS_ERROR_INVALID_PARAMETER;
1237 
1238       expected_fourcc = memory_attribute->pixel_format;
1239       break;
1240    case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1241    case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3:
1242       /* If we don't have surface descriptor, use it as a hint
1243        * that application will export the surface later. */
1244       if (!prime_desc) {
1245          templat.bind |= PIPE_BIND_SHARED;
1246          memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
1247       } else {
1248          expected_fourcc = prime_desc->fourcc;
1249       }
1250       break;
1251 #endif
1252    default:
1253       assert(0);
1254    }
1255 
1256    if (!modifiers)
1257       templat.interlaced =
1258          !pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1259                                    PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
1260                                    PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE);
1261 
1262 #ifndef _WIN32
1263    if (expected_fourcc != VA_FOURCC_NV12 || memory_attribute || prime_desc)
1264 #else
1265    if (expected_fourcc != VA_FOURCC_NV12 || memory_attribute)
1266 #endif
1267      templat.interlaced = false;
1268 
1269    templat.buffer_format = VaFourccToPipeFormat(expected_fourcc);
1270    templat.width = width;
1271    templat.height = height;
1272    if (protected)
1273       templat.bind |= PIPE_BIND_PROTECTED;
1274 
1275    memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID));
1276 
1277    mtx_lock(&drv->mutex);
1278    for (i = 0; i < num_surfaces; i++) {
1279       surf = CALLOC(1, sizeof(vlVaSurface));
1280       if (!surf) {
1281          vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
1282          goto no_res;
1283       }
1284 
1285       surf->templat = templat;
1286 
1287       switch (memory_type) {
1288       case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
1289          /* The application will clear the TILING flag when the surface is
1290           * intended to be exported as dmabuf. Adding shared flag because not
1291           * null memory_attribute means VASurfaceAttribExternalBuffers is used.
1292           */
1293          if (memory_attribute &&
1294              !(memory_attribute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING))
1295             surf->templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED;
1296 
1297          if (modifiers) {
1298             vaStatus = vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, modifiers,
1299                                                  modifiers_count);
1300             if (vaStatus != VA_STATUS_SUCCESS)
1301                goto free_surf;
1302          } /* Delayed allocation from vlVaGetSurfaceBuffer otherwise */
1303          break;
1304 
1305 #ifdef _WIN32
1306       case VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE:
1307       case VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE:
1308          vaStatus = surface_from_external_win32_memory(ctx, surf, memory_type, win32_handles[i], &templat);
1309          if (vaStatus != VA_STATUS_SUCCESS)
1310             goto free_surf;
1311          break;
1312 #else
1313       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
1314          vaStatus = surface_from_external_memory(ctx, surf, memory_attribute, i, &templat);
1315          if (vaStatus != VA_STATUS_SUCCESS)
1316             goto free_surf;
1317          break;
1318 
1319       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2:
1320       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3:
1321          vaStatus = surface_from_prime(ctx, surf, prime_desc, memory_type, &templat);
1322          if (vaStatus != VA_STATUS_SUCCESS)
1323             goto free_surf;
1324          break;
1325 #endif
1326       default:
1327          assert(0);
1328       }
1329 
1330       util_dynarray_init(&surf->subpics, NULL);
1331       surfaces[i] = handle_table_add(drv->htab, surf);
1332       if (!surfaces[i]) {
1333          vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
1334          goto destroy_surf;
1335       }
1336    }
1337 
1338    if (memory_type != VA_SURFACE_ATTRIB_MEM_TYPE_VA)
1339       drv->has_external_handles = true;
1340    mtx_unlock(&drv->mutex);
1341 
1342    return VA_STATUS_SUCCESS;
1343 
1344 destroy_surf:
1345    if (surf->buffer)
1346       surf->buffer->destroy(surf->buffer);
1347 
1348 free_surf:
1349    FREE(surf);
1350 
1351 no_res:
1352    mtx_unlock(&drv->mutex);
1353    if (i)
1354       vlVaDestroySurfaces(ctx, surfaces, i);
1355 
1356    return vaStatus;
1357 }
1358 
1359 VAStatus
vlVaQueryVideoProcFilters(VADriverContextP ctx,VAContextID context,VAProcFilterType * filters,unsigned int * num_filters)1360 vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context,
1361                           VAProcFilterType *filters, unsigned int *num_filters)
1362 {
1363    unsigned int num = 0;
1364 
1365    if (!ctx)
1366       return VA_STATUS_ERROR_INVALID_CONTEXT;
1367 
1368    if (!num_filters || !filters)
1369       return VA_STATUS_ERROR_INVALID_PARAMETER;
1370 
1371    filters[num++] = VAProcFilterDeinterlacing;
1372 
1373    *num_filters = num;
1374 
1375    return VA_STATUS_SUCCESS;
1376 }
1377 
1378 VAStatus
vlVaQueryVideoProcFilterCaps(VADriverContextP ctx,VAContextID context,VAProcFilterType type,void * filter_caps,unsigned int * num_filter_caps)1379 vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context,
1380                              VAProcFilterType type, void *filter_caps,
1381                              unsigned int *num_filter_caps)
1382 {
1383    unsigned int i;
1384 
1385    if (!ctx)
1386       return VA_STATUS_ERROR_INVALID_CONTEXT;
1387 
1388    if (!filter_caps || !num_filter_caps)
1389       return VA_STATUS_ERROR_INVALID_PARAMETER;
1390 
1391    i = 0;
1392 
1393    switch (type) {
1394    case VAProcFilterNone:
1395       break;
1396    case VAProcFilterDeinterlacing: {
1397       VAProcFilterCapDeinterlacing *deint = filter_caps;
1398 
1399       if (*num_filter_caps < 3) {
1400          *num_filter_caps = 3;
1401          return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
1402       }
1403 
1404       deint[i++].type = VAProcDeinterlacingBob;
1405       deint[i++].type = VAProcDeinterlacingWeave;
1406       deint[i++].type = VAProcDeinterlacingMotionAdaptive;
1407       break;
1408    }
1409 
1410    case VAProcFilterNoiseReduction:
1411    case VAProcFilterSharpening:
1412    case VAProcFilterColorBalance:
1413    case VAProcFilterSkinToneEnhancement:
1414       return VA_STATUS_ERROR_UNIMPLEMENTED;
1415    default:
1416       assert(0);
1417    }
1418 
1419    *num_filter_caps = i;
1420 
1421    return VA_STATUS_SUCCESS;
1422 }
1423 
1424 static VAProcColorStandardType vpp_input_color_standards[] = {
1425    VAProcColorStandardBT601,
1426    VAProcColorStandardBT709
1427 };
1428 
1429 static VAProcColorStandardType vpp_output_color_standards[] = {
1430    VAProcColorStandardBT601,
1431    VAProcColorStandardBT709
1432 };
1433 
1434 static VAProcColorStandardType vpp_input_color_standards_extends[] = {
1435    VAProcColorStandardBT601,
1436    VAProcColorStandardBT709,
1437    VAProcColorStandardBT2020,
1438    VAProcColorStandardExplicit
1439 };
1440 
1441 static VAProcColorStandardType vpp_output_color_standards_extends[] = {
1442    VAProcColorStandardBT601,
1443    VAProcColorStandardBT709,
1444    VAProcColorStandardBT2020,
1445    VAProcColorStandardExplicit
1446 };
1447 
1448 VAStatus
vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx,VAContextID context,VABufferID * filters,unsigned int num_filters,VAProcPipelineCaps * pipeline_cap)1449 vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
1450                                VABufferID *filters, unsigned int num_filters,
1451                                VAProcPipelineCaps *pipeline_cap)
1452 {
1453    unsigned int i = 0;
1454 
1455    if (!ctx)
1456       return VA_STATUS_ERROR_INVALID_CONTEXT;
1457 
1458    if (!pipeline_cap)
1459       return VA_STATUS_ERROR_INVALID_PARAMETER;
1460 
1461    if (num_filters && !filters)
1462       return VA_STATUS_ERROR_INVALID_PARAMETER;
1463 
1464    pipeline_cap->pipeline_flags = 0;
1465    pipeline_cap->filter_flags = 0;
1466    pipeline_cap->num_forward_references = 0;
1467    pipeline_cap->num_backward_references = 0;
1468 
1469    struct pipe_screen *pscreen = VL_VA_PSCREEN(ctx);
1470    uint32_t pipe_orientation_flags = pscreen->get_video_param(pscreen,
1471                                                               PIPE_VIDEO_PROFILE_UNKNOWN,
1472                                                               PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1473                                                               PIPE_VIDEO_CAP_VPP_ORIENTATION_MODES);
1474 
1475    pipeline_cap->rotation_flags = VA_ROTATION_NONE;
1476    if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_90)
1477       pipeline_cap->rotation_flags |= (1 << VA_ROTATION_90);
1478    if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_180)
1479       pipeline_cap->rotation_flags |= (1 << VA_ROTATION_180);
1480    if(pipe_orientation_flags & PIPE_VIDEO_VPP_ROTATION_270)
1481       pipeline_cap->rotation_flags |= (1 << VA_ROTATION_270);
1482 
1483    pipeline_cap->mirror_flags = VA_MIRROR_NONE;
1484    if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_HORIZONTAL)
1485       pipeline_cap->mirror_flags |= VA_MIRROR_HORIZONTAL;
1486    if(pipe_orientation_flags & PIPE_VIDEO_VPP_FLIP_VERTICAL)
1487       pipeline_cap->mirror_flags |= VA_MIRROR_VERTICAL;
1488 
1489    if (pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1490                                 PIPE_VIDEO_CAP_VPP_SUPPORT_HDR_INPUT)) {
1491       pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards_extends);
1492       pipeline_cap->input_color_standards = vpp_input_color_standards_extends;
1493    } else {
1494       pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards);
1495       pipeline_cap->input_color_standards = vpp_input_color_standards;
1496    }
1497    if (pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1498                                 PIPE_VIDEO_CAP_VPP_SUPPORT_HDR_OUTPUT)) {
1499       pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards_extends);
1500       pipeline_cap->output_color_standards = vpp_output_color_standards_extends;
1501    } else {
1502       pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
1503       pipeline_cap->output_color_standards = vpp_output_color_standards;
1504    }
1505 
1506    pipeline_cap->max_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1507                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1508                                                             PIPE_VIDEO_CAP_VPP_MAX_INPUT_WIDTH);
1509 
1510    pipeline_cap->max_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1511                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1512                                                              PIPE_VIDEO_CAP_VPP_MAX_INPUT_HEIGHT);
1513 
1514    pipeline_cap->min_input_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1515                                                             PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1516                                                             PIPE_VIDEO_CAP_VPP_MIN_INPUT_WIDTH);
1517 
1518    pipeline_cap->min_input_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1519                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1520                                                              PIPE_VIDEO_CAP_VPP_MIN_INPUT_HEIGHT);
1521 
1522    pipeline_cap->max_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1523                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1524                                                              PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_WIDTH);
1525 
1526    pipeline_cap->max_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1527                                                               PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1528                                                               PIPE_VIDEO_CAP_VPP_MAX_OUTPUT_HEIGHT);
1529 
1530    pipeline_cap->min_output_width = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1531                                                              PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1532                                                              PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_WIDTH);
1533 
1534    pipeline_cap->min_output_height = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1535                                                               PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1536                                                               PIPE_VIDEO_CAP_VPP_MIN_OUTPUT_HEIGHT);
1537 
1538    uint32_t pipe_blend_modes = pscreen->get_video_param(pscreen, PIPE_VIDEO_PROFILE_UNKNOWN,
1539                                                         PIPE_VIDEO_ENTRYPOINT_PROCESSING,
1540                                                         PIPE_VIDEO_CAP_VPP_BLEND_MODES);
1541 
1542    pipeline_cap->blend_flags = 0;
1543    if (pipe_blend_modes & PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA)
1544       pipeline_cap->blend_flags |= VA_BLEND_GLOBAL_ALPHA;
1545 
1546    vlVaDriver *drv = VL_VA_DRIVER(ctx);
1547 
1548    mtx_lock(&drv->mutex);
1549    for (i = 0; i < num_filters; i++) {
1550       vlVaBuffer *buf = handle_table_get(drv->htab, filters[i]);
1551       VAProcFilterParameterBufferBase *filter;
1552 
1553       if (!buf || buf->type != VAProcFilterParameterBufferType) {
1554          mtx_unlock(&drv->mutex);
1555          return VA_STATUS_ERROR_INVALID_BUFFER;
1556       }
1557 
1558       filter = buf->data;
1559       switch (filter->type) {
1560       case VAProcFilterDeinterlacing: {
1561          VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
1562          if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) {
1563             pipeline_cap->num_forward_references = 2;
1564             pipeline_cap->num_backward_references = 1;
1565          }
1566          break;
1567       }
1568       default:
1569          mtx_unlock(&drv->mutex);
1570          return VA_STATUS_ERROR_UNIMPLEMENTED;
1571       }
1572    }
1573    mtx_unlock(&drv->mutex);
1574 
1575    return VA_STATUS_SUCCESS;
1576 }
1577 
1578 #ifndef _WIN32
pipe_format_to_drm_format(enum pipe_format format)1579 static uint32_t pipe_format_to_drm_format(enum pipe_format format)
1580 {
1581    switch (format) {
1582    case PIPE_FORMAT_R8_UNORM:
1583       return DRM_FORMAT_R8;
1584    case PIPE_FORMAT_R8G8_UNORM:
1585       return DRM_FORMAT_GR88;
1586    case PIPE_FORMAT_R16_UNORM:
1587       return DRM_FORMAT_R16;
1588    case PIPE_FORMAT_R16G16_UNORM:
1589       return DRM_FORMAT_GR1616;
1590    case PIPE_FORMAT_B8G8R8A8_UNORM:
1591       return DRM_FORMAT_ARGB8888;
1592    case PIPE_FORMAT_R8G8B8A8_UNORM:
1593       return DRM_FORMAT_ABGR8888;
1594    case PIPE_FORMAT_B8G8R8X8_UNORM:
1595       return DRM_FORMAT_XRGB8888;
1596    case PIPE_FORMAT_R8G8B8X8_UNORM:
1597       return DRM_FORMAT_XBGR8888;
1598    case PIPE_FORMAT_B10G10R10A2_UNORM:
1599       return DRM_FORMAT_ARGB2101010;
1600    case PIPE_FORMAT_R10G10B10A2_UNORM:
1601       return DRM_FORMAT_ABGR2101010;
1602    case PIPE_FORMAT_B10G10R10X2_UNORM:
1603       return DRM_FORMAT_XRGB2101010;
1604    case PIPE_FORMAT_R10G10B10X2_UNORM:
1605       return DRM_FORMAT_XBGR2101010;
1606    case PIPE_FORMAT_NV12:
1607       return DRM_FORMAT_NV12;
1608    case PIPE_FORMAT_P010:
1609       return DRM_FORMAT_P010;
1610    case PIPE_FORMAT_P012:
1611       return DRM_FORMAT_P012;
1612    case PIPE_FORMAT_YUYV:
1613    case PIPE_FORMAT_R8G8_R8B8_UNORM:
1614       return DRM_FORMAT_YUYV;
1615    default:
1616       return DRM_FORMAT_INVALID;
1617    }
1618 }
1619 #endif
1620 
1621 #if VA_CHECK_VERSION(1, 1, 0)
1622 VAStatus
vlVaExportSurfaceHandle(VADriverContextP ctx,VASurfaceID surface_id,uint32_t mem_type,uint32_t flags,void * descriptor)1623 vlVaExportSurfaceHandle(VADriverContextP ctx,
1624                         VASurfaceID surface_id,
1625                         uint32_t mem_type,
1626                         uint32_t flags,
1627                         void *descriptor)
1628 {
1629    vlVaDriver *drv;
1630    vlVaSurface *surf;
1631    struct pipe_surface **surfaces;
1632    struct pipe_screen *screen;
1633    VAStatus ret;
1634    unsigned int usage;
1635 
1636 #ifdef _WIN32
1637    if ((mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1638       && (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE))
1639       return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1640 
1641    if ((flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) == 0)
1642       return VA_STATUS_ERROR_INVALID_SURFACE;
1643 #else
1644    int i, p;
1645    if (mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 &&
1646        mem_type != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3)
1647       return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1648 #endif
1649 
1650    drv    = VL_VA_DRIVER(ctx);
1651    screen = VL_VA_PSCREEN(ctx);
1652    mtx_lock(&drv->mutex);
1653 
1654    surf = handle_table_get(drv->htab, surface_id);
1655    vlVaGetSurfaceBuffer(drv, surf);
1656    if (!surf || !surf->buffer) {
1657       mtx_unlock(&drv->mutex);
1658       return VA_STATUS_ERROR_INVALID_SURFACE;
1659    }
1660 
1661    if (surf->buffer->interlaced) {
1662       mtx_unlock(&drv->mutex);
1663       return VA_STATUS_ERROR_INVALID_SURFACE;
1664    }
1665 
1666    surfaces = surf->buffer->get_surfaces(surf->buffer);
1667 
1668    usage = 0;
1669    if (flags & VA_EXPORT_SURFACE_WRITE_ONLY)
1670       usage |= PIPE_HANDLE_USAGE_FRAMEBUFFER_WRITE;
1671 
1672 #ifdef _WIN32
1673    struct winsys_handle whandle;
1674    memset(&whandle, 0, sizeof(struct winsys_handle));
1675    struct pipe_resource *resource = surfaces[0]->texture;
1676 
1677    if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1678       whandle.type = WINSYS_HANDLE_TYPE_FD;
1679    else if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1680       whandle.type = WINSYS_HANDLE_TYPE_D3D12_RES;
1681 
1682    if (!screen->resource_get_handle(screen, drv->pipe, resource,
1683                                     &whandle, usage)) {
1684       ret = VA_STATUS_ERROR_INVALID_SURFACE;
1685       goto fail;
1686    }
1687 
1688    if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE)
1689       *(HANDLE**)descriptor = whandle.handle;
1690    else if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_D3D12_RESOURCE)
1691       *(void**) descriptor = whandle.com_obj;
1692 
1693 #else
1694    VADRMPRIMESurfaceDescriptor *desc = descriptor;
1695    desc->fourcc = PipeFormatToVaFourcc(surf->buffer->buffer_format);
1696    desc->width = surf->templat.width;
1697    desc->height = surf->templat.height;
1698    desc->num_objects = 0;
1699 
1700    bool supports_contiguous_planes = screen->resource_get_info && surf->buffer->contiguous_planes;
1701 
1702    for (p = 0; p < ARRAY_SIZE(desc->objects); p++) {
1703       struct winsys_handle whandle;
1704       struct pipe_resource *resource;
1705       uint32_t drm_format;
1706 
1707       if (!surfaces[p])
1708          break;
1709 
1710       resource = surfaces[p]->texture;
1711 
1712       drm_format = pipe_format_to_drm_format(resource->format);
1713       if (drm_format == DRM_FORMAT_INVALID) {
1714          ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1715          goto fail;
1716       }
1717 
1718       /* If the driver stores all planes contiguously in memory, only one
1719        * handle needs to be exported. resource_get_info is used to obtain
1720        * pitch and offset for each layer. */
1721       if (!desc->num_objects || !supports_contiguous_planes) {
1722          memset(&whandle, 0, sizeof(whandle));
1723          whandle.type = WINSYS_HANDLE_TYPE_FD;
1724 
1725          if (!screen->resource_get_handle(screen, drv->pipe, resource,
1726                                           &whandle, usage)) {
1727             ret = VA_STATUS_ERROR_INVALID_SURFACE;
1728             goto fail;
1729          }
1730 
1731          desc->objects[desc->num_objects].fd = (int) whandle.handle;
1732          /* As per VADRMPRIMESurfaceDescriptor documentation, size must be the
1733          * "Total size of this object (may include regions which are not part
1734          * of the surface)."" */
1735          desc->objects[desc->num_objects].size = (uint32_t) whandle.size;
1736          desc->objects[desc->num_objects].drm_format_modifier = whandle.modifier;
1737 
1738          desc->num_objects++;
1739       }
1740 
1741       if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) {
1742          desc->layers[0].object_index[p] = desc->num_objects - 1;
1743 
1744          if (supports_contiguous_planes) {
1745             screen->resource_get_info(screen, resource, &desc->layers[0].pitch[p], &desc->layers[0].offset[p]);
1746          } else {
1747             desc->layers[0].pitch[p] = whandle.stride;
1748             desc->layers[0].offset[p] = whandle.offset;
1749          }
1750       } else {
1751          desc->layers[p].drm_format      = drm_format;
1752          desc->layers[p].num_planes      = 1;
1753          desc->layers[p].object_index[0] = desc->num_objects - 1;
1754 
1755          if (supports_contiguous_planes) {
1756             screen->resource_get_info(screen, resource, &desc->layers[p].pitch[0], &desc->layers[p].offset[0]);
1757          } else {
1758             desc->layers[p].pitch[0] = whandle.stride;
1759             desc->layers[p].offset[0] = whandle.offset;
1760          }
1761       }
1762    }
1763 
1764    if (flags & VA_EXPORT_SURFACE_COMPOSED_LAYERS) {
1765       uint32_t drm_format = pipe_format_to_drm_format(surf->buffer->buffer_format);
1766       if (drm_format == DRM_FORMAT_INVALID) {
1767          ret = VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
1768          goto fail;
1769       }
1770 
1771       desc->num_layers = 1;
1772       desc->layers[0].drm_format = drm_format;
1773       desc->layers[0].num_planes = p;
1774    } else {
1775       desc->num_layers = p;
1776    }
1777 
1778 #if VA_CHECK_VERSION(1, 21, 0)
1779    if (mem_type == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3) {
1780       VADRMPRIME3SurfaceDescriptor *desc3 = descriptor;
1781       memset(desc3->reserved, 0, sizeof(desc3->reserved));
1782       desc3->flags = 0;
1783       if (surf->templat.bind & PIPE_BIND_PROTECTED)
1784          desc3->flags |= VA_SURFACE_EXTBUF_DESC_PROTECTED;
1785    }
1786 #endif
1787 
1788 #endif
1789 
1790    drv->has_external_handles = true;
1791    mtx_unlock(&drv->mutex);
1792 
1793    return VA_STATUS_SUCCESS;
1794 
1795 fail:
1796 #ifndef _WIN32
1797    for (i = 0; i < desc->num_objects; i++)
1798       close(desc->objects[i].fd);
1799 #else
1800    if(whandle.handle)
1801       CloseHandle(whandle.handle);
1802 #endif
1803 
1804    mtx_unlock(&drv->mutex);
1805 
1806    return ret;
1807 }
1808 #endif
1809