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