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