Path: blob/21.2-virgl/src/gallium/frontends/va/postproc.c
4561 views
/**************************************************************************1*2* Copyright 2015 Advanced Micro Devices, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627#include "util/u_handle_table.h"28#include "util/u_memory.h"29#include "util/u_compute.h"3031#include "vl/vl_defines.h"32#include "vl/vl_video_buffer.h"33#include "vl/vl_deint_filter.h"3435#include "va_private.h"3637static const VARectangle *38vlVaRegionDefault(const VARectangle *region, vlVaSurface *surf,39VARectangle *def)40{41if (region)42return region;4344def->x = 0;45def->y = 0;46def->width = surf->templat.width;47def->height = surf->templat.height;4849return def;50}5152static VAStatus53vlVaPostProcCompositor(vlVaDriver *drv, vlVaContext *context,54const VARectangle *src_region,55const VARectangle *dst_region,56struct pipe_video_buffer *src,57struct pipe_video_buffer *dst,58enum vl_compositor_deinterlace deinterlace)59{60struct pipe_surface **surfaces;61struct u_rect src_rect;62struct u_rect dst_rect;6364surfaces = dst->get_surfaces(dst);65if (!surfaces || !surfaces[0])66return VA_STATUS_ERROR_INVALID_SURFACE;6768src_rect.x0 = src_region->x;69src_rect.y0 = src_region->y;70src_rect.x1 = src_region->x + src_region->width;71src_rect.y1 = src_region->y + src_region->height;7273dst_rect.x0 = dst_region->x;74dst_rect.y0 = dst_region->y;75dst_rect.x1 = dst_region->x + dst_region->width;76dst_rect.y1 = dst_region->y + dst_region->height;7778vl_compositor_clear_layers(&drv->cstate);79vl_compositor_set_buffer_layer(&drv->cstate, &drv->compositor, 0, src,80&src_rect, NULL, deinterlace);81vl_compositor_set_layer_dst_area(&drv->cstate, 0, &dst_rect);82vl_compositor_render(&drv->cstate, &drv->compositor, surfaces[0], NULL, false);8384drv->pipe->flush(drv->pipe, NULL, 0);85return VA_STATUS_SUCCESS;86}8788static void vlVaGetBox(struct pipe_video_buffer *buf, unsigned idx,89struct pipe_box *box, const VARectangle *region)90{91unsigned plane = buf->interlaced ? idx / 2: idx;92unsigned x, y, width, height;9394x = abs(region->x);95y = abs(region->y);96width = region->width;97height = region->height;9899vl_video_buffer_adjust_size(&x, &y, plane,100pipe_format_to_chroma_format(buf->buffer_format),101buf->interlaced);102vl_video_buffer_adjust_size(&width, &height, plane,103pipe_format_to_chroma_format(buf->buffer_format),104buf->interlaced);105106box->x = region->x < 0 ? -x : x;107box->y = region->y < 0 ? -y : y;108box->width = width;109box->height = height;110}111112static VAStatus vlVaPostProcBlit(vlVaDriver *drv, vlVaContext *context,113const VARectangle *src_region,114const VARectangle *dst_region,115struct pipe_video_buffer *src,116struct pipe_video_buffer *dst,117enum vl_compositor_deinterlace deinterlace)118{119struct pipe_surface **src_surfaces;120struct pipe_surface **dst_surfaces;121struct u_rect src_rect;122struct u_rect dst_rect;123bool scale = false;124bool grab = false;125unsigned i;126127if ((src->buffer_format == PIPE_FORMAT_B8G8R8A8_UNORM ||128src->buffer_format == PIPE_FORMAT_B8G8R8X8_UNORM) &&129!src->interlaced)130grab = true;131132if ((src->width != dst->width || src->height != dst->height) &&133(src->interlaced && dst->interlaced))134scale = true;135136src_surfaces = src->get_surfaces(src);137if (!src_surfaces || !src_surfaces[0])138return VA_STATUS_ERROR_INVALID_SURFACE;139140if (scale || (src->interlaced != dst->interlaced && dst->interlaced)) {141vlVaSurface *surf;142143surf = handle_table_get(drv->htab, context->target_id);144surf->templat.interlaced = false;145dst->destroy(dst);146147if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)148return VA_STATUS_ERROR_ALLOCATION_FAILED;149150dst = context->target = surf->buffer;151}152153dst_surfaces = dst->get_surfaces(dst);154if (!dst_surfaces || !dst_surfaces[0])155return VA_STATUS_ERROR_INVALID_SURFACE;156157src_rect.x0 = src_region->x;158src_rect.y0 = src_region->y;159src_rect.x1 = src_region->x + src_region->width;160src_rect.y1 = src_region->y + src_region->height;161162dst_rect.x0 = dst_region->x;163dst_rect.y0 = dst_region->y;164dst_rect.x1 = dst_region->x + dst_region->width;165dst_rect.y1 = dst_region->y + dst_region->height;166167if (grab) {168vl_compositor_convert_rgb_to_yuv(&drv->cstate, &drv->compositor, 0,169((struct vl_video_buffer *)src)->resources[0],170dst, &src_rect, &dst_rect);171172return VA_STATUS_SUCCESS;173}174175if (src->interlaced != dst->interlaced) {176vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor,177src, dst, &src_rect, &dst_rect,178deinterlace);179180return VA_STATUS_SUCCESS;181}182183for (i = 0; i < VL_MAX_SURFACES; ++i) {184struct pipe_surface *from = src_surfaces[i];185struct pipe_blit_info blit;186187if (src->interlaced) {188/* Not 100% accurate, but close enough */189switch (deinterlace) {190case VL_COMPOSITOR_BOB_TOP:191from = src_surfaces[i & ~1];192break;193case VL_COMPOSITOR_BOB_BOTTOM:194from = src_surfaces[(i & ~1) + 1];195break;196default:197break;198}199}200201if (!from || !dst_surfaces[i])202continue;203204memset(&blit, 0, sizeof(blit));205blit.src.resource = from->texture;206blit.src.format = from->format;207blit.src.level = 0;208blit.src.box.z = from->u.tex.first_layer;209blit.src.box.depth = 1;210vlVaGetBox(src, i, &blit.src.box, src_region);211212blit.dst.resource = dst_surfaces[i]->texture;213blit.dst.format = dst_surfaces[i]->format;214blit.dst.level = 0;215blit.dst.box.z = dst_surfaces[i]->u.tex.first_layer;216blit.dst.box.depth = 1;217vlVaGetBox(dst, i, &blit.dst.box, dst_region);218219blit.mask = PIPE_MASK_RGBA;220blit.filter = PIPE_TEX_MIPFILTER_LINEAR;221222if (drv->pipe->screen->get_param(drv->pipe->screen,223PIPE_CAP_PREFER_COMPUTE_FOR_MULTIMEDIA))224util_compute_blit(drv->pipe, &blit, &context->blit_cs, !drv->compositor.deinterlace);225else226drv->pipe->blit(drv->pipe, &blit);227}228229// TODO: figure out why this is necessary for DMA-buf sharing230drv->pipe->flush(drv->pipe, NULL, 0);231232return VA_STATUS_SUCCESS;233}234235static struct pipe_video_buffer *236vlVaApplyDeint(vlVaDriver *drv, vlVaContext *context,237VAProcPipelineParameterBuffer *param,238struct pipe_video_buffer *current,239unsigned field)240{241vlVaSurface *prevprev, *prev, *next;242243if (param->num_forward_references < 2 ||244param->num_backward_references < 1)245return current;246247prevprev = handle_table_get(drv->htab, param->forward_references[1]);248prev = handle_table_get(drv->htab, param->forward_references[0]);249next = handle_table_get(drv->htab, param->backward_references[0]);250251if (!prevprev || !prev || !next)252return current;253254if (context->deint && (context->deint->video_width != current->width ||255context->deint->video_height != current->height)) {256vl_deint_filter_cleanup(context->deint);257FREE(context->deint);258context->deint = NULL;259}260261if (!context->deint) {262context->deint = MALLOC(sizeof(struct vl_deint_filter));263if (!vl_deint_filter_init(context->deint, drv->pipe, current->width,264current->height, false, false)) {265FREE(context->deint);266context->deint = NULL;267return current;268}269}270271if (!vl_deint_filter_check_buffers(context->deint, prevprev->buffer,272prev->buffer, current, next->buffer))273return current;274275vl_deint_filter_render(context->deint, prevprev->buffer, prev->buffer,276current, next->buffer, field);277return context->deint->video_buffer;278}279280VAStatus281vlVaHandleVAProcPipelineParameterBufferType(vlVaDriver *drv, vlVaContext *context, vlVaBuffer *buf)282{283enum vl_compositor_deinterlace deinterlace = VL_COMPOSITOR_NONE;284VARectangle def_src_region, def_dst_region;285const VARectangle *src_region, *dst_region;286VAProcPipelineParameterBuffer *param;287struct pipe_video_buffer *src, *dst;288vlVaSurface *src_surface, *dst_surface;289unsigned i;290291if (!drv || !context)292return VA_STATUS_ERROR_INVALID_CONTEXT;293294if (!buf || !buf->data)295return VA_STATUS_ERROR_INVALID_BUFFER;296297if (!context->target)298return VA_STATUS_ERROR_INVALID_SURFACE;299300param = buf->data;301302src_surface = handle_table_get(drv->htab, param->surface);303dst_surface = handle_table_get(drv->htab, context->target_id);304305if (!src_surface || !src_surface->buffer)306return VA_STATUS_ERROR_INVALID_SURFACE;307308src = src_surface->buffer;309dst = dst_surface->buffer;310311/* convert the destination buffer to progressive if we're deinterlacing312otherwise we might end up deinterlacing twice */313if (param->num_filters && dst->interlaced) {314vlVaSurface *surf;315surf = dst_surface;316surf->templat.interlaced = false;317dst->destroy(dst);318319if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat, NULL, 0) != VA_STATUS_SUCCESS)320return VA_STATUS_ERROR_ALLOCATION_FAILED;321322dst = context->target = surf->buffer;323}324325for (i = 0; i < param->num_filters; i++) {326vlVaBuffer *buf = handle_table_get(drv->htab, param->filters[i]);327VAProcFilterParameterBufferBase *filter;328329if (!buf || buf->type != VAProcFilterParameterBufferType)330return VA_STATUS_ERROR_INVALID_BUFFER;331332filter = buf->data;333switch (filter->type) {334case VAProcFilterDeinterlacing: {335VAProcFilterParameterBufferDeinterlacing *deint = buf->data;336switch (deint->algorithm) {337case VAProcDeinterlacingBob:338if (deint->flags & VA_DEINTERLACING_BOTTOM_FIELD)339deinterlace = VL_COMPOSITOR_BOB_BOTTOM;340else341deinterlace = VL_COMPOSITOR_BOB_TOP;342break;343344case VAProcDeinterlacingWeave:345deinterlace = VL_COMPOSITOR_WEAVE;346break;347348case VAProcDeinterlacingMotionAdaptive:349src = vlVaApplyDeint(drv, context, param, src,350!!(deint->flags & VA_DEINTERLACING_BOTTOM_FIELD));351deinterlace = VL_COMPOSITOR_MOTION_ADAPTIVE;352break;353354default:355return VA_STATUS_ERROR_UNIMPLEMENTED;356}357drv->compositor.deinterlace = deinterlace;358break;359}360361default:362return VA_STATUS_ERROR_UNIMPLEMENTED;363}364}365366src_region = vlVaRegionDefault(param->surface_region, src_surface, &def_src_region);367dst_region = vlVaRegionDefault(param->output_region, dst_surface, &def_dst_region);368369if (context->target->buffer_format != PIPE_FORMAT_NV12 &&370context->target->buffer_format != PIPE_FORMAT_P010 &&371context->target->buffer_format != PIPE_FORMAT_P016)372return vlVaPostProcCompositor(drv, context, src_region, dst_region,373src, context->target, deinterlace);374else375return vlVaPostProcBlit(drv, context, src_region, dst_region,376src, context->target, deinterlace);377}378379380