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
vlVaGetFullRange(vlVaSurface * surface,uint8_t va_range)114 static bool vlVaGetFullRange(vlVaSurface *surface, uint8_t va_range)
115 {
116 if (va_range != VA_SOURCE_RANGE_UNKNOWN)
117 return va_range == VA_SOURCE_RANGE_FULL;
118
119 /* Assume limited for YUV, full for RGB */
120 return !util_format_is_yuv(surface->buffer->buffer_format);
121 }
122
vlVaGetChromaLocation(unsigned va_chroma_location,enum pipe_format format)123 static unsigned vlVaGetChromaLocation(unsigned va_chroma_location,
124 enum pipe_format format)
125 {
126 unsigned ret = VL_COMPOSITOR_LOCATION_NONE;
127
128 if (util_format_get_plane_height(format, 1, 4) != 4) {
129 /* Bits 0-1 */
130 switch (va_chroma_location & 3) {
131 case VA_CHROMA_SITING_VERTICAL_TOP:
132 ret |= VL_COMPOSITOR_LOCATION_VERTICAL_TOP;
133 break;
134 case VA_CHROMA_SITING_VERTICAL_BOTTOM:
135 ret |= VL_COMPOSITOR_LOCATION_VERTICAL_BOTTOM;
136 break;
137 case VA_CHROMA_SITING_VERTICAL_CENTER:
138 default:
139 ret |= VL_COMPOSITOR_LOCATION_VERTICAL_CENTER;
140 break;
141 }
142 }
143
144 if (util_format_is_subsampled_422(format) ||
145 util_format_get_plane_width(format, 1, 4) != 4) {
146 /* Bits 2-3 */
147 switch (va_chroma_location & 12) {
148 case VA_CHROMA_SITING_HORIZONTAL_CENTER:
149 ret |= VL_COMPOSITOR_LOCATION_HORIZONTAL_CENTER;
150 break;
151 case VA_CHROMA_SITING_HORIZONTAL_LEFT:
152 default:
153 ret |= VL_COMPOSITOR_LOCATION_HORIZONTAL_LEFT;
154 break;
155 }
156 }
157
158 return ret;
159 }
160
vlVaSetProcParameters(vlVaDriver * drv,vlVaSurface * src,vlVaSurface * dst,VAProcPipelineParameterBuffer * param)161 static void vlVaSetProcParameters(vlVaDriver *drv,
162 vlVaSurface *src,
163 vlVaSurface *dst,
164 VAProcPipelineParameterBuffer *param)
165 {
166 enum VL_CSC_COLOR_STANDARD color_standard;
167 bool src_yuv = util_format_is_yuv(src->buffer->buffer_format);
168 bool dst_yuv = util_format_is_yuv(dst->buffer->buffer_format);
169
170 if (src_yuv == dst_yuv) {
171 color_standard = VL_CSC_COLOR_STANDARD_IDENTITY;
172 } else if (src_yuv) {
173 switch (param->surface_color_standard) {
174 case VAProcColorStandardBT601:
175 color_standard = VL_CSC_COLOR_STANDARD_BT_601;
176 break;
177 case VAProcColorStandardBT709:
178 default:
179 color_standard = src->full_range ?
180 VL_CSC_COLOR_STANDARD_BT_709_FULL :
181 VL_CSC_COLOR_STANDARD_BT_709;
182 break;
183 }
184 } else {
185 color_standard = VL_CSC_COLOR_STANDARD_BT_709_REV;
186 }
187
188 vl_csc_get_matrix(color_standard, NULL, dst->full_range, &drv->csc);
189 vl_compositor_set_csc_matrix(&drv->cstate, &drv->csc, 1.0f, 0.0f);
190
191 if (src_yuv)
192 drv->cstate.chroma_location =
193 vlVaGetChromaLocation(param->input_color_properties.chroma_sample_location,
194 src->buffer->buffer_format);
195 else if (dst_yuv)
196 drv->cstate.chroma_location =
197 vlVaGetChromaLocation(param->output_color_properties.chroma_sample_location,
198 dst->buffer->buffer_format);
199 }
200
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)201 static VAStatus vlVaVidEngineBlit(vlVaDriver *drv, vlVaContext *context,
202 const VARectangle *src_region,
203 const VARectangle *dst_region,
204 struct pipe_video_buffer *src,
205 struct pipe_video_buffer *dst,
206 enum vl_compositor_deinterlace deinterlace,
207 VAProcPipelineParameterBuffer* param)
208 {
209 if (deinterlace != VL_COMPOSITOR_NONE)
210 return VA_STATUS_ERROR_UNIMPLEMENTED;
211
212 if (!drv->pipe->screen->is_video_format_supported(drv->pipe->screen,
213 src->buffer_format,
214 PIPE_VIDEO_PROFILE_UNKNOWN,
215 PIPE_VIDEO_ENTRYPOINT_PROCESSING))
216 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
217
218 if (!drv->pipe->screen->is_video_format_supported(drv->pipe->screen,
219 dst->buffer_format,
220 PIPE_VIDEO_PROFILE_UNKNOWN,
221 PIPE_VIDEO_ENTRYPOINT_PROCESSING))
222 return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT;
223
224 struct u_rect src_rect;
225 struct u_rect dst_rect;
226
227 src_rect.x0 = src_region->x;
228 src_rect.y0 = src_region->y;
229 src_rect.x1 = src_region->x + src_region->width;
230 src_rect.y1 = src_region->y + src_region->height;
231
232 dst_rect.x0 = dst_region->x;
233 dst_rect.y0 = dst_region->y;
234 dst_rect.x1 = dst_region->x + dst_region->width;
235 dst_rect.y1 = dst_region->y + dst_region->height;
236
237 context->desc.vidproc.base.input_format = src->buffer_format;
238 context->desc.vidproc.base.output_format = dst->buffer_format;
239
240 context->desc.vidproc.src_region = src_rect;
241 context->desc.vidproc.dst_region = dst_rect;
242
243 if (param->rotation_state == VA_ROTATION_NONE)
244 context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ORIENTATION_DEFAULT;
245 else if (param->rotation_state == VA_ROTATION_90)
246 context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_90;
247 else if (param->rotation_state == VA_ROTATION_180)
248 context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_180;
249 else if (param->rotation_state == VA_ROTATION_270)
250 context->desc.vidproc.orientation = PIPE_VIDEO_VPP_ROTATION_270;
251
252 if (param->mirror_state == VA_MIRROR_HORIZONTAL)
253 context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_HORIZONTAL;
254 if (param->mirror_state == VA_MIRROR_VERTICAL)
255 context->desc.vidproc.orientation |= PIPE_VIDEO_VPP_FLIP_VERTICAL;
256
257 memset(&context->desc.vidproc.blend, 0, sizeof(context->desc.vidproc.blend));
258 context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_NONE;
259 if (param->blend_state != NULL) {
260 if (param->blend_state->flags & VA_BLEND_GLOBAL_ALPHA) {
261 context->desc.vidproc.blend.mode = PIPE_VIDEO_VPP_BLEND_MODE_GLOBAL_ALPHA;
262 context->desc.vidproc.blend.global_alpha = param->blend_state->global_alpha;
263 }
264 }
265
266 // Output background color
267 context->desc.vidproc.background_color = param->output_background_color;
268
269 // Input surface color standard
270 context->desc.vidproc.in_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_NONE;
271 if (param->surface_color_standard == VAProcColorStandardBT601)
272 context->desc.vidproc.in_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT601;
273 else if (param->surface_color_standard == VAProcColorStandardBT709)
274 context->desc.vidproc.in_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT709;
275 else if (param->surface_color_standard == VAProcColorStandardBT2020)
276 context->desc.vidproc.in_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT2020;
277
278 // Input surface color range
279 context->desc.vidproc.in_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_NONE;
280 if (param->input_color_properties.color_range == VA_SOURCE_RANGE_REDUCED)
281 context->desc.vidproc.in_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_REDUCED;
282 else if (param->input_color_properties.color_range == VA_SOURCE_RANGE_FULL)
283 context->desc.vidproc.in_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL;
284
285 // Input surface chroma sample location
286 context->desc.vidproc.in_chroma_siting = PIPE_VIDEO_VPP_CHROMA_SITING_NONE;
287 if (param->input_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_TOP)
288 context->desc.vidproc.in_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_TOP;
289 else if (param->input_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_CENTER)
290 context->desc.vidproc.in_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_CENTER;
291 else if (param->input_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_BOTTOM)
292 context->desc.vidproc.in_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_BOTTOM;
293 if (param->input_color_properties.chroma_sample_location & VA_CHROMA_SITING_HORIZONTAL_LEFT)
294 context->desc.vidproc.in_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_LEFT;
295 else if (param->input_color_properties.chroma_sample_location & VA_CHROMA_SITING_HORIZONTAL_CENTER)
296 context->desc.vidproc.in_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_CENTER;
297
298 // Output surface color standard
299 context->desc.vidproc.out_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_NONE;
300 if (param->output_color_standard == VAProcColorStandardBT601)
301 context->desc.vidproc.out_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT601;
302 else if (param->output_color_standard == VAProcColorStandardBT709)
303 context->desc.vidproc.out_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT709;
304 else if (param->output_color_standard == VAProcColorStandardBT2020)
305 context->desc.vidproc.out_colors_standard = PIPE_VIDEO_VPP_COLOR_STANDARD_TYPE_BT2020;
306
307 // Output surface color range
308 context->desc.vidproc.out_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_NONE;
309 if (param->output_color_properties.color_range == VA_SOURCE_RANGE_REDUCED)
310 context->desc.vidproc.out_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_REDUCED;
311 else if (param->output_color_properties.color_range == VA_SOURCE_RANGE_FULL)
312 context->desc.vidproc.out_color_range = PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL;
313
314 // Output surface chroma sample location
315 context->desc.vidproc.out_chroma_siting = PIPE_VIDEO_VPP_CHROMA_SITING_NONE;
316 if (param->output_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_TOP)
317 context->desc.vidproc.out_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_TOP;
318 else if (param->output_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_CENTER)
319 context->desc.vidproc.out_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_CENTER;
320 else if (param->output_color_properties.chroma_sample_location & VA_CHROMA_SITING_VERTICAL_BOTTOM)
321 context->desc.vidproc.out_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_VERTICAL_BOTTOM;
322 if (param->output_color_properties.chroma_sample_location & VA_CHROMA_SITING_HORIZONTAL_LEFT)
323 context->desc.vidproc.out_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_LEFT;
324 else if (param->output_color_properties.chroma_sample_location & VA_CHROMA_SITING_HORIZONTAL_CENTER)
325 context->desc.vidproc.out_chroma_siting |= PIPE_VIDEO_VPP_CHROMA_SITING_HORIZONTAL_CENTER;
326
327 if (context->needs_begin_frame) {
328 context->decoder->begin_frame(context->decoder, dst,
329 &context->desc.base);
330 context->needs_begin_frame = false;
331 }
332 context->decoder->process_frame(context->decoder, src, &context->desc.vidproc);
333
334 return VA_STATUS_SUCCESS;
335 }
336
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)337 static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,
338 const VARectangle *src_region,
339 const VARectangle *dst_region,
340 struct pipe_video_buffer *src,
341 struct pipe_video_buffer *dst,
342 enum vl_compositor_deinterlace deinterlace)
343 {
344 struct pipe_surface **src_surfaces;
345 struct pipe_surface **dst_surfaces;
346 struct u_rect src_rect;
347 struct u_rect dst_rect;
348 bool scale = false;
349 bool grab = false;
350 unsigned i;
351
352 if ((src->buffer_format == PIPE_FORMAT_B8G8R8X8_UNORM ||
353 src->buffer_format == PIPE_FORMAT_B8G8R8A8_UNORM ||
354 src->buffer_format == PIPE_FORMAT_R8G8B8X8_UNORM ||
355 src->buffer_format == PIPE_FORMAT_R8G8B8A8_UNORM) &&
356 !src->interlaced)
357 grab = true;
358
359 if ((src->width != dst->width || src->height != dst->height) &&
360 (src->interlaced && dst->interlaced))
361 scale = true;
362
363 src_surfaces = src->get_surfaces(src);
364 if (!src_surfaces || !src_surfaces[0])
365 return VA_STATUS_ERROR_INVALID_SURFACE;
366
367 if (scale || (src->interlaced != dst->interlaced && dst->interlaced)) {
368 vlVaSurface *surf;
369
370 surf = handle_table_get(drv->htab, context->target_id);
371 if (!surf)
372 return VA_STATUS_ERROR_INVALID_SURFACE;
373 surf->templat.interlaced = false;
374 dst->destroy(dst);
375
376 if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
377 return VA_STATUS_ERROR_ALLOCATION_FAILED;
378
379 dst = context->target = surf->buffer;
380 }
381
382 dst_surfaces = dst->get_surfaces(dst);
383 if (!dst_surfaces || !dst_surfaces[0])
384 return VA_STATUS_ERROR_INVALID_SURFACE;
385
386 src_rect.x0 = src_region->x;
387 src_rect.y0 = src_region->y;
388 src_rect.x1 = src_region->x + src_region->width;
389 src_rect.y1 = src_region->y + src_region->height;
390
391 dst_rect.x0 = dst_region->x;
392 dst_rect.y0 = dst_region->y;
393 dst_rect.x1 = dst_region->x + dst_region->width;
394 dst_rect.y1 = dst_region->y + dst_region->height;
395
396 if (grab) {
397 vl_compositor_convert_rgb_to_yuv(&drv->cstate, &drv->compositor, 0,
398 ((struct vl_video_buffer *)src)->resources[0],
399 dst, &src_rect, &dst_rect);
400
401 return VA_STATUS_SUCCESS;
402 }
403
404 if (src->buffer_format == PIPE_FORMAT_YUYV ||
405 src->buffer_format == PIPE_FORMAT_UYVY ||
406 src->buffer_format == PIPE_FORMAT_YV12 ||
407 src->buffer_format == PIPE_FORMAT_IYUV) {
408 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
409 src, dst, &src_rect, &dst_rect,
410 VL_COMPOSITOR_NONE);
411
412 return VA_STATUS_SUCCESS;
413 }
414
415 if (src->interlaced != dst->interlaced) {
416 deinterlace = deinterlace ? deinterlace : VL_COMPOSITOR_WEAVE;
417 vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,
418 src, dst, &src_rect, &dst_rect,
419 deinterlace);
420
421 return VA_STATUS_SUCCESS;
422 }
423
424 for (i = 0; i < VL_MAX_SURFACES; ++i) {
425 struct pipe_surface *from = src_surfaces[i];
426 struct pipe_blit_info blit;
427
428 if (src->interlaced) {
429 /* Not 100% accurate, but close enough */
430 switch (deinterlace) {
431 case VL_COMPOSITOR_BOB_TOP:
432 from = src_surfaces[i & ~1];
433 break;
434 case VL_COMPOSITOR_BOB_BOTTOM:
435 from = src_surfaces[(i & ~1) + 1];
436 break;
437 default:
438 break;
439 }
440 }
441
442 if (!from || !dst_surfaces[i])
443 continue;
444
445 memset(&blit, 0, sizeof(blit));
446 blit.src.resource = from->texture;
447 blit.src.format = from->format;
448 blit.src.level = 0;
449 blit.src.box.z = from->u.tex.first_layer;
450 blit.src.box.depth = 1;
451 vlVaGetBox(src, i, &blit.src.box, src_region);
452
453 blit.dst.resource = dst_surfaces[i]->texture;
454 blit.dst.format = dst_surfaces[i]->format;
455 blit.dst.level = 0;
456 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;
457 blit.dst.box.depth = 1;
458 vlVaGetBox(dst, i, &blit.dst.box, dst_region);
459
460 blit.mask = PIPE_MASK_RGBA;
461 blit.filter = PIPE_TEX_MIPFILTER_LINEAR;
462
463 if (drv->pipe->screen->get_param(drv->pipe->screen,
464 PIPE_CAP_PREFER_COMPUTE_FOR_MULTIMEDIA))
465 util_compute_blit(drv->pipe, &blit, &context->blit_cs);
466 else
467 drv->pipe->blit(drv->pipe, &blit);
468 }
469
470 // TODO: figure out why this is necessary for DMA-buf sharing
471 drv->pipe->flush(drv->pipe, NULL, 0);
472
473 return VA_STATUS_SUCCESS;
474 }
475
476 static struct pipe_video_buffer *
vlVaApplyDeint(vlVaDriver * drv,vlVaContext * context,VAProcPipelineParameterBuffer * param,struct pipe_video_buffer * current,unsigned field)477 vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,
478 VAProcPipelineParameterBuffer *param,
479 struct pipe_video_buffer *current,
480 unsigned field)
481 {
482 vlVaSurface *prevprev, *prev, *next;
483
484 if (param->num_forward_references < 2 ||
485 param->num_backward_references < 1)
486 return current;
487
488 prevprev = handle_table_get(drv->htab, param->forward_references[1]);
489 prev = handle_table_get(drv->htab, param->forward_references[0]);
490 next = handle_table_get(drv->htab, param->backward_references[0]);
491
492 if (!prevprev || !prev || !next)
493 return current;
494
495 if (context->deint && (context->deint->video_width != current->width ||
496 context->deint->video_height != current->height ||
497 context->deint->interleaved != !current->interlaced)) {
498 vl_deint_filter_cleanup(context->deint);
499 FREE(context->deint);
500 context->deint = NULL;
501 }
502
503 if (!context->deint) {
504 context->deint = MALLOC(sizeof(struct vl_deint_filter));
505 if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,
506 current->height, false, false, !current->interlaced)) {
507 FREE(context->deint);
508 context->deint = NULL;
509 return current;
510 }
511 }
512
513 if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,
514 prev->buffer, current, next->buffer))
515 return current;
516
517 vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,
518 current, next->buffer, field);
519 return context->deint->video_buffer;
520 }
521
can_convert_with_efc(vlVaSurface * src,vlVaSurface * dst)522 static bool can_convert_with_efc(vlVaSurface *src, vlVaSurface *dst)
523 {
524 enum pipe_format src_format, dst_format;
525
526 if (src->buffer->interlaced)
527 return false;
528
529 src_format = src->buffer->buffer_format;
530
531 if (src_format != PIPE_FORMAT_B8G8R8A8_UNORM &&
532 src_format != PIPE_FORMAT_R8G8B8A8_UNORM &&
533 src_format != PIPE_FORMAT_B8G8R8X8_UNORM &&
534 src_format != PIPE_FORMAT_R8G8B8X8_UNORM)
535 return false;
536
537 dst_format = dst->encoder_format != PIPE_FORMAT_NONE ?
538 dst->encoder_format : dst->buffer->buffer_format;
539
540 return dst_format == PIPE_FORMAT_NV12;
541 }
542
543 VAStatus
vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver * drv,vlVaContext * context,vlVaBuffer * buf)544 vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)
545 {
546 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_NONE;
547 VARectangle def_src_region, def_dst_region;
548 const VARectangle *src_region, *dst_region;
549 VAProcPipelineParameterBuffer *param;
550 struct pipe_video_buffer *src, *dst;
551 vlVaSurface *src_surface, *dst_surface;
552 unsigned i;
553 struct pipe_screen *pscreen;
554 VAStatus ret;
555
556 if (!drv || !context)
557 return VA_STATUS_ERROR_INVALID_CONTEXT;
558
559 if (!buf || !buf->data)
560 return VA_STATUS_ERROR_INVALID_BUFFER;
561
562 if (!context->target)
563 return VA_STATUS_ERROR_INVALID_SURFACE;
564
565 param = buf->data;
566
567 src_surface = handle_table_get(drv->htab, param->surface);
568 dst_surface = handle_table_get(drv->htab, context->target_id);
569 if (!src_surface || !dst_surface)
570 return VA_STATUS_ERROR_INVALID_SURFACE;
571 if (!src_surface->buffer || !dst_surface->buffer)
572 return VA_STATUS_ERROR_INVALID_SURFACE;
573
574 src_surface->full_range = vlVaGetFullRange(src_surface,
575 param->input_color_properties.color_range);
576 dst_surface->full_range = vlVaGetFullRange(dst_surface,
577 param->output_color_properties.color_range);
578
579 pscreen = drv->vscreen->pscreen;
580
581 src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region);
582 dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region);
583
584 if (!param->num_filters &&
585 src_region->width == dst_region->width &&
586 src_region->height == dst_region->height &&
587 src_region->x == dst_region->x &&
588 src_region->y == dst_region->y &&
589 can_convert_with_efc(src_surface, dst_surface) &&
590 pscreen->get_video_param(pscreen,
591 PIPE_VIDEO_PROFILE_UNKNOWN,
592 PIPE_VIDEO_ENTRYPOINT_ENCODE,
593 PIPE_VIDEO_CAP_EFC_SUPPORTED)) {
594
595 vlVaSurface *surf = dst_surface;
596
597 // EFC will convert the buffer to a format the encoder accepts
598 if (src_surface->buffer->buffer_format != surf->buffer->buffer_format) {
599 surf->encoder_format = surf->buffer->buffer_format;
600
601 surf->templat.interlaced = src_surface->templat.interlaced;
602 surf->templat.buffer_format = src_surface->templat.buffer_format;
603 surf->buffer->destroy(surf->buffer);
604
605 if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
606 return VA_STATUS_ERROR_ALLOCATION_FAILED;
607 }
608
609 pipe_resource_reference(&(((struct vl_video_buffer *)(surf->buffer))->resources[0]), ((struct vl_video_buffer *)(src_surface->buffer))->resources[0]);
610 context->target = surf->buffer;
611
612 return VA_STATUS_SUCCESS;
613 }
614
615 src = src_surface->buffer;
616 dst = dst_surface->buffer;
617
618 /* convert the destination buffer to progressive if we're deinterlacing
619 otherwise we might end up deinterlacing twice */
620 if (param->num_filters && dst->interlaced) {
621 vlVaSurface *surf;
622 surf = dst_surface;
623 surf->templat.interlaced = false;
624 dst->destroy(dst);
625
626 if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)
627 return VA_STATUS_ERROR_ALLOCATION_FAILED;
628
629 dst = context->target = surf->buffer;
630 }
631
632 for (i = 0; i < param->num_filters; i++) {
633 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);
634 VAProcFilterParameterBufferBase *filter;
635
636 if (!buf || buf->type != VAProcFilterParameterBufferType)
637 return VA_STATUS_ERROR_INVALID_BUFFER;
638
639 filter = buf->data;
640 switch (filter->type) {
641 case VAProcFilterDeinterlacing: {
642 VAProcFilterParameterBufferDeinterlacing *deint = buf->data;
643 switch (deint->algorithm) {
644 case VAProcDeinterlacingBob:
645 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)
646 deinterlace = VL_COMPOSITOR_BOB_BOTTOM;
647 else
648 deinterlace = VL_COMPOSITOR_BOB_TOP;
649 break;
650
651 case VAProcDeinterlacingWeave:
652 deinterlace = VL_COMPOSITOR_WEAVE;
653 break;
654
655 case VAProcDeinterlacingMotionAdaptive:
656 src = vlVaApplyDeint(drv, context, param, src,
657 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));
658 deinterlace = VL_COMPOSITOR_MOTION_ADAPTIVE;
659 break;
660
661 default:
662 return VA_STATUS_ERROR_UNIMPLEMENTED;
663 }
664 drv->compositor.deinterlace = deinterlace;
665 break;
666 }
667
668 default:
669 return VA_STATUS_ERROR_UNIMPLEMENTED;
670 }
671 }
672
673 /* If the driver supports video engine post proc, attempt to do that
674 * if it fails, fallback to the other existing implementations below
675 */
676 if (pscreen->get_video_param(pscreen,
677 PIPE_VIDEO_PROFILE_UNKNOWN,
678 PIPE_VIDEO_ENTRYPOINT_PROCESSING,
679 PIPE_VIDEO_CAP_SUPPORTED)) {
680 if (!context->decoder) {
681 context->decoder = drv->pipe->create_video_codec(drv->pipe, &context->templat);
682 if (!context->decoder)
683 return VA_STATUS_ERROR_ALLOCATION_FAILED;
684 }
685
686 context->desc.vidproc.src_surface_fence = src_surface->fence;
687 /* Perform VPBlit, if fail, fallback to other implementations below */
688 if (VA_STATUS_SUCCESS == vlVaVidEngineBlit(drv, context, src_region, dst_region,
689 src, context->target, deinterlace, param))
690 return VA_STATUS_SUCCESS;
691 }
692
693 vlVaSetProcParameters(drv, src_surface, dst_surface, param);
694
695 /* Try other post proc implementations */
696 if (context->target->buffer_format != PIPE_FORMAT_NV12 &&
697 context->target->buffer_format != PIPE_FORMAT_P010 &&
698 context->target->buffer_format != PIPE_FORMAT_P016)
699 ret = vlVaPostProcCompositor(drv, context, src_region, dst_region,
700 src, context->target, deinterlace);
701 else
702 ret = vlVaPostProcBlit(drv, context, src_region, dst_region,
703 src, context->target, deinterlace);
704
705 /* Reset chroma location */
706 drv->cstate.chroma_location = VL_COMPOSITOR_LOCATION_NONE;
707
708 return ret;
709 }
710