1b8e80941Smrg/************************************************************************** 2b8e80941Smrg * 3b8e80941Smrg * Copyright 2015 Advanced Micro Devices, Inc. 4b8e80941Smrg * All Rights Reserved. 5b8e80941Smrg * 6b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 7b8e80941Smrg * copy of this software and associated documentation files (the 8b8e80941Smrg * "Software"), to deal in the Software without restriction, including 9b8e80941Smrg * without limitation the rights to use, copy, modify, merge, publish, 10b8e80941Smrg * distribute, sub license, and/or sell copies of the Software, and to 11b8e80941Smrg * permit persons to whom the Software is furnished to do so, subject to 12b8e80941Smrg * the following conditions: 13b8e80941Smrg * 14b8e80941Smrg * The above copyright notice and this permission notice (including the 15b8e80941Smrg * next paragraph) shall be included in all copies or substantial portions 16b8e80941Smrg * of the Software. 17b8e80941Smrg * 18b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19b8e80941Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20b8e80941Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21b8e80941Smrg * IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR 22b8e80941Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23b8e80941Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24b8e80941Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25b8e80941Smrg * 26b8e80941Smrg **************************************************************************/ 27b8e80941Smrg 28b8e80941Smrg#include "util/u_handle_table.h" 29b8e80941Smrg#include "util/u_memory.h" 30b8e80941Smrg#include "util/u_compute.h" 31b8e80941Smrg 32b8e80941Smrg#include "vl/vl_defines.h" 33b8e80941Smrg#include "vl/vl_video_buffer.h" 34b8e80941Smrg#include "vl/vl_deint_filter.h" 35b8e80941Smrg 36b8e80941Smrg#include "va_private.h" 37b8e80941Smrg 38b8e80941Smrgstatic const VARectangle * 39b8e80941SmrgvlVaRegionDefault(const VARectangle *region, vlVaSurface *surf, 40b8e80941Smrg VARectangle *def) 41b8e80941Smrg{ 42b8e80941Smrg if (region) 43b8e80941Smrg return region; 44b8e80941Smrg 45b8e80941Smrg def->x = 0; 46b8e80941Smrg def->y = 0; 47b8e80941Smrg def->width = surf->templat.width; 48b8e80941Smrg def->height = surf->templat.height; 49b8e80941Smrg 50b8e80941Smrg return def; 51b8e80941Smrg} 52b8e80941Smrg 53b8e80941Smrgstatic VAStatus 54b8e80941SmrgvlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context, 55b8e80941Smrg const VARectangle *src_region, 56b8e80941Smrg const VARectangle *dst_region, 57b8e80941Smrg struct pipe_video_buffer *src, 58b8e80941Smrg struct pipe_video_buffer *dst, 59b8e80941Smrg enum vl_compositor_deinterlace deinterlace) 60b8e80941Smrg{ 61b8e80941Smrg struct pipe_surface **surfaces; 62b8e80941Smrg struct u_rect src_rect; 63b8e80941Smrg struct u_rect dst_rect; 64b8e80941Smrg 65b8e80941Smrg surfaces = dst->get_surfaces(dst); 66b8e80941Smrg if (!surfaces || !surfaces[0]) 67b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 68b8e80941Smrg 69b8e80941Smrg src_rect.x0 = src_region->x; 70b8e80941Smrg src_rect.y0 = src_region->y; 71b8e80941Smrg src_rect.x1 = src_region->x + src_region->width; 72b8e80941Smrg src_rect.y1 = src_region->y + src_region->height; 73b8e80941Smrg 74b8e80941Smrg dst_rect.x0 = dst_region->x; 75b8e80941Smrg dst_rect.y0 = dst_region->y; 76b8e80941Smrg dst_rect.x1 = dst_region->x + dst_region->width; 77b8e80941Smrg dst_rect.y1 = dst_region->y + dst_region->height; 78b8e80941Smrg 79b8e80941Smrg vl_compositor_clear_layers(&drv->cstate); 80b8e80941Smrg vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src, 81b8e80941Smrg &src_rect, NULL, deinterlace); 82b8e80941Smrg vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect); 83b8e80941Smrg vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false); 84b8e80941Smrg 85b8e80941Smrg drv->pipe->flush(drv->pipe, NULL, 0); 86b8e80941Smrg return VA_STATUS_SUCCESS; 87b8e80941Smrg} 88b8e80941Smrg 89b8e80941Smrgstatic void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx, 90b8e80941Smrg struct pipe_box *box, const VARectangle *region) 91b8e80941Smrg{ 92b8e80941Smrg unsigned plane = buf->interlaced ? idx / 2: idx; 93b8e80941Smrg unsigned x, y, width, height; 94b8e80941Smrg 95b8e80941Smrg x = abs(region->x); 96b8e80941Smrg y = abs(region->y); 97b8e80941Smrg width = region->width; 98b8e80941Smrg height = region->height; 99b8e80941Smrg 100b8e80941Smrg vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format, 101b8e80941Smrg buf->interlaced); 102b8e80941Smrg vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format, 103b8e80941Smrg buf->interlaced); 104b8e80941Smrg 105b8e80941Smrg box->x = region->x < 0 ? -x : x; 106b8e80941Smrg box->y = region->y < 0 ? -y : y; 107b8e80941Smrg box->width = width; 108b8e80941Smrg box->height = height; 109b8e80941Smrg} 110b8e80941Smrg 111b8e80941Smrgstatic VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context, 112b8e80941Smrg const VARectangle *src_region, 113b8e80941Smrg const VARectangle *dst_region, 114b8e80941Smrg struct pipe_video_buffer *src, 115b8e80941Smrg struct pipe_video_buffer *dst, 116b8e80941Smrg enum vl_compositor_deinterlace deinterlace) 117b8e80941Smrg{ 118b8e80941Smrg struct pipe_surface **src_surfaces; 119b8e80941Smrg struct pipe_surface **dst_surfaces; 120b8e80941Smrg struct u_rect src_rect; 121b8e80941Smrg struct u_rect dst_rect; 122b8e80941Smrg bool scale = false; 123b8e80941Smrg bool grab = false; 124b8e80941Smrg unsigned i; 125b8e80941Smrg 126b8e80941Smrg if ((src->buffer_format == PIPE_FORMAT_B8G8R8A8_UNORM || 127b8e80941Smrg src->buffer_format == PIPE_FORMAT_B8G8R8X8_UNORM) && 128b8e80941Smrg !src->interlaced) 129b8e80941Smrg grab = true; 130b8e80941Smrg 131b8e80941Smrg if (src->interlaced != dst->interlaced && dst->interlaced && !grab) 132b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 133b8e80941Smrg 134b8e80941Smrg if ((src->width != dst->width || src->height != dst->height) && 135b8e80941Smrg (src->interlaced && dst->interlaced)) 136b8e80941Smrg scale = true; 137b8e80941Smrg 138b8e80941Smrg src_surfaces = src->get_surfaces(src); 139b8e80941Smrg if (!src_surfaces || !src_surfaces[0]) 140b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 141b8e80941Smrg 142b8e80941Smrg if (scale || (grab && dst->interlaced)) { 143b8e80941Smrg vlVaSurface *surf; 144b8e80941Smrg 145b8e80941Smrg surf = handle_table_get(drv->htab, context->target_id); 146b8e80941Smrg surf->templat.interlaced = false; 147b8e80941Smrg dst->destroy(dst); 148b8e80941Smrg 149b8e80941Smrg if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat) != VA_STATUS_SUCCESS) 150b8e80941Smrg return VA_STATUS_ERROR_ALLOCATION_FAILED; 151b8e80941Smrg 152b8e80941Smrg dst = context->target = surf->buffer; 153b8e80941Smrg } 154b8e80941Smrg 155b8e80941Smrg dst_surfaces = dst->get_surfaces(dst); 156b8e80941Smrg if (!dst_surfaces || !dst_surfaces[0]) 157b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 158b8e80941Smrg 159b8e80941Smrg src_rect.x0 = src_region->x; 160b8e80941Smrg src_rect.y0 = src_region->y; 161b8e80941Smrg src_rect.x1 = src_region->x + src_region->width; 162b8e80941Smrg src_rect.y1 = src_region->y + src_region->height; 163b8e80941Smrg 164b8e80941Smrg dst_rect.x0 = dst_region->x; 165b8e80941Smrg dst_rect.y0 = dst_region->y; 166b8e80941Smrg dst_rect.x1 = dst_region->x + dst_region->width; 167b8e80941Smrg dst_rect.y1 = dst_region->y + dst_region->height; 168b8e80941Smrg 169b8e80941Smrg if (grab) { 170b8e80941Smrg vl_compositor_convert_rgb_to_yuv(&drv->cstate, &drv->compositor, 0, 171b8e80941Smrg ((struct vl_video_buffer *)src)->resources[0], 172b8e80941Smrg dst, &src_rect, &dst_rect); 173b8e80941Smrg 174b8e80941Smrg return VA_STATUS_SUCCESS; 175b8e80941Smrg } 176b8e80941Smrg 177b8e80941Smrg if (src->interlaced != dst->interlaced) { 178b8e80941Smrg vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor, 179b8e80941Smrg src, dst, &src_rect, &dst_rect, 180b8e80941Smrg deinterlace); 181b8e80941Smrg 182b8e80941Smrg return VA_STATUS_SUCCESS; 183b8e80941Smrg } 184b8e80941Smrg 185b8e80941Smrg for (i = 0; i < VL_MAX_SURFACES; ++i) { 186b8e80941Smrg struct pipe_surface *from = src_surfaces[i]; 187b8e80941Smrg struct pipe_blit_info blit; 188b8e80941Smrg 189b8e80941Smrg if (src->interlaced) { 190b8e80941Smrg /* Not 100% accurate, but close enough */ 191b8e80941Smrg switch (deinterlace) { 192b8e80941Smrg case VL_COMPOSITOR_BOB_TOP: 193b8e80941Smrg from = src_surfaces[i & ~1]; 194b8e80941Smrg break; 195b8e80941Smrg case VL_COMPOSITOR_BOB_BOTTOM: 196b8e80941Smrg from = src_surfaces[(i & ~1) + 1]; 197b8e80941Smrg break; 198b8e80941Smrg default: 199b8e80941Smrg break; 200b8e80941Smrg } 201b8e80941Smrg } 202b8e80941Smrg 203b8e80941Smrg if (!from || !dst_surfaces[i]) 204b8e80941Smrg continue; 205b8e80941Smrg 206b8e80941Smrg memset(&blit, 0, sizeof(blit)); 207b8e80941Smrg blit.src.resource = from->texture; 208b8e80941Smrg blit.src.format = from->format; 209b8e80941Smrg blit.src.level = 0; 210b8e80941Smrg blit.src.box.z = from->u.tex.first_layer; 211b8e80941Smrg blit.src.box.depth = 1; 212b8e80941Smrg vlVaGetBox(src, i, &blit.src.box, src_region); 213b8e80941Smrg 214b8e80941Smrg blit.dst.resource = dst_surfaces[i]->texture; 215b8e80941Smrg blit.dst.format = dst_surfaces[i]->format; 216b8e80941Smrg blit.dst.level = 0; 217b8e80941Smrg blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer; 218b8e80941Smrg blit.dst.box.depth = 1; 219b8e80941Smrg vlVaGetBox(dst, i, &blit.dst.box, dst_region); 220b8e80941Smrg 221b8e80941Smrg blit.mask = PIPE_MASK_RGBA; 222b8e80941Smrg blit.filter = PIPE_TEX_MIPFILTER_LINEAR; 223b8e80941Smrg 224b8e80941Smrg if (drv->pipe->screen->get_param(drv->pipe->screen, 225b8e80941Smrg PIPE_CAP_PREFER_COMPUTE_FOR_MULTIMEDIA)) 226b8e80941Smrg util_compute_blit(drv->pipe, &blit, &context->blit_cs); 227b8e80941Smrg else 228b8e80941Smrg drv->pipe->blit(drv->pipe, &blit); 229b8e80941Smrg } 230b8e80941Smrg 231b8e80941Smrg // TODO: figure out why this is necessary for DMA-buf sharing 232b8e80941Smrg drv->pipe->flush(drv->pipe, NULL, 0); 233b8e80941Smrg 234b8e80941Smrg return VA_STATUS_SUCCESS; 235b8e80941Smrg} 236b8e80941Smrg 237b8e80941Smrgstatic struct pipe_video_buffer * 238b8e80941SmrgvlVaApplyDeint(vlVaDriver *drv, vlVaContext *context, 239b8e80941Smrg VAProcPipelineParameterBuffer *param, 240b8e80941Smrg struct pipe_video_buffer *current, 241b8e80941Smrg unsigned field) 242b8e80941Smrg{ 243b8e80941Smrg vlVaSurface *prevprev, *prev, *next; 244b8e80941Smrg 245b8e80941Smrg if (param->num_forward_references < 2 || 246b8e80941Smrg param->num_backward_references < 1) 247b8e80941Smrg return current; 248b8e80941Smrg 249b8e80941Smrg prevprev = handle_table_get(drv->htab, param->forward_references[1]); 250b8e80941Smrg prev = handle_table_get(drv->htab, param->forward_references[0]); 251b8e80941Smrg next = handle_table_get(drv->htab, param->backward_references[0]); 252b8e80941Smrg 253b8e80941Smrg if (!prevprev || !prev || !next) 254b8e80941Smrg return current; 255b8e80941Smrg 256b8e80941Smrg if (context->deint && (context->deint->video_width != current->width || 257b8e80941Smrg context->deint->video_height != current->height)) { 258b8e80941Smrg vl_deint_filter_cleanup(context->deint); 259b8e80941Smrg FREE(context->deint); 260b8e80941Smrg context->deint = NULL; 261b8e80941Smrg } 262b8e80941Smrg 263b8e80941Smrg if (!context->deint) { 264b8e80941Smrg context->deint = MALLOC(sizeof(struct vl_deint_filter)); 265b8e80941Smrg if (!vl_deint_filter_init(context->deint, drv->pipe, current->width, 266b8e80941Smrg current->height, false, false)) { 267b8e80941Smrg FREE(context->deint); 268b8e80941Smrg context->deint = NULL; 269b8e80941Smrg return current; 270b8e80941Smrg } 271b8e80941Smrg } 272b8e80941Smrg 273b8e80941Smrg if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer, 274b8e80941Smrg prev->buffer, current, next->buffer)) 275b8e80941Smrg return current; 276b8e80941Smrg 277b8e80941Smrg vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer, 278b8e80941Smrg current, next->buffer, field); 279b8e80941Smrg return context->deint->video_buffer; 280b8e80941Smrg} 281b8e80941Smrg 282b8e80941SmrgVAStatus 283b8e80941SmrgvlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf) 284b8e80941Smrg{ 285b8e80941Smrg enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE; 286b8e80941Smrg VARectangle def_src_region, def_dst_region; 287b8e80941Smrg const VARectangle *src_region, *dst_region; 288b8e80941Smrg VAProcPipelineParameterBuffer *param; 289b8e80941Smrg struct pipe_video_buffer *src; 290b8e80941Smrg vlVaSurface *src_surface, *dst_surface; 291b8e80941Smrg unsigned i; 292b8e80941Smrg 293b8e80941Smrg if (!drv || !context) 294b8e80941Smrg return VA_STATUS_ERROR_INVALID_CONTEXT; 295b8e80941Smrg 296b8e80941Smrg if (!buf || !buf->data) 297b8e80941Smrg return VA_STATUS_ERROR_INVALID_BUFFER; 298b8e80941Smrg 299b8e80941Smrg if (!context->target) 300b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 301b8e80941Smrg 302b8e80941Smrg param = buf->data; 303b8e80941Smrg 304b8e80941Smrg src_surface = handle_table_get(drv->htab, param->surface); 305b8e80941Smrg dst_surface = handle_table_get(drv->htab, context->target_id); 306b8e80941Smrg 307b8e80941Smrg if (!src_surface || !src_surface->buffer) 308b8e80941Smrg return VA_STATUS_ERROR_INVALID_SURFACE; 309b8e80941Smrg 310b8e80941Smrg src = src_surface->buffer; 311b8e80941Smrg 312b8e80941Smrg for (i = 0; i < param->num_filters; i++) { 313b8e80941Smrg vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]); 314b8e80941Smrg VAProcFilterParameterBufferBase *filter; 315b8e80941Smrg 316b8e80941Smrg if (!buf || buf->type != VAProcFilterParameterBufferType) 317b8e80941Smrg return VA_STATUS_ERROR_INVALID_BUFFER; 318b8e80941Smrg 319b8e80941Smrg filter = buf->data; 320b8e80941Smrg switch (filter->type) { 321b8e80941Smrg case VAProcFilterDeinterlacing: { 322b8e80941Smrg VAProcFilterParameterBufferDeinterlacing *deint = buf->data; 323b8e80941Smrg switch (deint->algorithm) { 324b8e80941Smrg case VAProcDeinterlacingBob: 325b8e80941Smrg if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD) 326b8e80941Smrg deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 327b8e80941Smrg else 328b8e80941Smrg deinterlace = VL_COMPOSITOR_BOB_TOP; 329b8e80941Smrg break; 330b8e80941Smrg 331b8e80941Smrg case VAProcDeinterlacingWeave: 332b8e80941Smrg deinterlace = VL_COMPOSITOR_WEAVE; 333b8e80941Smrg break; 334b8e80941Smrg 335b8e80941Smrg case VAProcDeinterlacingMotionAdaptive: 336b8e80941Smrg src = vlVaApplyDeint(drv, context, param, src, 337b8e80941Smrg !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)); 338b8e80941Smrg break; 339b8e80941Smrg 340b8e80941Smrg default: 341b8e80941Smrg return VA_STATUS_ERROR_UNIMPLEMENTED; 342b8e80941Smrg } 343b8e80941Smrg 344b8e80941Smrg break; 345b8e80941Smrg } 346b8e80941Smrg 347b8e80941Smrg default: 348b8e80941Smrg return VA_STATUS_ERROR_UNIMPLEMENTED; 349b8e80941Smrg } 350b8e80941Smrg } 351b8e80941Smrg 352b8e80941Smrg src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region); 353b8e80941Smrg dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region); 354b8e80941Smrg 355b8e80941Smrg if (context->target->buffer_format != PIPE_FORMAT_NV12 && 356b8e80941Smrg context->target->buffer_format != PIPE_FORMAT_P016) 357b8e80941Smrg return vlVaPostProcCompositor(drv, context, src_region, dst_region, 358b8e80941Smrg src, context->target, deinterlace); 359b8e80941Smrg else 360b8e80941Smrg return vlVaPostProcBlit(drv, context, src_region, dst_region, 361b8e80941Smrg src, context->target, deinterlace); 362b8e80941Smrg} 363