Path: blob/21.2-virgl/src/gallium/frontends/xvmc/surface.c
4565 views
/**************************************************************************1*2* Copyright 2009 Younes Manton.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 VMWARE AND/OR ITS SUPPLIERS 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 <assert.h>28#include <stdio.h>2930#include <X11/Xlibint.h>3132#include "pipe/p_video_codec.h"33#include "pipe/p_video_state.h"34#include "pipe/p_state.h"3536#include "util/macros.h"37#include "util/u_inlines.h"38#include "util/u_memory.h"39#include "util/u_math.h"40#include "vl/vl_winsys.h"4142#include "xvmc_private.h"4344static void45MacroBlocksToPipe(XvMCContextPrivate *context,46XvMCSurfacePrivate *surface,47unsigned int xvmc_picture_structure,48const XvMCMacroBlock *xvmc_mb,49const XvMCBlockArray *xvmc_blocks,50struct pipe_mpeg12_macroblock *mb,51unsigned int num_macroblocks)52{53unsigned int i, j, k;5455assert(xvmc_mb);56assert(xvmc_blocks);57assert(num_macroblocks);5859for (; num_macroblocks > 0; --num_macroblocks) {60mb->base.codec = PIPE_VIDEO_FORMAT_MPEG12;61mb->x = xvmc_mb->x;62mb->y = xvmc_mb->y;63mb->macroblock_type = xvmc_mb->macroblock_type;6465switch (xvmc_picture_structure) {66case XVMC_FRAME_PICTURE:67mb->macroblock_modes.bits.frame_motion_type = xvmc_mb->motion_type;68mb->macroblock_modes.bits.field_motion_type = 0;69break;7071case XVMC_TOP_FIELD:72case XVMC_BOTTOM_FIELD:73mb->macroblock_modes.bits.frame_motion_type = 0;74mb->macroblock_modes.bits.field_motion_type = xvmc_mb->motion_type;75break;7677default:78assert(0);79}8081mb->macroblock_modes.bits.dct_type = xvmc_mb->dct_type;82mb->motion_vertical_field_select = xvmc_mb->motion_vertical_field_select;8384for (i = 0; i < 2; ++i)85for (j = 0; j < 2; ++j)86for (k = 0; k < 2; ++k)87mb->PMV[i][j][k] = xvmc_mb->PMV[i][j][k];8889mb->coded_block_pattern = xvmc_mb->coded_block_pattern;90mb->blocks = xvmc_blocks->blocks + xvmc_mb->index * BLOCK_SIZE_SAMPLES;91mb->num_skipped_macroblocks = 0;9293++xvmc_mb;94++mb;95}96}9798static void99GetPictureDescription(XvMCSurfacePrivate *surface, struct pipe_mpeg12_picture_desc *desc)100{101unsigned i, num_refs = 0;102103assert(surface && desc);104105memset(desc, 0, sizeof(*desc));106desc->base.profile = PIPE_VIDEO_PROFILE_MPEG1;107desc->picture_structure = surface->picture_structure;108for (i = 0; i < 2; ++i) {109if (surface->ref[i]) {110XvMCSurfacePrivate *ref = surface->ref[i]->privData;111112if (ref)113desc->ref[num_refs++] = ref->video_buffer;114}115}116}117118static void119RecursiveEndFrame(XvMCSurfacePrivate *surface)120{121XvMCContextPrivate *context_priv;122unsigned i;123124assert(surface);125126context_priv = surface->context->privData;127128for ( i = 0; i < 2; ++i ) {129if (surface->ref[i]) {130XvMCSurface *ref = surface->ref[i];131132assert(ref);133134surface->ref[i] = NULL;135RecursiveEndFrame(ref->privData);136surface->ref[i] = ref;137}138}139140if (surface->picture_structure) {141struct pipe_mpeg12_picture_desc desc;142GetPictureDescription(surface, &desc);143surface->picture_structure = 0;144145for (i = 0; i < 2; ++i)146surface->ref[i] = NULL;147148context_priv->decoder->end_frame(context_priv->decoder, surface->video_buffer, &desc.base);149}150}151152PUBLIC153Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface)154{155XvMCContextPrivate *context_priv;156struct pipe_context *pipe;157XvMCSurfacePrivate *surface_priv;158struct pipe_video_buffer tmpl;159160XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface);161162assert(dpy);163164if (!context)165return XvMCBadContext;166if (!surface)167return XvMCBadSurface;168169context_priv = context->privData;170pipe = context_priv->pipe;171172surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate));173if (!surface_priv)174return BadAlloc;175176memset(&tmpl, 0, sizeof(tmpl));177tmpl.buffer_format = pipe->screen->get_video_param178(179pipe->screen,180context_priv->decoder->profile,181context_priv->decoder->entrypoint,182PIPE_VIDEO_CAP_PREFERED_FORMAT183);184assert(pipe_format_to_chroma_format(tmpl.buffer_format) == context_priv->decoder->chroma_format);185tmpl.width = context_priv->decoder->width;186tmpl.height = context_priv->decoder->height;187tmpl.interlaced = pipe->screen->get_video_param188(189pipe->screen,190context_priv->decoder->profile,191context_priv->decoder->entrypoint,192PIPE_VIDEO_CAP_PREFERS_INTERLACED193);194195surface_priv->video_buffer = pipe->create_video_buffer(pipe, &tmpl);196if (!surface_priv->video_buffer) {197FREE(surface_priv);198return BadAlloc;199}200surface_priv->context = context;201202surface->surface_id = XAllocID(dpy);203surface->context_id = context->context_id;204surface->surface_type_id = context->surface_type_id;205surface->width = context->width;206surface->height = context->height;207surface->privData = surface_priv;208209SyncHandle();210211XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface);212213return Success;214}215216PUBLIC217Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure,218XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface,219unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock,220XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks221)222{223struct pipe_mpeg12_macroblock mb[num_macroblocks];224struct pipe_video_codec *decoder;225struct pipe_mpeg12_picture_desc desc;226227XvMCContextPrivate *context_priv;228XvMCSurfacePrivate *target_surface_priv;229ASSERTED XvMCSurfacePrivate *past_surface_priv;230ASSERTED XvMCSurfacePrivate *future_surface_priv;231XvMCMacroBlock *xvmc_mb;232233XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n",234target_surface, past_surface, future_surface);235236assert(dpy);237238if (!context || !context->privData)239return XvMCBadContext;240if (!target_surface || !target_surface->privData)241return XvMCBadSurface;242243if (picture_structure != XVMC_TOP_FIELD &&244picture_structure != XVMC_BOTTOM_FIELD &&245picture_structure != XVMC_FRAME_PICTURE)246return BadValue;247/* Bkwd pred equivalent to fwd (past && !future) */248if (future_surface && !past_surface)249return BadMatch;250251assert(context->context_id == target_surface->context_id);252assert(!past_surface || context->context_id == past_surface->context_id);253assert(!future_surface || context->context_id == future_surface->context_id);254255assert(macroblocks);256assert(blocks);257258assert(macroblocks->context_id == context->context_id);259assert(blocks->context_id == context->context_id);260261assert(flags == 0 || flags == XVMC_SECOND_FIELD);262263context_priv = context->privData;264decoder = context_priv->decoder;265266target_surface_priv = target_surface->privData;267past_surface_priv = past_surface ? past_surface->privData : NULL;268future_surface_priv = future_surface ? future_surface->privData : NULL;269270assert(target_surface_priv->context == context);271assert(!past_surface || past_surface_priv->context == context);272assert(!future_surface || future_surface_priv->context == context);273274// call end frame on all referenced frames275if (past_surface)276RecursiveEndFrame(past_surface->privData);277278if (future_surface)279RecursiveEndFrame(future_surface->privData);280281xvmc_mb = macroblocks->macro_blocks + first_macroblock;282283/* If the surface we're rendering hasn't changed the ref frames shouldn't change. */284if (target_surface_priv->picture_structure > 0 && (285target_surface_priv->picture_structure != picture_structure ||286target_surface_priv->ref[0] != past_surface ||287target_surface_priv->ref[1] != future_surface ||288(xvmc_mb->x == 0 && xvmc_mb->y == 0))) {289290// If they change anyway we must assume that the current frame is ended291RecursiveEndFrame(target_surface_priv);292}293294target_surface_priv->ref[0] = past_surface;295target_surface_priv->ref[1] = future_surface;296297if (target_surface_priv->picture_structure)298GetPictureDescription(target_surface_priv, &desc);299else {300target_surface_priv->picture_structure = picture_structure;301GetPictureDescription(target_surface_priv, &desc);302decoder->begin_frame(decoder, target_surface_priv->video_buffer, &desc.base);303}304305MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure,306xvmc_mb, blocks, mb, num_macroblocks);307308context_priv->decoder->decode_macroblock(context_priv->decoder,309target_surface_priv->video_buffer,310&desc.base,311&mb[0].base, num_macroblocks);312313XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface);314315return Success;316}317318PUBLIC319Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface)320{321assert(dpy);322323if (!surface)324return XvMCBadSurface;325326// don't call flush here, because this is usually327// called once for every slice instead of every frame328329XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface);330331return Success;332}333334PUBLIC335Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface)336{337assert(dpy);338339if (!surface)340return XvMCBadSurface;341342XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface);343344return Success;345}346347PUBLIC348Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable,349short srcx, short srcy, unsigned short srcw, unsigned short srch,350short destx, short desty, unsigned short destw, unsigned short desth,351int flags)352{353static int dump_window = -1;354355struct pipe_context *pipe;356struct vl_compositor *compositor;357struct vl_compositor_state *cstate;358struct vl_screen *vscreen;359360XvMCSurfacePrivate *surface_priv;361XvMCContextPrivate *context_priv;362XvMCSubpicturePrivate *subpicture_priv;363XvMCContext *context;364struct u_rect src_rect = {srcx, srcx + srcw, srcy, srcy + srch};365struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth};366367struct pipe_resource *tex;368struct pipe_surface surf_templ, *surf;369struct u_rect *dirty_area;370371XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface);372373assert(dpy);374375if (!surface || !surface->privData)376return XvMCBadSurface;377378surface_priv = surface->privData;379context = surface_priv->context;380context_priv = context->privData;381382assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE);383assert(srcx + srcw - 1 < surface->width);384assert(srcy + srch - 1 < surface->height);385386subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL;387pipe = context_priv->pipe;388compositor = &context_priv->compositor;389cstate = &context_priv->cstate;390vscreen = context_priv->vscreen;391392tex = vscreen->texture_from_drawable(vscreen, (void *)drawable);393dirty_area = vscreen->get_dirty_area(vscreen);394395memset(&surf_templ, 0, sizeof(surf_templ));396surf_templ.format = tex->format;397surf = pipe->create_surface(pipe, tex, &surf_templ);398399if (!surf)400return BadDrawable;401402/*403* Some apps (mplayer) hit these asserts because they call404* this function after the window has been resized by the WM405* but before they've handled the corresponding XEvent and406* know about the new dimensions. The output should be clipped407* until the app updates destw and desth.408*/409/*410assert(destx + destw - 1 < drawable_surface->width);411assert(desty + desth - 1 < drawable_surface->height);412*/413414RecursiveEndFrame(surface_priv);415416context_priv->decoder->flush(context_priv->decoder);417418vl_compositor_clear_layers(cstate);419vl_compositor_set_buffer_layer(cstate, compositor, 0, surface_priv->video_buffer,420&src_rect, NULL, VL_COMPOSITOR_WEAVE);421422if (subpicture_priv) {423XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture);424425assert(subpicture_priv->surface == surface);426427if (subpicture_priv->palette)428vl_compositor_set_palette_layer(cstate, compositor, 1, subpicture_priv->sampler, subpicture_priv->palette,429&subpicture_priv->src_rect, &subpicture_priv->dst_rect, true);430else431vl_compositor_set_rgba_layer(cstate, compositor, 1, subpicture_priv->sampler,432&subpicture_priv->src_rect, &subpicture_priv->dst_rect, NULL);433434surface_priv->subpicture = NULL;435subpicture_priv->surface = NULL;436}437438// Workaround for r600g, there seems to be a bug in the fence refcounting code439pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL);440441vl_compositor_set_layer_dst_area(cstate, 0, &dst_rect);442vl_compositor_set_layer_dst_area(cstate, 1, &dst_rect);443vl_compositor_render(cstate, compositor, surf, dirty_area, true);444445pipe->flush(pipe, &surface_priv->fence, 0);446447XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface);448449pipe->screen->flush_frontbuffer(pipe->screen, pipe, tex, 0, 0,450vscreen->get_private(vscreen), NULL);451452if(dump_window == -1) {453dump_window = debug_get_num_option("XVMC_DUMP", 0);454}455456if(dump_window) {457static unsigned int framenum = 0;458char cmd[256];459460sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum);461if (system(cmd) != 0)462XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface);463}464465XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface);466467return Success;468}469470PUBLIC471Status XvMCGetSurfaceStatus(Display *dpy, XvMCSurface *surface, int *status)472{473struct pipe_context *pipe;474XvMCSurfacePrivate *surface_priv;475XvMCContextPrivate *context_priv;476477assert(dpy);478479if (!surface)480return XvMCBadSurface;481482assert(status);483484surface_priv = surface->privData;485context_priv = surface_priv->context->privData;486pipe = context_priv->pipe;487488*status = 0;489490if (surface_priv->fence)491if (!pipe->screen->fence_finish(pipe->screen, NULL, surface_priv->fence, 0))492*status |= XVMC_RENDERING;493494return Success;495}496497PUBLIC498Status XvMCDestroySurface(Display *dpy, XvMCSurface *surface)499{500XvMCSurfacePrivate *surface_priv;501XvMCContextPrivate *context_priv;502503XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying surface %p.\n", surface);504505assert(dpy);506507if (!surface || !surface->privData)508return XvMCBadSurface;509510surface_priv = surface->privData;511context_priv = surface_priv->context->privData;512513if (surface_priv->picture_structure) {514struct pipe_mpeg12_picture_desc desc;515GetPictureDescription(surface_priv, &desc);516context_priv->decoder->end_frame(context_priv->decoder, surface_priv->video_buffer, &desc.base);517}518surface_priv->video_buffer->destroy(surface_priv->video_buffer);519FREE(surface_priv);520surface->privData = NULL;521522XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p destroyed.\n", surface);523524return Success;525}526527PUBLIC528Status XvMCHideSurface(Display *dpy, XvMCSurface *surface)529{530assert(dpy);531532if (!surface || !surface->privData)533return XvMCBadSurface;534535/* No op, only for overlaid rendering */536537return Success;538}539540541