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 30#include "vl/vl_defines.h" 31#include "vl/vl_video_buffer.h" 32#include "vl/vl_deint_filter.h" 33 34#include "va_private.h" 35 36static const VARectangle * 37vlVaRegionDefault(const VARectangle *region, struct pipe_video_buffer *buf, 38 VARectangle *def) 39{ 40 if (region) 41 return region; 42 43 def->x = 0; 44 def->y = 0; 45 def->width = buf->width; 46 def->height = buf->height; 47 48 return def; 49} 50 51static VAStatus 52vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context, 53 const VARectangle *src_region, 54 const VARectangle *dst_region, 55 struct pipe_video_buffer *src, 56 struct pipe_video_buffer *dst, 57 enum vl_compositor_deinterlace deinterlace) 58{ 59 struct pipe_surface **surfaces; 60 struct u_rect src_rect; 61 struct u_rect dst_rect; 62 63 surfaces = dst->get_surfaces(dst); 64 if (!surfaces || !surfaces[0]) 65 return VA_STATUS_ERROR_INVALID_SURFACE; 66 67 src_rect.x0 = src_region->x; 68 src_rect.y0 = src_region->y; 69 src_rect.x1 = src_region->x + src_region->width; 70 src_rect.y1 = src_region->y + src_region->height; 71 72 dst_rect.x0 = dst_region->x; 73 dst_rect.y0 = dst_region->y; 74 dst_rect.x1 = dst_region->x + dst_region->width; 75 dst_rect.y1 = dst_region->y + dst_region->height; 76 77 vl_compositor_clear_layers(&drv->cstate); 78 vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src, 79 &src_rect, NULL, deinterlace); 80 vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect); 81 vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false); 82 83 drv->pipe->flush(drv->pipe, NULL, 0); 84 return VA_STATUS_SUCCESS; 85} 86 87static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx, 88 struct pipe_box *box, const VARectangle *region) 89{ 90 unsigned plane = buf->interlaced ? idx / 2: idx; 91 unsigned x, y, width, height; 92 93 x = abs(region->x); 94 y = abs(region->y); 95 width = region->width; 96 height = region->height; 97 98 vl_video_buffer_adjust_size(&x, &y, plane, buf->chroma_format, 99 buf->interlaced); 100 vl_video_buffer_adjust_size(&width, &height, plane, buf->chroma_format, 101 buf->interlaced); 102 103 box->x = region->x < 0 ? -x : x; 104 box->y = region->y < 0 ? -y : y; 105 box->width = width; 106 box->height = height; 107} 108 109static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context, 110 const VARectangle *src_region, 111 const VARectangle *dst_region, 112 struct pipe_video_buffer *src, 113 struct pipe_video_buffer *dst, 114 enum vl_compositor_deinterlace deinterlace) 115{ 116 struct pipe_surface **src_surfaces; 117 struct pipe_surface **dst_surfaces; 118 unsigned i; 119 120 if (src->interlaced != dst->interlaced) 121 return VA_STATUS_ERROR_INVALID_SURFACE; 122 123 src_surfaces = src->get_surfaces(src); 124 if (!src_surfaces || !src_surfaces[0]) 125 return VA_STATUS_ERROR_INVALID_SURFACE; 126 127 dst_surfaces = dst->get_surfaces(dst); 128 if (!dst_surfaces || !dst_surfaces[0]) 129 return VA_STATUS_ERROR_INVALID_SURFACE; 130 131 for (i = 0; i < VL_MAX_SURFACES; ++i) { 132 struct pipe_surface *from = src_surfaces[i]; 133 struct pipe_blit_info blit; 134 135 if (src->interlaced) { 136 /* Not 100% accurate, but close enough */ 137 switch (deinterlace) { 138 case VL_COMPOSITOR_BOB_TOP: 139 from = src_surfaces[i & ~1]; 140 break; 141 case VL_COMPOSITOR_BOB_BOTTOM: 142 from = src_surfaces[(i & ~1) + 1]; 143 break; 144 default: 145 break; 146 } 147 } 148 149 if (!from || !dst_surfaces[i]) 150 continue; 151 152 memset(&blit, 0, sizeof(blit)); 153 blit.src.resource = from->texture; 154 blit.src.format = from->format; 155 blit.src.level = 0; 156 blit.src.box.z = from->u.tex.first_layer; 157 blit.src.box.depth = 1; 158 vlVaGetBox(src, i, &blit.src.box, src_region); 159 160 blit.dst.resource = dst_surfaces[i]->texture; 161 blit.dst.format = dst_surfaces[i]->format; 162 blit.dst.level = 0; 163 blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer; 164 blit.dst.box.depth = 1; 165 vlVaGetBox(dst, i, &blit.dst.box, dst_region); 166 167 blit.mask = PIPE_MASK_RGBA; 168 blit.filter = PIPE_TEX_MIPFILTER_LINEAR; 169 170 drv->pipe->blit(drv->pipe, &blit); 171 } 172 173 // TODO: figure out why this is necessary for DMA-buf sharing 174 drv->pipe->flush(drv->pipe, NULL, 0); 175 176 return VA_STATUS_SUCCESS; 177} 178 179static struct pipe_video_buffer * 180vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context, 181 VAProcPipelineParameterBuffer *param, 182 struct pipe_video_buffer *current, 183 unsigned field) 184{ 185 vlVaSurface *prevprev, *prev, *next; 186 187 if (param->num_forward_references < 1 || 188 param->num_backward_references < 2) 189 return current; 190 191 prevprev = handle_table_get(drv->htab, param->backward_references[1]); 192 prev = handle_table_get(drv->htab, param->backward_references[0]); 193 next = handle_table_get(drv->htab, param->forward_references[0]); 194 195 if (!prevprev || !prev || !next) 196 return current; 197 198 if (context->deint && (context->deint->video_width != current->width || 199 context->deint->video_height != current->height)) { 200 vl_deint_filter_cleanup(context->deint); 201 FREE(context->deint); 202 context->deint = NULL; 203 } 204 205 if (!context->deint) { 206 context->deint = MALLOC(sizeof(struct vl_deint_filter)); 207 if (!vl_deint_filter_init(context->deint, drv->pipe, current->width, 208 current->height, false, false)) { 209 FREE(context->deint); 210 context->deint = NULL; 211 return current; 212 } 213 } 214 215 if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer, 216 prev->buffer, current, next->buffer)) 217 return current; 218 219 vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer, 220 current, next->buffer, field); 221 return context->deint->video_buffer; 222} 223 224VAStatus 225vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf) 226{ 227 enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_WEAVE; 228 VARectangle def_src_region, def_dst_region; 229 const VARectangle *src_region, *dst_region; 230 VAProcPipelineParameterBuffer *param; 231 struct pipe_video_buffer *src; 232 vlVaSurface *src_surface; 233 unsigned i; 234 235 if (!drv || !context) 236 return VA_STATUS_ERROR_INVALID_CONTEXT; 237 238 if (!buf || !buf->data) 239 return VA_STATUS_ERROR_INVALID_BUFFER; 240 241 if (!context->target) 242 return VA_STATUS_ERROR_INVALID_SURFACE; 243 244 param = buf->data; 245 246 src_surface = handle_table_get(drv->htab, param->surface); 247 if (!src_surface || !src_surface->buffer) 248 return VA_STATUS_ERROR_INVALID_SURFACE; 249 250 src = src_surface->buffer; 251 252 for (i = 0; i < param->num_filters; i++) { 253 vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]); 254 VAProcFilterParameterBufferBase *filter; 255 256 if (!buf || buf->type != VAProcFilterParameterBufferType) 257 return VA_STATUS_ERROR_INVALID_BUFFER; 258 259 filter = buf->data; 260 switch (filter->type) { 261 case VAProcFilterDeinterlacing: { 262 VAProcFilterParameterBufferDeinterlacing *deint = buf->data; 263 switch (deint->algorithm) { 264 case VAProcDeinterlacingBob: 265 if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD) 266 deinterlace = VL_COMPOSITOR_BOB_BOTTOM; 267 else 268 deinterlace = VL_COMPOSITOR_BOB_TOP; 269 break; 270 271 case VAProcDeinterlacingWeave: 272 deinterlace = VL_COMPOSITOR_WEAVE; 273 break; 274 275 case VAProcDeinterlacingMotionAdaptive: 276 src = vlVaApplyDeint(drv, context, param, src, 277 !!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)); 278 break; 279 280 default: 281 return VA_STATUS_ERROR_UNIMPLEMENTED; 282 } 283 284 break; 285 } 286 287 default: 288 return VA_STATUS_ERROR_UNIMPLEMENTED; 289 } 290 } 291 292 src_region = vlVaRegionDefault(param->surface_region, src_surface->buffer, &def_src_region); 293 dst_region = vlVaRegionDefault(param->output_region, context->target, &def_dst_region); 294 295 if (context->target->buffer_format != PIPE_FORMAT_NV12) 296 return vlVaPostProcCompositor(drv, context, src_region, dst_region, 297 src, context->target, deinterlace); 298 else 299 return vlVaPostProcBlit(drv, context, src_region, dst_region, 300 src, context->target, deinterlace); 301} 302