• 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 "state_tracker/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 
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 DEBUG_GET_ONCE_BOOL_OPTION(nointerlace, "VAAPI_DISABLE_INTERLACE", FALSE);
47 
48 #include <va/va_drmcommon.h>
49 
50 static const enum pipe_format vpp_surface_formats[] = {
51    PIPE_FORMAT_B8G8R8A8_UNORM, PIPE_FORMAT_R8G8B8A8_UNORM,
52    PIPE_FORMAT_B8G8R8X8_UNORM, PIPE_FORMAT_R8G8B8X8_UNORM
53 };
54 
55 VAStatus
vlVaCreateSurfaces(VADriverContextP ctx,int width,int height,int format,int num_surfaces,VASurfaceID * surfaces)56 vlVaCreateSurfaces(VADriverContextP ctx, int width, int height, int format,
57                    int num_surfaces, VASurfaceID *surfaces)
58 {
59    return vlVaCreateSurfaces2(ctx, format, width, height, surfaces, num_surfaces,
60                               NULL, 0);
61 }
62 
63 VAStatus
vlVaDestroySurfaces(VADriverContextP ctx,VASurfaceID * surface_list,int num_surfaces)64 vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces)
65 {
66    vlVaDriver *drv;
67    int i;
68 
69    if (!ctx)
70       return VA_STATUS_ERROR_INVALID_CONTEXT;
71 
72    drv = VL_VA_DRIVER(ctx);
73    pipe_mutex_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          pipe_mutex_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    pipe_mutex_unlock(drv->mutex);
87 
88    return VA_STATUS_SUCCESS;
89 }
90 
91 VAStatus
vlVaSyncSurface(VADriverContextP ctx,VASurfaceID render_target)92 vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target)
93 {
94    vlVaDriver *drv;
95    vlVaContext *context;
96    vlVaSurface *surf;
97 
98    if (!ctx)
99       return VA_STATUS_ERROR_INVALID_CONTEXT;
100 
101    drv = VL_VA_DRIVER(ctx);
102    if (!drv)
103       return VA_STATUS_ERROR_INVALID_CONTEXT;
104 
105    pipe_mutex_lock(drv->mutex);
106    surf = handle_table_get(drv->htab, render_target);
107 
108    if (!surf || !surf->buffer) {
109       pipe_mutex_unlock(drv->mutex);
110       return VA_STATUS_ERROR_INVALID_SURFACE;
111    }
112 
113    if (!surf->feedback) {
114       // No outstanding operation: nothing to do.
115       pipe_mutex_unlock(drv->mutex);
116       return VA_STATUS_SUCCESS;
117    }
118 
119    context = handle_table_get(drv->htab, surf->ctx);
120    if (!context) {
121       pipe_mutex_unlock(drv->mutex);
122       return VA_STATUS_ERROR_INVALID_CONTEXT;
123    }
124 
125    if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) {
126       int frame_diff;
127       if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt)
128          frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt;
129       else
130          frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt;
131       if ((frame_diff == 0) &&
132           (surf->force_flushed == false) &&
133           (context->desc.h264enc.frame_num_cnt % 2 != 0)) {
134          context->decoder->flush(context->decoder);
135          context->first_single_submitted = true;
136       }
137       context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size));
138       surf->feedback = NULL;
139    }
140    pipe_mutex_unlock(drv->mutex);
141    return VA_STATUS_SUCCESS;
142 }
143 
144 VAStatus
vlVaQuerySurfaceStatus(VADriverContextP ctx,VASurfaceID render_target,VASurfaceStatus * status)145 vlVaQuerySurfaceStatus(VADriverContextP ctx, VASurfaceID render_target, VASurfaceStatus *status)
146 {
147    if (!ctx)
148       return VA_STATUS_ERROR_INVALID_CONTEXT;
149 
150    return VA_STATUS_SUCCESS;
151 }
152 
153 VAStatus
vlVaQuerySurfaceError(VADriverContextP ctx,VASurfaceID render_target,VAStatus error_status,void ** error_info)154 vlVaQuerySurfaceError(VADriverContextP ctx, VASurfaceID render_target, VAStatus error_status, void **error_info)
155 {
156    if (!ctx)
157       return VA_STATUS_ERROR_INVALID_CONTEXT;
158 
159    return VA_STATUS_ERROR_UNIMPLEMENTED;
160 }
161 
162 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)163 upload_sampler(struct pipe_context *pipe, struct pipe_sampler_view *dst,
164                const struct pipe_box *dst_box, const void *src, unsigned src_stride,
165                unsigned src_x, unsigned src_y)
166 {
167    struct pipe_transfer *transfer;
168    void *map;
169 
170    map = pipe->transfer_map(pipe, dst->texture, 0, PIPE_TRANSFER_WRITE,
171                             dst_box, &transfer);
172    if (!map)
173       return;
174 
175    util_copy_rect(map, dst->texture->format, transfer->stride, 0, 0,
176                   dst_box->width, dst_box->height,
177                   src, src_stride, src_x, src_y);
178 
179    pipe->transfer_unmap(pipe, transfer);
180 }
181 
182 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)183 vlVaPutSubpictures(vlVaSurface *surf, vlVaDriver *drv,
184                    struct pipe_surface *surf_draw, struct u_rect *dirty_area,
185                    struct u_rect *src_rect, struct u_rect *dst_rect)
186 {
187    vlVaSubpicture *sub;
188    int i;
189 
190    if (!(surf->subpics.data || surf->subpics.size))
191       return VA_STATUS_SUCCESS;
192 
193    for (i = 0; i < surf->subpics.size/sizeof(vlVaSubpicture *); i++) {
194       struct pipe_blend_state blend;
195       void *blend_state;
196       vlVaBuffer *buf;
197       struct pipe_box box;
198       struct u_rect *s, *d, sr, dr, c;
199       int sw, sh, dw, dh;
200 
201       sub = ((vlVaSubpicture **)surf->subpics.data)[i];
202       if (!sub)
203          continue;
204 
205       buf = handle_table_get(drv->htab, sub->image->buf);
206       if (!buf)
207          return VA_STATUS_ERROR_INVALID_IMAGE;
208 
209       box.x = 0;
210       box.y = 0;
211       box.z = 0;
212       box.width = sub->dst_rect.x1 - sub->dst_rect.x0;
213       box.height = sub->dst_rect.y1 - sub->dst_rect.y0;
214       box.depth = 1;
215 
216       s = &sub->src_rect;
217       d = &sub->dst_rect;
218       sw = s->x1 - s->x0;
219       sh = s->y1 - s->y0;
220       dw = d->x1 - d->x0;
221       dh = d->y1 - d->y0;
222       c.x0 = MAX2(d->x0, s->x0);
223       c.y0 = MAX2(d->y0, s->y0);
224       c.x1 = MIN2(d->x0 + dw, src_rect->x1);
225       c.y1 = MIN2(d->y0 + dh, src_rect->y1);
226       sr.x0 = s->x0 + (c.x0 - d->x0)*(sw/(float)dw);
227       sr.y0 = s->y0 + (c.y0 - d->y0)*(sh/(float)dh);
228       sr.x1 = s->x0 + (c.x1 - d->x0)*(sw/(float)dw);
229       sr.y1 = s->y0 + (c.y1 - d->y0)*(sh/(float)dh);
230 
231       s = src_rect;
232       d = dst_rect;
233       sw = s->x1 - s->x0;
234       sh = s->y1 - s->y0;
235       dw = d->x1 - d->x0;
236       dh = d->y1 - d->y0;
237       dr.x0 = d->x0 + c.x0*(dw/(float)sw);
238       dr.y0 = d->y0 + c.y0*(dh/(float)sh);
239       dr.x1 = d->x0 + c.x1*(dw/(float)sw);
240       dr.y1 = d->y0 + c.y1*(dh/(float)sh);
241 
242       memset(&blend, 0, sizeof(blend));
243       blend.independent_blend_enable = 0;
244       blend.rt[0].blend_enable = 1;
245       blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_SRC_ALPHA;
246       blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_INV_SRC_ALPHA;
247       blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ZERO;
248       blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ZERO;
249       blend.rt[0].rgb_func = PIPE_BLEND_ADD;
250       blend.rt[0].alpha_func = PIPE_BLEND_ADD;
251       blend.rt[0].colormask = PIPE_MASK_RGBA;
252       blend.logicop_enable = 0;
253       blend.logicop_func = PIPE_LOGICOP_CLEAR;
254       blend.dither = 0;
255       blend_state = drv->pipe->create_blend_state(drv->pipe, &blend);
256 
257       vl_compositor_clear_layers(&drv->cstate);
258       vl_compositor_set_layer_blend(&drv->cstate, 0, blend_state, false);
259       upload_sampler(drv->pipe, sub->sampler, &box, buf->data,
260                      sub->image->pitches[0], 0, 0);
261       vl_compositor_set_rgba_layer(&drv->cstate, &drv->compositor, 0, sub->sampler,
262                                    &sr, NULL, NULL);
263       vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dr);
264       vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, false);
265       drv->pipe->delete_blend_state(drv->pipe, blend_state);
266    }
267 
268    return VA_STATUS_SUCCESS;
269 }
270 
271 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)272 vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short srcx, short srcy,
273                unsigned short srcw, unsigned short srch, short destx, short desty,
274                unsigned short destw, unsigned short desth, VARectangle *cliprects,
275                unsigned int number_cliprects,  unsigned int flags)
276 {
277    vlVaDriver *drv;
278    vlVaSurface *surf;
279    struct pipe_screen *screen;
280    struct pipe_resource *tex;
281    struct pipe_surface surf_templ, *surf_draw;
282    struct vl_screen *vscreen;
283    struct u_rect src_rect, *dirty_area;
284    struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};
285    VAStatus status;
286 
287    if (!ctx)
288       return VA_STATUS_ERROR_INVALID_CONTEXT;
289 
290    drv = VL_VA_DRIVER(ctx);
291    pipe_mutex_lock(drv->mutex);
292    surf = handle_table_get(drv->htab, surface_id);
293    if (!surf) {
294       pipe_mutex_unlock(drv->mutex);
295       return VA_STATUS_ERROR_INVALID_SURFACE;
296    }
297 
298    screen = drv->pipe->screen;
299    vscreen = drv->vscreen;
300 
301    tex = vscreen->texture_from_drawable(vscreen, draw);
302    if (!tex) {
303       pipe_mutex_unlock(drv->mutex);
304       return VA_STATUS_ERROR_INVALID_DISPLAY;
305    }
306 
307    dirty_area = vscreen->get_dirty_area(vscreen);
308 
309    memset(&surf_templ, 0, sizeof(surf_templ));
310    surf_templ.format = tex->format;
311    surf_draw = drv->pipe->create_surface(drv->pipe, tex, &surf_templ);
312    if (!surf_draw) {
313       pipe_resource_reference(&tex, NULL);
314       pipe_mutex_unlock(drv->mutex);
315       return VA_STATUS_ERROR_INVALID_DISPLAY;
316    }
317 
318    src_rect.x0 = srcx;
319    src_rect.y0 = srcy;
320    src_rect.x1 = srcw + srcx;
321    src_rect.y1 = srch + srcy;
322 
323    vl_compositor_clear_layers(&drv->cstate);
324    vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, surf->buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE);
325    vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
326    vl_compositor_render(&drv->cstate, &drv->compositor, surf_draw, dirty_area, true);
327 
328    status = vlVaPutSubpictures(surf, drv, surf_draw, dirty_area, &src_rect, &dst_rect);
329    if (status) {
330       pipe_mutex_unlock(drv->mutex);
331       return status;
332    }
333 
334    /* flush before calling flush_frontbuffer so that rendering is flushed
335     * to back buffer so the texture can be copied in flush_frontbuffer
336     */
337    drv->pipe->flush(drv->pipe, NULL, 0);
338 
339    screen->flush_frontbuffer(screen, tex, 0, 0,
340                              vscreen->get_private(vscreen), NULL);
341 
342 
343    pipe_resource_reference(&tex, NULL);
344    pipe_surface_reference(&surf_draw, NULL);
345    pipe_mutex_unlock(drv->mutex);
346 
347    return VA_STATUS_SUCCESS;
348 }
349 
350 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)351 vlVaLockSurface(VADriverContextP ctx, VASurfaceID surface, unsigned int *fourcc,
352                 unsigned int *luma_stride, unsigned int *chroma_u_stride, unsigned int *chroma_v_stride,
353                 unsigned int *luma_offset, unsigned int *chroma_u_offset, unsigned int *chroma_v_offset,
354                 unsigned int *buffer_name, void **buffer)
355 {
356    if (!ctx)
357       return VA_STATUS_ERROR_INVALID_CONTEXT;
358 
359    return VA_STATUS_ERROR_UNIMPLEMENTED;
360 }
361 
362 VAStatus
vlVaUnlockSurface(VADriverContextP ctx,VASurfaceID surface)363 vlVaUnlockSurface(VADriverContextP ctx, VASurfaceID surface)
364 {
365    if (!ctx)
366       return VA_STATUS_ERROR_INVALID_CONTEXT;
367 
368    return VA_STATUS_ERROR_UNIMPLEMENTED;
369 }
370 
371 VAStatus
vlVaQuerySurfaceAttributes(VADriverContextP ctx,VAConfigID config_id,VASurfaceAttrib * attrib_list,unsigned int * num_attribs)372 vlVaQuerySurfaceAttributes(VADriverContextP ctx, VAConfigID config_id,
373                            VASurfaceAttrib *attrib_list, unsigned int *num_attribs)
374 {
375    vlVaDriver *drv;
376    vlVaConfig *config;
377    VASurfaceAttrib *attribs;
378    struct pipe_screen *pscreen;
379    int i, j;
380 
381    STATIC_ASSERT(ARRAY_SIZE(vpp_surface_formats) <= VL_VA_MAX_IMAGE_FORMATS);
382 
383    if (config_id == VA_INVALID_ID)
384       return VA_STATUS_ERROR_INVALID_CONFIG;
385 
386    if (!attrib_list && !num_attribs)
387       return VA_STATUS_ERROR_INVALID_PARAMETER;
388 
389    if (!attrib_list) {
390       *num_attribs = VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount;
391       return VA_STATUS_SUCCESS;
392    }
393 
394    if (!ctx)
395       return VA_STATUS_ERROR_INVALID_CONTEXT;
396 
397    drv = VL_VA_DRIVER(ctx);
398 
399    if (!drv)
400       return VA_STATUS_ERROR_INVALID_CONTEXT;
401 
402    pipe_mutex_lock(drv->mutex);
403    config = handle_table_get(drv->htab, config_id);
404    pipe_mutex_unlock(drv->mutex);
405 
406    if (!config)
407       return VA_STATUS_ERROR_INVALID_CONFIG;
408 
409    pscreen = VL_VA_PSCREEN(ctx);
410 
411    if (!pscreen)
412       return VA_STATUS_ERROR_INVALID_CONTEXT;
413 
414    attribs = CALLOC(VL_VA_MAX_IMAGE_FORMATS + VASurfaceAttribCount,
415                     sizeof(VASurfaceAttrib));
416 
417    if (!attribs)
418       return VA_STATUS_ERROR_ALLOCATION_FAILED;
419 
420    i = 0;
421 
422    /* vlVaCreateConfig returns PIPE_VIDEO_PROFILE_UNKNOWN
423     * only for VAEntrypointVideoProc. */
424    if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) {
425       if (config->rt_format & VA_RT_FORMAT_RGB32) {
426          for (j = 0; j < ARRAY_SIZE(vpp_surface_formats); ++j) {
427             attribs[i].type = VASurfaceAttribPixelFormat;
428             attribs[i].value.type = VAGenericValueTypeInteger;
429             attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
430             attribs[i].value.value.i = PipeFormatToVaFourcc(vpp_surface_formats[j]);
431             i++;
432          }
433       }
434       if (config->rt_format & VA_RT_FORMAT_YUV420) {
435          attribs[i].type = VASurfaceAttribPixelFormat;
436          attribs[i].value.type = VAGenericValueTypeInteger;
437          attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
438          attribs[i].value.value.i = VA_FOURCC_NV12;
439          i++;
440       }
441    } else {
442       /* Assume VAEntrypointVLD for now. */
443       attribs[i].type = VASurfaceAttribPixelFormat;
444       attribs[i].value.type = VAGenericValueTypeInteger;
445       attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
446       attribs[i].value.value.i = VA_FOURCC_NV12;
447       i++;
448    }
449 
450    attribs[i].type = VASurfaceAttribMemoryType;
451    attribs[i].value.type = VAGenericValueTypeInteger;
452    attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE | VA_SURFACE_ATTRIB_SETTABLE;
453    attribs[i].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA |
454          VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
455    i++;
456 
457    attribs[i].type = VASurfaceAttribExternalBufferDescriptor;
458    attribs[i].value.type = VAGenericValueTypePointer;
459    attribs[i].flags = VA_SURFACE_ATTRIB_SETTABLE;
460    attribs[i].value.value.p = NULL; /* ignore */
461    i++;
462 
463    attribs[i].type = VASurfaceAttribMaxWidth;
464    attribs[i].value.type = VAGenericValueTypeInteger;
465    attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
466    attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
467    i++;
468 
469    attribs[i].type = VASurfaceAttribMaxHeight;
470    attribs[i].value.type = VAGenericValueTypeInteger;
471    attribs[i].flags = VA_SURFACE_ATTRIB_GETTABLE;
472    attribs[i].value.value.i = vl_video_buffer_max_size(pscreen);
473    i++;
474 
475    if (i > *num_attribs) {
476       *num_attribs = i;
477       FREE(attribs);
478       return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
479    }
480 
481    *num_attribs = i;
482    memcpy(attrib_list, attribs, i * sizeof(VASurfaceAttrib));
483    FREE(attribs);
484 
485    return VA_STATUS_SUCCESS;
486 }
487 
488 static VAStatus
suface_from_external_memory(VADriverContextP ctx,vlVaSurface * surface,VASurfaceAttribExternalBuffers * memory_attibute,int index,VASurfaceID * surfaces,struct pipe_video_buffer * templat)489 suface_from_external_memory(VADriverContextP ctx, vlVaSurface *surface,
490                             VASurfaceAttribExternalBuffers *memory_attibute,
491                             int index, VASurfaceID *surfaces,
492                             struct pipe_video_buffer *templat)
493 {
494    vlVaDriver *drv;
495    struct pipe_screen *pscreen;
496    struct pipe_resource *resource;
497    struct pipe_resource res_templ;
498    struct winsys_handle whandle;
499    struct pipe_resource *resources[VL_NUM_COMPONENTS];
500 
501    if (!ctx)
502       return VA_STATUS_ERROR_INVALID_PARAMETER;
503 
504    pscreen = VL_VA_PSCREEN(ctx);
505    drv = VL_VA_DRIVER(ctx);
506 
507    if (!memory_attibute || !memory_attibute->buffers ||
508        index > memory_attibute->num_buffers)
509       return VA_STATUS_ERROR_INVALID_PARAMETER;
510 
511    if (surface->templat.width != memory_attibute->width ||
512        surface->templat.height != memory_attibute->height ||
513        memory_attibute->num_planes < 1)
514       return VA_STATUS_ERROR_INVALID_PARAMETER;
515 
516    switch (memory_attibute->pixel_format) {
517    case VA_FOURCC_RGBA:
518    case VA_FOURCC_RGBX:
519    case VA_FOURCC_BGRA:
520    case VA_FOURCC_BGRX:
521       if (memory_attibute->num_planes != 1)
522          return VA_STATUS_ERROR_INVALID_PARAMETER;
523       break;
524    default:
525       return VA_STATUS_ERROR_INVALID_PARAMETER;
526    }
527 
528    memset(&res_templ, 0, sizeof(res_templ));
529    res_templ.target = PIPE_TEXTURE_2D;
530    res_templ.last_level = 0;
531    res_templ.depth0 = 1;
532    res_templ.array_size = 1;
533    res_templ.width0 = memory_attibute->width;
534    res_templ.height0 = memory_attibute->height;
535    res_templ.format = surface->templat.buffer_format;
536    res_templ.bind = PIPE_BIND_SAMPLER_VIEW;
537    res_templ.usage = PIPE_USAGE_DEFAULT;
538 
539    memset(&whandle, 0, sizeof(struct winsys_handle));
540    whandle.type = DRM_API_HANDLE_TYPE_FD;
541    whandle.handle = memory_attibute->buffers[index];
542    whandle.stride = memory_attibute->pitches[index];
543 
544    resource = pscreen->resource_from_handle(pscreen, &res_templ, &whandle,
545                                             PIPE_HANDLE_USAGE_READ_WRITE);
546 
547    if (!resource)
548       return VA_STATUS_ERROR_ALLOCATION_FAILED;
549 
550    memset(resources, 0, sizeof resources);
551    resources[0] = resource;
552 
553    surface->buffer = vl_video_buffer_create_ex2(drv->pipe, templat, resources);
554    if (!surface->buffer)
555       return VA_STATUS_ERROR_ALLOCATION_FAILED;
556 
557    util_dynarray_init(&surface->subpics);
558    surfaces[index] = handle_table_add(drv->htab, surface);
559 
560    if (!surfaces[index]) {
561       surface->buffer->destroy(surface->buffer);
562       return VA_STATUS_ERROR_ALLOCATION_FAILED;
563    }
564 
565    return VA_STATUS_SUCCESS;
566 }
567 
568 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)569 vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format,
570                     unsigned int width, unsigned int height,
571                     VASurfaceID *surfaces, unsigned int num_surfaces,
572                     VASurfaceAttrib *attrib_list, unsigned int num_attribs)
573 {
574    vlVaDriver *drv;
575    VASurfaceAttribExternalBuffers *memory_attibute;
576    struct pipe_video_buffer templat;
577    struct pipe_screen *pscreen;
578    int i;
579    int memory_type;
580    int expected_fourcc;
581    VAStatus vaStatus;
582 
583    if (!ctx)
584       return VA_STATUS_ERROR_INVALID_CONTEXT;
585 
586    if (!(width && height))
587       return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
588 
589    drv = VL_VA_DRIVER(ctx);
590 
591    if (!drv)
592       return VA_STATUS_ERROR_INVALID_CONTEXT;
593 
594    pscreen = VL_VA_PSCREEN(ctx);
595 
596    if (!pscreen)
597       return VA_STATUS_ERROR_INVALID_CONTEXT;
598 
599    /* Default. */
600    memory_attibute = NULL;
601    memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
602    expected_fourcc = 0;
603 
604    for (i = 0; i < num_attribs && attrib_list; i++) {
605       if ((attrib_list[i].type == VASurfaceAttribPixelFormat) &&
606           (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) {
607          if (attrib_list[i].value.type != VAGenericValueTypeInteger)
608             return VA_STATUS_ERROR_INVALID_PARAMETER;
609          expected_fourcc = attrib_list[i].value.value.i;
610       }
611 
612       if ((attrib_list[i].type == VASurfaceAttribMemoryType) &&
613           (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) {
614 
615          if (attrib_list[i].value.type != VAGenericValueTypeInteger)
616             return VA_STATUS_ERROR_INVALID_PARAMETER;
617 
618          switch (attrib_list[i].value.value.i) {
619          case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
620          case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
621             memory_type = attrib_list[i].value.value.i;
622             break;
623          default:
624             return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE;
625          }
626       }
627 
628       if ((attrib_list[i].type == VASurfaceAttribExternalBufferDescriptor) &&
629           (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) {
630          if (attrib_list[i].value.type != VAGenericValueTypePointer)
631             return VA_STATUS_ERROR_INVALID_PARAMETER;
632          memory_attibute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p;
633       }
634    }
635 
636    if (VA_RT_FORMAT_YUV420 != format &&
637        VA_RT_FORMAT_YUV422 != format &&
638        VA_RT_FORMAT_YUV444 != format &&
639        VA_RT_FORMAT_RGB32  != format) {
640       return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
641    }
642 
643    switch (memory_type) {
644    case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
645       break;
646    case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
647       if (!memory_attibute)
648          return VA_STATUS_ERROR_INVALID_PARAMETER;
649 
650       expected_fourcc = memory_attibute->pixel_format;
651       break;
652    default:
653       assert(0);
654    }
655 
656    memset(&templat, 0, sizeof(templat));
657 
658    templat.buffer_format = pscreen->get_video_param(
659       pscreen,
660       PIPE_VIDEO_PROFILE_UNKNOWN,
661       PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
662       PIPE_VIDEO_CAP_PREFERED_FORMAT
663    );
664    templat.interlaced = pscreen->get_video_param(
665       pscreen,
666       PIPE_VIDEO_PROFILE_UNKNOWN,
667       PIPE_VIDEO_ENTRYPOINT_BITSTREAM,
668       PIPE_VIDEO_CAP_PREFERS_INTERLACED
669    );
670 
671    if (expected_fourcc) {
672       enum pipe_format expected_format = VaFourccToPipeFormat(expected_fourcc);
673 
674       if (expected_format != templat.buffer_format || memory_attibute)
675         templat.interlaced = 0;
676 
677       templat.buffer_format = expected_format;
678    }
679 
680    templat.chroma_format = ChromaToPipe(format);
681 
682    templat.width = width;
683    templat.height = height;
684    if (debug_get_option_nointerlace())
685       templat.interlaced = false;
686 
687    memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID));
688 
689    pipe_mutex_lock(drv->mutex);
690    for (i = 0; i < num_surfaces; i++) {
691       vlVaSurface *surf = CALLOC(1, sizeof(vlVaSurface));
692       if (!surf)
693          goto no_res;
694 
695       surf->templat = templat;
696 
697       switch (memory_type) {
698       case VA_SURFACE_ATTRIB_MEM_TYPE_VA:
699          /* The application will clear the TILING flag when the surface is
700           * intended to be exported as dmabuf. Adding shared flag because not
701           * null memory_attibute means VASurfaceAttribExternalBuffers is used.
702           */
703          if (memory_attibute &&
704              !(memory_attibute->flags & VA_SURFACE_EXTBUF_DESC_ENABLE_TILING))
705             templat.bind = PIPE_BIND_LINEAR | PIPE_BIND_SHARED;
706 
707          surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &templat);
708          if (!surf->buffer) {
709             FREE(surf);
710             goto no_res;
711          }
712          util_dynarray_init(&surf->subpics);
713          surfaces[i] = handle_table_add(drv->htab, surf);
714          break;
715       case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME:
716          vaStatus = suface_from_external_memory(ctx, surf, memory_attibute, i, surfaces, &templat);
717          if (vaStatus != VA_STATUS_SUCCESS) {
718             FREE(surf);
719             goto no_res;
720          }
721          break;
722       default:
723          assert(0);
724       }
725    }
726    pipe_mutex_unlock(drv->mutex);
727 
728    return VA_STATUS_SUCCESS;
729 
730 no_res:
731    pipe_mutex_unlock(drv->mutex);
732    if (i)
733       vlVaDestroySurfaces(ctx, surfaces, i);
734 
735    return VA_STATUS_ERROR_ALLOCATION_FAILED;
736 }
737 
738 VAStatus
vlVaQueryVideoProcFilters(VADriverContextP ctx,VAContextID context,VAProcFilterType * filters,unsigned int * num_filters)739 vlVaQueryVideoProcFilters(VADriverContextP ctx, VAContextID context,
740                           VAProcFilterType *filters, unsigned int *num_filters)
741 {
742    unsigned int num = 0;
743 
744    if (!ctx)
745       return VA_STATUS_ERROR_INVALID_CONTEXT;
746 
747    if (!num_filters || !filters)
748       return VA_STATUS_ERROR_INVALID_PARAMETER;
749 
750    filters[num++] = VAProcFilterDeinterlacing;
751 
752    *num_filters = num;
753 
754    return VA_STATUS_SUCCESS;
755 }
756 
757 VAStatus
vlVaQueryVideoProcFilterCaps(VADriverContextP ctx,VAContextID context,VAProcFilterType type,void * filter_caps,unsigned int * num_filter_caps)758 vlVaQueryVideoProcFilterCaps(VADriverContextP ctx, VAContextID context,
759                              VAProcFilterType type, void *filter_caps,
760                              unsigned int *num_filter_caps)
761 {
762    unsigned int i;
763 
764    if (!ctx)
765       return VA_STATUS_ERROR_INVALID_CONTEXT;
766 
767    if (!filter_caps || !num_filter_caps)
768       return VA_STATUS_ERROR_INVALID_PARAMETER;
769 
770    i = 0;
771 
772    switch (type) {
773    case VAProcFilterNone:
774       break;
775    case VAProcFilterDeinterlacing: {
776       VAProcFilterCapDeinterlacing *deint = filter_caps;
777 
778       if (*num_filter_caps < 3) {
779          *num_filter_caps = 3;
780          return VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
781       }
782 
783       deint[i++].type = VAProcDeinterlacingBob;
784       deint[i++].type = VAProcDeinterlacingWeave;
785       deint[i++].type = VAProcDeinterlacingMotionAdaptive;
786       break;
787    }
788 
789    case VAProcFilterNoiseReduction:
790    case VAProcFilterSharpening:
791    case VAProcFilterColorBalance:
792    case VAProcFilterSkinToneEnhancement:
793       return VA_STATUS_ERROR_UNIMPLEMENTED;
794    default:
795       assert(0);
796    }
797 
798    *num_filter_caps = i;
799 
800    return VA_STATUS_SUCCESS;
801 }
802 
803 static VAProcColorStandardType vpp_input_color_standards[] = {
804    VAProcColorStandardBT601
805 };
806 
807 static VAProcColorStandardType vpp_output_color_standards[] = {
808    VAProcColorStandardBT601
809 };
810 
811 VAStatus
vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx,VAContextID context,VABufferID * filters,unsigned int num_filters,VAProcPipelineCaps * pipeline_cap)812 vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context,
813                                VABufferID *filters, unsigned int num_filters,
814                                VAProcPipelineCaps *pipeline_cap)
815 {
816    unsigned int i = 0;
817 
818    if (!ctx)
819       return VA_STATUS_ERROR_INVALID_CONTEXT;
820 
821    if (!pipeline_cap)
822       return VA_STATUS_ERROR_INVALID_PARAMETER;
823 
824    if (num_filters && !filters)
825       return VA_STATUS_ERROR_INVALID_PARAMETER;
826 
827    pipeline_cap->pipeline_flags = 0;
828    pipeline_cap->filter_flags = 0;
829    pipeline_cap->num_forward_references = 0;
830    pipeline_cap->num_backward_references = 0;
831    pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards);
832    pipeline_cap->input_color_standards = vpp_input_color_standards;
833    pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards);
834    pipeline_cap->output_color_standards = vpp_output_color_standards;
835 
836    for (i = 0; i < num_filters; i++) {
837       vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]);
838       VAProcFilterParameterBufferBase *filter;
839 
840       if (!buf || buf->type != VAProcFilterParameterBufferType)
841          return VA_STATUS_ERROR_INVALID_BUFFER;
842 
843       filter = buf->data;
844       switch (filter->type) {
845       case VAProcFilterDeinterlacing: {
846          VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
847          if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) {
848             pipeline_cap->num_forward_references = 1;
849             pipeline_cap->num_backward_references = 2;
850          }
851          break;
852       }
853       default:
854          return VA_STATUS_ERROR_UNIMPLEMENTED;
855       }
856    }
857 
858    return VA_STATUS_SUCCESS;
859 }
860