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 39static const VARectangle * 40vlVaRegionDefault(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 54static VAStatus 55vlVaPostProcCompositor(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 90static 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 114static 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 182static 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 307static struct pipe_video_buffer * 308vlVaApplyDeint(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 352VAStatus 353vlVaHandleVAProcPipelineParameterBufferType(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