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