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