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