• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**************************************************************************
2  *
3  * Copyright 2015 Advanced Micro Devices, Inc.
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sub license, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice (including the
15  * next paragraph) shall be included in all copies or substantial portions
16  * of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21  * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  *
26  **************************************************************************/
27 
28 #include "util/u_handle_table.h"
29 #include "util/u_memory.h"
30 #include "util/u_compute.h"
31 
32 #include "vl/vl_defines.h"
33 #include "vl/vl_video_buffer.h"
34 #include "vl/vl_deint_filter.h"
35 #include "vl/vl_winsys.h"
36 
37 #include "va_private.h"
38 
39 static const VARectangle *
vlVaRegionDefault(const VARectangle * region,vlVaSurface * surf,VARectangle * def)40 vlVaRegionDefault(const VARectangle *region, vlVaSurface *surf,
41 		  VARectangle *def)
42 {
43    if (region)
44       return region;
45 
46    def->x = 0;
47    def->y = 0;
48    def->width = surf->templat.width;
49    def->height = surf->templat.height;
50 
51    return def;
52 }
53 
54 static VAStatus
vlVaPostProcCompositor(vlVaDriver * drv,vlVaContext * context,const VARectangle * src_region,const VARectangle * dst_region,struct pipe_video_buffer * src,struct pipe_video_buffer * dst,enum vl_compositor_deinterlace deinterlace)55 vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context,
56                        const VARectangle *src_region,
57                        const VARectangle *dst_region,
58                        struct pipe_video_buffer *src,
59                        struct pipe_video_buffer *dst,
60                        enum vl_compositor_deinterlace deinterlace)
61 {
62    struct pipe_surface **surfaces;
63    struct u_rect src_rect;
64    struct u_rect dst_rect;
65 
66    surfaces = dst->get_surfaces(dst);
67    if (!surfaces || !surfaces[0])
68       return VA_STATUS_ERROR_INVALID_SURFACE;
69 
70    src_rect.x0 = src_region->x;
71    src_rect.y0 = src_region->y;
72    src_rect.x1 = src_region->x + src_region->width;
73    src_rect.y1 = src_region->y + src_region->height;
74 
75    dst_rect.x0 = dst_region->x;
76    dst_rect.y0 = dst_region->y;
77    dst_rect.x1 = dst_region->x + dst_region->width;
78    dst_rect.y1 = dst_region->y + dst_region->height;
79 
80    vl_compositor_clear_layers(&drv->cstate);
81    vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src,
82 				  &src_rect, NULL, deinterlace);
83    vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);
84    vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false);
85 
86    drv->pipe->flush(drv->pipe, NULL, 0);
87    return VA_STATUS_SUCCESS;
88 }
89 
vlVaGetBox(struct pipe_video_buffer * buf,unsigned idx,struct pipe_box * box,const VARectangle * region)90 static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,
91                        struct pipe_box *box, const VARectangle *region)
92 {
93    unsigned plane = buf->interlaced ? idx / 2: idx;
94    unsigned x, y, width, height;
95 
96    x = abs(region->x);
97    y = abs(region->y);
98    width = region->width;
99    height = region->height;
100 
101    vl_video_buffer_adjust_size(&x, &y, plane,
102                                pipe_format_to_chroma_format(buf->buffer_format),
103                                buf->interlaced);
104    vl_video_buffer_adjust_size(&width, &height, plane,
105                                pipe_format_to_chroma_format(buf->buffer_format),
106                                buf->interlaced);
107 
108    box->x = region->x < 0 ? -x : x;
109    box->y = region->y < 0 ? -y : y;
110    box->width = width;
111    box->height = height;
112 }
113 
vlVaVidEngineBlit(vlVaDriver * drv,vlVaContext * context,const VARectangle * src_region,const VARectangle * dst_region,struct pipe_video_buffer * src,struct pipe_video_buffer * dst,enum vl_compositor_deinterlace deinterlace,VAProcPipelineParameterBuffer * param)114 static VAStatus vlVaVidEngineBlit(vlVaDriver *drv, vlVaContext *context,
115                                  const VARectangle *src_region,
116                                  const VARectangle *dst_region,
117                                  struct pipe_video_buffer *src,
118                                  struct pipe_video_buffer *dst,
119                                  enum vl_compositor_deinterlace deinterlace,
120                                  VAProcPipelineParameterBuffer* param)
121 {
122    if (deinterlace != VL_COMPOSITOR_NONE)
123       return VA_STATUS_ERROR_UNIMPLEMENTED;
124 
125    if (src->buffer_format != PIPE_FORMAT_NV12 ||
126        dst->buffer_format != PIPE_FORMAT_NV12)
127       return VA_STATUS_ERROR_UNIMPLEMENTED;
128 
129    struct u_rect src_rect;
130    struct u_rect dst_rect;
131 
132    src_rect.x0 = src_region->x;
133    src_rect.y0 = src_region->y;
134    src_rect.x1 = src_region->x + src_region->width;
135    src_rect.y1 = src_region->y + src_region->height;
136 
137    dst_rect.x0 = dst_region->x;
138    dst_rect.y0 = dst_region->y;
139    dst_rect.x1 = dst_region->x + dst_region->width;
140    dst_rect.y1 = dst_region->y + dst_region->height;
141 
142    context->desc.vidproc.base.input_format = src->buffer_format;
143    context->desc.vidproc.base.output_format = dst->buffer_format;
144 
145    context->desc.vidproc.src_region = src_rect;
146    context->desc.vidproc.dst_region = dst_rect;
147 
148    if (param->rotation_state == VA_ROTATION_NONE)
149       context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ORIENTATION_DEFAULT;
150    else if (param->rotation_state == VA_ROTATION_90)
151       context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_90;
152    else if (param->rotation_state == VA_ROTATION_180)
153       context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_180;
154    else if (param->rotation_state == VA_ROTATION_270)
155       context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_270;
156 
157    if (param->mirror_state == VA_MIRROR_HORIZONTAL)
158       context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_HORIZONTAL;
159    if (param->mirror_state == VA_MIRROR_VERTICAL)
160       context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_VERTICAL;
161 
162    memset(&context->desc.vidproc.blend, 0, sizeof(context->desc.vidproc.blend));
163    context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_NONE;
164    if (param->blend_state != NULL) {
165       if (param->blend_state->flags & VA_BLEND_GLOBAL_ALPHA) {
166          context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA;
167          context->desc.vidproc.blend.global_alpha = param->blend_state->global_alpha;
168       }
169    }
170 
171    if (context->needs_begin_frame) {
172       context->decoder->begin_frame(context->decoder, dst,
173                                     &context->desc.base);
174       context->needs_begin_frame = false;
175    }
176    context->decoder->process_frame(context->decoder, src, &context->desc.vidproc);
177    context->vpp_needs_flush_on_endpic = true;
178 
179    return VA_STATUS_SUCCESS;
180 }
181 
vlVaPostProcBlit(vlVaDriver * drv,vlVaContext * context,const VARectangle * src_region,const VARectangle * dst_region,struct pipe_video_buffer * src,struct pipe_video_buffer * dst,enum vl_compositor_deinterlace deinterlace)182 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
183                                  const VARectangle *src_region,
184                                  const VARectangle *dst_region,
185                                  struct pipe_video_buffer *src,
186                                  struct pipe_video_buffer *dst,
187                                  enum vl_compositor_deinterlace deinterlace)
188 {
189    struct pipe_surface **src_surfaces;
190    struct pipe_surface **dst_surfaces;
191    struct u_rect src_rect;
192    struct u_rect dst_rect;
193    bool scale = false;
194    bool grab = false;
195    unsigned i;
196 
197    if ((src->buffer_format == PIPE_FORMAT_B8G8R8X8_UNORM ||
198         src->buffer_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
199         src->buffer_format == PIPE_FORMAT_R8G8B8X8_UNORM ||
200         src->buffer_format == PIPE_FORMAT_R8G8B8A8_UNORM) &&
201        !src->interlaced)
202       grab = true;
203 
204    if ((src->width != dst->width || src->height != dst->height) &&
205        (src->interlaced && dst->interlaced))
206       scale = true;
207 
208    src_surfaces = src->get_surfaces(src);
209    if (!src_surfaces || !src_surfaces[0])
210       return VA_STATUS_ERROR_INVALID_SURFACE;
211 
212    if (scale || (src->interlaced != dst->interlaced && dst->interlaced)) {
213       vlVaSurface *surf;
214 
215       surf = handle_table_get(drv->htab, context->target_id);
216       surf->templat.interlaced = false;
217       dst->destroy(dst);
218 
219       if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
220          return VA_STATUS_ERROR_ALLOCATION_FAILED;
221 
222       dst = context->target = surf->buffer;
223    }
224 
225    dst_surfaces = dst->get_surfaces(dst);
226    if (!dst_surfaces || !dst_surfaces[0])
227       return VA_STATUS_ERROR_INVALID_SURFACE;
228 
229    src_rect.x0 = src_region->x;
230    src_rect.y0 = src_region->y;
231    src_rect.x1 = src_region->x + src_region->width;
232    src_rect.y1 = src_region->y + src_region->height;
233 
234    dst_rect.x0 = dst_region->x;
235    dst_rect.y0 = dst_region->y;
236    dst_rect.x1 = dst_region->x + dst_region->width;
237    dst_rect.y1 = dst_region->y + dst_region->height;
238 
239    if (grab) {
240       vl_compositor_convert_rgb_to_yuv(&drv->cstate, &drv->compositor, 0,
241                                        ((struct vl_video_buffer *)src)->resources[0],
242                                        dst, &src_rect, &dst_rect);
243 
244       return VA_STATUS_SUCCESS;
245    }
246 
247    if (src->interlaced != dst->interlaced) {
248       vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
249                                    src, dst, &src_rect, &dst_rect,
250                                    deinterlace);
251 
252       return VA_STATUS_SUCCESS;
253    }
254 
255    for (i = 0; i < VL_MAX_SURFACES; ++i) {
256       struct pipe_surface *from = src_surfaces[i];
257       struct pipe_blit_info blit;
258 
259       if (src->interlaced) {
260          /* Not 100% accurate, but close enough */
261          switch (deinterlace) {
262          case VL_COMPOSITOR_BOB_TOP:
263             from = src_surfaces[i & ~1];
264             break;
265          case VL_COMPOSITOR_BOB_BOTTOM:
266             from = src_surfaces[(i & ~1) + 1];
267             break;
268          default:
269             break;
270          }
271       }
272 
273       if (!from || !dst_surfaces[i])
274          continue;
275 
276       memset(&blit, 0, sizeof(blit));
277       blit.src.resource = from->texture;
278       blit.src.format = from->format;
279       blit.src.level = 0;
280       blit.src.box.z = from->u.tex.first_layer;
281       blit.src.box.depth = 1;
282       vlVaGetBox(src, i, &blit.src.box, src_region);
283 
284       blit.dst.resource = dst_surfaces[i]->texture;
285       blit.dst.format = dst_surfaces[i]->format;
286       blit.dst.level = 0;
287       blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
288       blit.dst.box.depth = 1;
289       vlVaGetBox(dst, i, &blit.dst.box, dst_region);
290 
291       blit.mask = PIPE_MASK_RGBA;
292       blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
293 
294       if (drv->pipe->screen->get_param(drv->pipe->screen,
295                                        PIPE_CAP_PREFER_COMPUTE_FOR_MULTIMEDIA))
296          util_compute_blit(drv->pipe, &blit, &context->blit_cs, !drv->compositor.deinterlace);
297       else
298          drv->pipe->blit(drv->pipe, &blit);
299    }
300 
301    // TODO: figure out why this is necessary for DMA-buf sharing
302    drv->pipe->flush(drv->pipe, NULL, 0);
303 
304    return VA_STATUS_SUCCESS;
305 }
306 
307 static struct pipe_video_buffer *
vlVaApplyDeint(vlVaDriver * drv,vlVaContext * context,VAProcPipelineParameterBuffer * param,struct pipe_video_buffer * current,unsigned field)308 vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,
309                VAProcPipelineParameterBuffer *param,
310                struct pipe_video_buffer *current,
311                unsigned field)
312 {
313    vlVaSurface *prevprev, *prev, *next;
314 
315    if (param->num_forward_references < 2 ||
316        param->num_backward_references < 1)
317       return current;
318 
319    prevprev = handle_table_get(drv->htab, param->forward_references[1]);
320    prev = handle_table_get(drv->htab, param->forward_references[0]);
321    next = handle_table_get(drv->htab, param->backward_references[0]);
322 
323    if (!prevprev || !prev || !next)
324       return current;
325 
326    if (context->deint && (context->deint->video_width != current->width ||
327        context->deint->video_height != current->height)) {
328       vl_deint_filter_cleanup(context->deint);
329       FREE(context->deint);
330       context->deint = NULL;
331    }
332 
333    if (!context->deint) {
334       context->deint = MALLOC(sizeof(struct vl_deint_filter));
335       if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,
336                                 current->height, false, false)) {
337          FREE(context->deint);
338          context->deint = NULL;
339          return current;
340       }
341    }
342 
343    if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,
344                                       prev->buffer, current, next->buffer))
345       return current;
346 
347    vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,
348                           current, next->buffer, field);
349    return context->deint->video_buffer;
350 }
351 
352 VAStatus
vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver * drv,vlVaContext * context,vlVaBuffer * buf)353 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
354 {
355    enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_NONE;
356    VARectangle def_src_region, def_dst_region;
357    const VARectangle *src_region, *dst_region;
358    VAProcPipelineParameterBuffer *param;
359    struct pipe_video_buffer *src, *dst;
360    vlVaSurface *src_surface, *dst_surface;
361    unsigned i;
362    struct pipe_screen *pscreen;
363 
364    if (!drv || !context)
365       return VA_STATUS_ERROR_INVALID_CONTEXT;
366 
367    if (!buf || !buf->data)
368       return VA_STATUS_ERROR_INVALID_BUFFER;
369 
370    if (!context->target)
371       return VA_STATUS_ERROR_INVALID_SURFACE;
372 
373    param = buf->data;
374 
375    src_surface = handle_table_get(drv->htab, param->surface);
376    dst_surface = handle_table_get(drv->htab, context->target_id);
377 
378    pscreen = drv->vscreen->pscreen;
379 
380    if (src_surface->buffer->buffer_format != dst_surface->buffer->buffer_format &&
381        !src_surface->buffer->interlaced &&
382        (dst_surface->buffer->buffer_format == PIPE_FORMAT_NV12 ||
383         dst_surface->buffer->buffer_format == PIPE_FORMAT_P010 ||
384         dst_surface->buffer->buffer_format == PIPE_FORMAT_P016) &&
385        pscreen->get_video_param(pscreen,
386                                 PIPE_VIDEO_PROFILE_UNKNOWN,
387                                 PIPE_VIDEO_ENTRYPOINT_ENCODE,
388                                 PIPE_VIDEO_CAP_EFC_SUPPORTED)) {
389 
390       // EFC will convert the buffer to a format the encoder accepts
391       dst_surface->encoder_format = dst_surface->buffer->buffer_format;
392 
393       vlVaSurface *surf;
394 
395       surf = handle_table_get(drv->htab, context->target_id);
396       surf->templat.interlaced = src_surface->templat.interlaced;
397       surf->templat.buffer_format = src_surface->templat.buffer_format;
398       surf->buffer->destroy(surf->buffer);
399 
400       if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
401          return VA_STATUS_ERROR_ALLOCATION_FAILED;
402 
403       pipe_resource_reference(&(((struct vl_video_buffer *)(surf->buffer))->resources[0]), ((struct vl_video_buffer *)(src_surface->buffer))->resources[0]);
404       context->target = surf->buffer;
405 
406       return VA_STATUS_SUCCESS;
407    }
408 
409    if (!src_surface || !src_surface->buffer)
410       return VA_STATUS_ERROR_INVALID_SURFACE;
411 
412    src = src_surface->buffer;
413    dst = dst_surface->buffer;
414 
415    /* convert the destination buffer to progressive if we're deinterlacing
416       otherwise we might end up deinterlacing twice */
417    if (param->num_filters && dst->interlaced) {
418       vlVaSurface *surf;
419       surf = dst_surface;
420       surf->templat.interlaced = false;
421       dst->destroy(dst);
422 
423       if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
424          return VA_STATUS_ERROR_ALLOCATION_FAILED;
425 
426       dst = context->target = surf->buffer;
427    }
428 
429    for (i = 0; i < param->num_filters; i++) {
430       vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
431       VAProcFilterParameterBufferBase *filter;
432 
433       if (!buf || buf->type != VAProcFilterParameterBufferType)
434          return VA_STATUS_ERROR_INVALID_BUFFER;
435 
436       filter = buf->data;
437       switch (filter->type) {
438       case VAProcFilterDeinterlacing: {
439          VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
440          switch (deint->algorithm) {
441          case VAProcDeinterlacingBob:
442             if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
443                deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
444             else
445                deinterlace = VL_COMPOSITOR_BOB_TOP;
446             break;
447 
448          case VAProcDeinterlacingWeave:
449             deinterlace = VL_COMPOSITOR_WEAVE;
450             break;
451 
452          case VAProcDeinterlacingMotionAdaptive:
453             src = vlVaApplyDeint(drv, context, param, src,
454 				 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));
455              deinterlace = VL_COMPOSITOR_MOTION_ADAPTIVE;
456             break;
457 
458          default:
459             return VA_STATUS_ERROR_UNIMPLEMENTED;
460          }
461          drv->compositor.deinterlace = deinterlace;
462          break;
463       }
464 
465       default:
466          return VA_STATUS_ERROR_UNIMPLEMENTED;
467       }
468    }
469 
470    src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region);
471    dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region);
472 
473    /* If the driver supports video engine post proc, attempt to do that
474     * if it fails, fallback to the other existing implementations below
475     */
476    if (pscreen->get_video_param(pscreen,
477                                 PIPE_VIDEO_PROFILE_UNKNOWN,
478                                 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
479                                 PIPE_VIDEO_CAP_SUPPORTED)) {
480       if (!context->decoder) {
481          context->decoder = drv->pipe->create_video_codec(drv->pipe, &context->templat);
482          if (!context->decoder)
483             return VA_STATUS_ERROR_ALLOCATION_FAILED;
484       }
485 
486       /* Perform VPBlit, if fail, fallback to other implementations below */
487       if (VA_STATUS_SUCCESS == vlVaVidEngineBlit(drv, context, src_region, dst_region,
488                                                  src, context->target, deinterlace, param))
489          return VA_STATUS_SUCCESS;
490    }
491 
492    /* Try other post proc implementations */
493    if (context->target->buffer_format != PIPE_FORMAT_NV12 &&
494        context->target->buffer_format != PIPE_FORMAT_P010 &&
495        context->target->buffer_format != PIPE_FORMAT_P016)
496       return vlVaPostProcCompositor(drv, context, src_region, dst_region,
497                                     src, context->target, deinterlace);
498    else
499       return vlVaPostProcBlit(drv, context, src_region, dst_region,
500                               src, context->target, deinterlace);
501 }
502