From 1902b5896cee6fbbeadf735a05737b0ff3ca51a4 Mon Sep 17 00:00:00 2001 From: iive Date: Mon, 25 Aug 2003 21:41:10 +0000 Subject: OSD support, optinal queue, optional use of sleep(), and benchmark mode git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@10699 b3059339-0415-0410-9bf9-f77b7e298cf2 --- libvo/vo_xvmc.c | 848 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 709 insertions(+), 139 deletions(-) (limited to 'libvo') diff --git a/libvo/vo_xvmc.c b/libvo/vo_xvmc.c index 4742572095..939f263fd5 100644 --- a/libvo/vo_xvmc.c +++ b/libvo/vo_xvmc.c @@ -1,20 +1,29 @@ #include #include #include +#include + +#include "config.h" +#include "mp_msg.h" +#include "video_out.h" +#include "video_out_internal.h" +#include "fastmemcpy.h" +#include "osdep/timer.h" #include #include #include + +#ifdef HAVE_SHM +#include +#include +#include +#endif + #include #include #include -#include "config.h" -#include "mp_msg.h" -#include "video_out.h" -#include "video_out_internal.h" -#include "fastmemcpy.h" - #include "x11_common.h" #include "xvmc_render.h" @@ -25,12 +34,12 @@ #include "../Gui/interface.h" #endif +//no chanse xinerama to be suported in near future #undef HAVE_XINERAMA #undef NDEBUG #include -//no chanse xinerama to be suported in near future #define UNUSED(x) ((void)(x)) @@ -38,17 +47,33 @@ extern int vo_directrendering; extern int vo_verbose; -static void xvmc_free(void); +static int benchmark; +static int busy_wait; +static int use_queue; static int image_width,image_height; static uint32_t drwX,drwY; static XvPortID xv_port; -//0-auto;1-backgound always keycolor;2-autopaint(by X);3-manual fill +#define AUTO_COLORKEY 0 +#define BACKGROUND_COLORKEY 1 +#define AUTOPAINT_COLORKEY 2 +#define MANUALFILL_COLORKEY 3 static int keycolor_handling; static unsigned long keycolor; +#define NO_SUBPICTURE 0 +#define OVERLAY_SUBPICTURE 1 +#define BLEND_SUBPICTURE 2 +#define BACKEND_SUBPICTURE 3 + +static int subpicture_mode; +static int subpicture_alloc; +static XvMCSubpicture subpicture; +static XvImageFormatValues subpicture_info; +static int subpicture_clear_color;//transparent color for the subpicture or color key for overlay + static XvMCSurfaceInfo surface_info; static XvMCContext ctx; static XvMCBlockArray data_blocks; @@ -62,6 +87,36 @@ static xvmc_render_state_t * surface_render; static xvmc_render_state_t * p_render_surface_to_show=NULL; static xvmc_render_state_t * p_render_surface_visible=NULL; +//display queue, kinda render ahead +static xvmc_render_state_t * show_queue[MAX_SURFACES]; +static int free_element; + + +static void (*draw_osd_fnc)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride); +static void (*clear_osd_fnc)(int x0,int y0, int w,int h); +static void (*init_osd_fnc)(void); + +static void draw_osd_AI44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride); +static void draw_osd_IA44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride); +static void clear_osd_subpic(int x0,int y0, int w,int h); +static void init_osd_yuv_pal(void); + + +static const struct{ + int id;//id as xvimages or as mplayer RGB|{8,15,16,24,32} + void (* init_func_ptr)(); + void (* draw_func_ptr)(); + void (* clear_func_ptr)(); + } osd_render[]={ + {0x34344149,init_osd_yuv_pal,draw_osd_AI44,clear_osd_subpic}, + {0x34344941,init_osd_yuv_pal,draw_osd_IA44,clear_osd_subpic}, + {0,NULL,NULL,NULL} + }; + +static void xvmc_free(void); +static int count_free_surfaces(); +static xvmc_render_state_t * find_free_surface(); + static vo_info_t info = { "XVideo Motion Compensation", "xvmc", @@ -71,6 +126,76 @@ static vo_info_t info = { LIBVO_EXTERN(xvmc); +//shm stuff from vo_xv +#ifdef HAVE_SHM +/* since it doesn't seem to be defined on some platforms */ +int XShmGetEventBase(Display*); +static XShmSegmentInfo Shminfo; +static int Shmem_Flag; +#endif +XvImage * xvimage; + + +static void allocate_xvimage(int xvimage_width,int xvimage_height,int xv_format) +{ + /* + * allocate XvImages. FIXME: no error checking, without + * mit-shm this will bomb... trzing to fix ::atmos + */ +#ifdef HAVE_SHM + if ( mLocalDisplay && XShmQueryExtension( mDisplay ) ) Shmem_Flag = 1; + else + { + Shmem_Flag = 0; + mp_msg(MSGT_VO,MSGL_INFO, "Shared memory not supported\nReverting to normal Xv\n" ); + } + if ( Shmem_Flag ) + { + xvimage = (XvImage *) XvShmCreateImage(mDisplay, xv_port, xv_format, + NULL, xvimage_width, xvimage_height, &Shminfo); + + Shminfo.shmid = shmget(IPC_PRIVATE, xvimage->data_size, IPC_CREAT | 0777); + Shminfo.shmaddr = (char *) shmat(Shminfo.shmid, 0, 0); + Shminfo.readOnly = False; + + xvimage->data = Shminfo.shmaddr; + XShmAttach(mDisplay, &Shminfo); + XSync(mDisplay, False); + shmctl(Shminfo.shmid, IPC_RMID, 0); + } + else +#endif + { + xvimage = (XvImage *) XvCreateImage(mDisplay, xv_port, xv_format, NULL, xvimage_width, xvimage_height); + xvimage->data = malloc(xvimage->data_size); + XSync(mDisplay,False); + } +// memset(xvimage->data,128,xvimage->data_size); + return; +} + +static void deallocate_xvimage() +{ +#ifdef HAVE_SHM + if ( Shmem_Flag ) + { + XShmDetach( mDisplay,&Shminfo ); + shmdt( Shminfo.shmaddr ); + } + else +#endif + { + free(xvimage->data); + } + XFree(xvimage); + + XFlush( mDisplay ); + XSync(mDisplay, False); + return; +} +//end of vo_xv shm/xvimage code + + static void init_keycolor(){ Atom xv_atom; XvAttribute * attributes; @@ -80,10 +205,10 @@ int attrib_count,i; keycolor=2110; - if(keycolor_handling == 0){ + if(keycolor_handling == AUTO_COLORKEY){ //XV_AUTOPING_COLORKEY doesn't work for XvMC yet(NVidia 43.63) attributes = XvQueryPortAttributes(mDisplay, xv_port, &attrib_count); - if(attributes!=NULL) + if(attributes!=NULL) for (i = 0; i < attrib_count; i++) if (!strcmp(attributes[i].name, "XV_AUTOPAINT_COLORKEY")) { @@ -92,7 +217,7 @@ int attrib_count,i; { rez=XvSetPortAttribute(mDisplay, xv_port, xv_atom, 1); if(rez == Success) - keycolor_handling = 2;//this is the way vo_xv works + keycolor_handling = AUTOPAINT_COLORKEY; } break; } @@ -103,9 +228,9 @@ int attrib_count,i; if(xv_atom == None) return; rez=XvGetPortAttribute(mDisplay,xv_port, xv_atom, &colorkey); if(rez == Success){ - keycolor=colorkey; - if(keycolor_handling == 0){ - keycolor_handling = 3; + keycolor = colorkey; + if(keycolor_handling == AUTO_COLORKEY){ + keycolor_handling = MANUALFILL_COLORKEY; } } } @@ -113,20 +238,21 @@ int attrib_count,i; //from vo_xmga static void mDrawColorKey(uint32_t x,uint32_t y, uint32_t w, uint32_t h) { - if( (keycolor_handling != 2) && (keycolor_handling != 3) ) - return ;//unknown method + if( (keycolor_handling != AUTOPAINT_COLORKEY) && + (keycolor_handling != MANUALFILL_COLORKEY) ) + return; XSetBackground( mDisplay,vo_gc,0 ); XClearWindow( mDisplay,vo_window ); - - if(keycolor_handling == 3){ + + if(keycolor_handling == MANUALFILL_COLORKEY){ XSetForeground( mDisplay,vo_gc,keycolor ); XFillRectangle( mDisplay,vo_window,vo_gc,x,y,w,h); } XFlush( mDisplay ); } -// now it is ugly, but i need it working + static int xvmc_check_surface_format(uint32_t format, XvMCSurfaceInfo * surf_info){ if ( format == IMGFMT_XVMC_IDCT_MPEG2 ){ if( surf_info->mc_type != (XVMC_IDCT|XVMC_MPEG_2) ) return -1; @@ -141,16 +267,72 @@ static int xvmc_check_surface_format(uint32_t format, XvMCSurfaceInfo * surf_inf return -1;//fail } +//print all info needed to add new format +static void print_xvimage_format_values(XvImageFormatValues *xifv){ +int i; + printf("Format_ID = 0x%X\n",xifv->id); + + printf(" type = "); + if(xifv->type == XvRGB) printf("RGB\n"); + else if(xifv->type == XvYUV) printf("YUV\n"); + else printf("Unknown\n"); + + printf(" byte_order = "); + if(xifv->byte_order == LSBFirst) printf("LSB First\n"); + else if(xifv->type == MSBFirst) printf("MSB First\n"); + else printf("Unknown\n");//yes Linux support other types too + + printf(" guid = "); + for(i=0;i<16;i++) + printf("%02X ",(unsigned char)xifv->guid[i]); + printf("\n"); + + printf(" bits_per_pixel = %d\n",xifv->bits_per_pixel); + + printf(" format = "); + if(xifv->format == XvPacked) printf("XvPacked\n"); + else if(xifv->format == XvPlanar) printf("XvPlanar\n"); + else printf("Unknown\n"); + + printf(" num_planes = %d\n",xifv->num_planes); + + if(xifv->type == XvRGB){ + printf(" red_mask = %0X\n", xifv->red_mask); + printf(" green_mask = %0X\n",xifv->green_mask); + printf(" blue_mask = %0X\n", xifv->blue_mask); + } + if(xifv->type == XvYUV){ + printf(" y_sample_bits = %d\n u_sample_bits = %d\n v_sample_bits = %d\n", + xifv->y_sample_bits,xifv->u_sample_bits,xifv->v_sample_bits); + printf(" horz_y_period = %d\n horz_u_period = %d\n horz_v_period = %d\n", + xifv->horz_y_period,xifv->horz_u_period,xifv->horz_v_period); + printf(" vert_y_period = %d\n vert_u_period = %d\n vert_v_period = %d\n", + xifv->vert_y_period,xifv->vert_u_period,xifv->vert_v_period); + + printf(" component_order = "); + for(i=0;i<32;i++) + if(xifv->component_order[i]>=32) + printf("%c",xifv->component_order[i]); + printf("\n"); + + printf(" scanline = "); + if(xifv->scanline_order == XvTopToBottom) printf("XvTopToBottom\n"); + else if(xifv->scanline_order == XvBottomToTop) printf("XvBottomToTop\n"); + else printf("Unknown\n"); + } + printf("\n"); +} + // WARNING This function may changes xv_port and surface_info! -static int xvmc_find_surface_by_format(int format,int width,int height, - XvMCSurfaceInfo * surf_info,int query){ +static int xvmc_find_surface_by_format(int format,int width,int height, + XvMCSurfaceInfo * surf_info,int query){ int rez; XvAdaptorInfo * ai; int num_adaptors,i; unsigned long p; int s,mc_surf_num; XvMCSurfaceInfo * mc_surf_list; - + rez = XvQueryAdaptors(mDisplay,DefaultRootWindow(mDisplay),&num_adaptors,&ai); if( rez != Success ) return -1; if( verbose > 2 ) printf("vo_xvmc: Querying %d adaptors\n",num_adaptors); @@ -171,13 +353,13 @@ XvMCSurfaceInfo * mc_surf_list; //we have XvMC list! for(s=0; s mc_surf_list[s].max_width ) continue; - if( height > mc_surf_list[s].max_height ) continue; + if( width > mc_surf_list[s].max_width ) continue; + if( height > mc_surf_list[s].max_height ) continue; if( xvmc_check_surface_format(format,&mc_surf_list[s])<0 ) continue; //we have match! - - if(!query){ - rez = XvGrabPort(mDisplay,p,CurrentTime); + + if(!query){ + rez = XvGrabPort(mDisplay,p,CurrentTime); if(rez != Success){ if (verbose > 2) printf("vo_xvmc: Fail to grab port %ld\n",p); continue; @@ -190,7 +372,7 @@ XvMCSurfaceInfo * mc_surf_list; XFree(mc_surf_list);//if mc_surf_num==0 is list==NULL ? }//for ports }//for adaptors - + if(!query) printf("vo_xvmc: Could not find free matching surface. Sorry.\n"); return 0; @@ -210,7 +392,7 @@ xvmc_render_state_t * rndr; assert(mpi!=NULL); assert(mpi->flags &MP_IMGFLAG_DIRECT); // assert(mpi->flags &MP_IMGFLAGS_DRAWBACK); - + rndr = (xvmc_render_state_t*)mpi->priv;//there is copy in plane[2] assert( rndr != NULL ); assert( rndr->magic == MP_XVMC_RENDER_MAGIC ); @@ -227,10 +409,10 @@ int xv_version,xv_release,xv_request_base,xv_event_base,xv_error_base; int mc_eventBase,mc_errorBase; int mc_ver,mc_rev; -//Obtain display handler + //Obtain display handler if (!vo_init()) return -1;//vo_xv - //XvMC is subdivision of XVideo + //XvMC is subdivision of XVideo if (Success != XvQueryExtension(mDisplay,&xv_version,&xv_release,&xv_request_base, &xv_event_base,&xv_error_base) ){ mp_msg(MSGT_VO,MSGL_ERR,"Sorry, Xv(MC) not supported by this X11 version/driver\n"); @@ -238,13 +420,13 @@ int mc_ver,mc_rev; return -1; } printf("vo_xvmc: X-Video extension %d.%d\n",xv_version,xv_release); - + if( True != XvMCQueryExtension(mDisplay,&mc_eventBase,&mc_errorBase) ){ printf("vo_xvmc: No X-Video MotionCompensation Extension on %s\n", XDisplayName(NULL)); return -1; } - + if(Success == XvMCQueryVersion(mDisplay, &mc_ver, &mc_rev) ){ printf("vo_xvmc: X-Video MotionCompensation Extension version %i.%i\n", mc_ver,mc_rev); @@ -253,11 +435,44 @@ int mc_ver,mc_rev; printf("vo_xvmc: Error querying version info!\n"); return -1; } + surface_render = NULL; xv_port = 0; number_of_surfaces = 0; - keycolor_handling = 3;//!!fixme - surface_render=NULL; + keycolor_handling = MANUALFILL_COLORKEY;//fixme + subpicture_alloc = 0; + benchmark = 0; //disable PutImageto allow faster display than screen refresh + busy_wait = 1; + use_queue = 0; + if(arg) + while(*arg){ + if(strncmp(arg,"benchmark",9) == 0){ + arg+=9; + if(*arg == ':') arg++; + benchmark = 1;//disable PutImageto allow faster display than screen refresh + continue; + } + if(strncmp(arg,"wait",4) == 0){ + arg+=4; + if(*arg == ':') arg++; + busy_wait = 1; + continue; + } + if(strncmp(arg,"sleep",5) == 0){ + arg+=5; + if(*arg == ':') arg++; + busy_wait = 0; + continue; + } + if(strncmp(arg,"queue",5) == 0){ + arg+=5; + if(*arg == ':') arg++; + use_queue = 1; + continue; + } + break; + } + return 0; } @@ -297,7 +512,7 @@ static uint32_t vm_height; numblocks=((width+15)/16)*((height+15)/16); // Find Supported Surface Type mode_id = xvmc_find_surface_by_format(format,width,height,&surface_info,0);//false=1 to grab port, not query - + rez = XvMCCreateContext(mDisplay, xv_port,mode_id,width,height,XVMC_DIRECT,&ctx); if( rez != Success ) return -1; if( ctx.flags & XVMC_DIRECT ){ @@ -306,10 +521,11 @@ static uint32_t vm_height; printf("vo_xvmc: Allocated Indirect Context!\n"); } + blocks_per_macroblock = 6; if(surface_info.chroma_format == XVMC_CHROMA_FORMAT_422) blocks_per_macroblock = 8; - if(surface_info.chroma_format == XVMC_CHROMA_FORMAT_444) + if(surface_info.chroma_format == XVMC_CHROMA_FORMAT_444) blocks_per_macroblock = 12; rez = XvMCCreateBlocks(mDisplay,&ctx,numblocks*blocks_per_macroblock,&data_blocks); @@ -329,7 +545,7 @@ static uint32_t vm_height; if(surface_render==NULL) surface_render=malloc(MAX_SURFACES*sizeof(xvmc_render_state_t));//easy mem debug - + for(i=0; i 3){//Print All subpicture types for debug + for(s=0;s 0) + for(s=0;s 0){ + + snum = subpicture.num_palette_entries; + seb = subpicture.entry_bytes; + palette = (char*)malloc(snum*seb);//check fail + if(palette == NULL) return; + for(i=0; i(0),(1*(1<<1)/2) + U = 1 << (subpicture_info.u_sample_bits - 1); + V = 1 << (subpicture_info.v_sample_bits - 1); + for(j=0; j3) + printf("vo_xvmc: destroying subpicture\n"); + XvMCDestroySubpicture(mDisplay,&subpicture); + deallocate_xvimage(); + subpicture_alloc = 0; + } + +/* if(surface_info.flags & XVMC_SUBPICTURE_INDEPENDENT_SCALING){ + osd_width = vo_dwidth; + osd_height = vo_dheight; + }else*/ + { + osd_width = image_width; + osd_height = image_height; + } + + if(osd_width > surface_info.subpicture_max_width) + osd_width = surface_info.subpicture_max_width; + if(osd_height > surface_info.subpicture_max_height) + osd_height = surface_info.subpicture_max_height; + if(osd_width == 0 || osd_height == 0) + return;//if called before window size is known + + if(verbose > 3) + printf("vo_xvmc: creating subpicture (%d,%d) format %X\n", + osd_width,osd_height,subpicture_info.id); + + rez = XvMCCreateSubpicture(mDisplay,&ctx,&subpicture, + osd_width,osd_height,subpicture_info.id); + if(rez != Success){ + subpicture_mode = NO_SUBPICTURE; + printf("vo_xvmc: Create Subpicture failed, OSD disabled\n"); + return; + } + if(verbose > 3){ + int i; + printf("vo_xvmc: Created Subpicture:\n"); + printf(" xvimage_id=0x%X\n",subpicture.xvimage_id); + printf(" width=%d\n",subpicture.width); + printf(" height=%d\n",subpicture.height); + printf(" num_palette_entries=0x%X\n",subpicture.num_palette_entries); + printf(" entry_bytes=0x%X\n",subpicture.entry_bytes); + + printf(" component_order=\""); + for(i=0; i<4; i++) + if(subpicture.component_order[i] >= 32) + printf("%c", subpicture.component_order[i]); + printf("\"\n"); + } + + //call init for the surface type + init_osd_fnc();//init palete,clear color etc ... + if(verbose > 3) + printf("vo_xvmc: clearing subpicture\n"); + clear_osd_fnc(0, 0, subpicture.width, subpicture.height); + + allocate_xvimage(subpicture.width, subpicture.height, subpicture_info.id); + subpicture_alloc = 1; +} + +static void draw_osd_IA44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){ +int ox,oy; +int rez; + + if(verbose > 3) + printf("vo_xvmc:composite AI44 subpicture (%d,%d - %d,%d)\n",x0,y0,w,h); + + for(ox=0; oxdata[oy*xvimage->width+ox] = (src[oy*stride+ox]>>4) | ((0-srca[oy*stride+ox])&0xf0); + } + } + rez = XvMCCompositeSubpicture(mDisplay, &subpicture, xvimage, 0, 0, + w,h,x0,y0); + if(rez != Success){ + printf("vo_xvmc: composite subpicture failed\n"); + assert(0); + } +} + +static void draw_osd_AI44(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){ +int ox,oy; +int rez; + if( verbose > 3) + printf("vo_xvmc:composite AI44 subpicture (%d,%d - %d,%d)\n",x0,y0,w,h); + + for(ox=0; oxdata[oy*xvimage->width+ox] = (src[oy*stride+ox]&0xf0) | (((0-srca[oy*stride+ox])>>4)&0xf); + } + } + rez = XvMCCompositeSubpicture(mDisplay, &subpicture, xvimage, 0, 0, + w,h,x0,y0); + if(rez != Success){ + printf("vo_xvmc: composite subpicture failed\n"); + assert(0); + } } static void draw_osd(void){ +xvmc_render_state_t * osd_rndr; +int osd_has_changed; +int have_osd_to_draw; +int rez; + + if(verbose > 3) + printf("vo_xvmc: draw_osd ,OSD_mode=%d, surface_to_show=%p\n", + subpicture_mode,p_render_surface_to_show); + + if(subpicture_mode == BLEND_SUBPICTURE || + subpicture_mode == BACKEND_SUBPICTURE ){ + + if(!subpicture_alloc) //allocate subpicture when dimensions are known + OSD_init(); + if(!subpicture_alloc) + return;//dimensions still unknown. + + osd_has_changed = vo_update_osd(subpicture.width, subpicture.height); + have_osd_to_draw = vo_osd_check_range_update(0, 0, subpicture.width, + subpicture.height); + + if(!have_osd_to_draw) + return;//nothing to draw,no subpic, no blend + + if(osd_has_changed){ + //vo_remove_text(subpicture.width, subpicture.height,clear_osd_fnc) + clear_osd_fnc(0,0,subpicture.width,subpicture.height); + vo_draw_text(subpicture.width, subpicture.height, draw_osd_fnc); + } + XvMCSyncSubpicture(mDisplay,&subpicture);//todo usleeep wait! + + if(subpicture_mode == BLEND_SUBPICTURE){ + osd_rndr = find_free_surface(); + if(osd_rndr == NULL) + return;// no free surface to draw OSD in + + rez = XvMCBlendSubpicture2(mDisplay, + p_render_surface_to_show->p_surface, osd_rndr->p_surface, + &subpicture, + 0, 0, subpicture.width, subpicture.height, + 0, 0, image_width, image_height); + if(rez!=Success){ + printf("vo_xvmc: BlendSubpicture failed rez=%d\n",rez); + assert(0); + return; + } +// XvMCFlushSurface(mDisplay,osd_rndr->p_surface);//fixme- should I? + + //When replaceing the surface with osd one, save the flags too! + osd_rndr->picture_structure = p_render_surface_to_show->picture_structure; + osd_rndr->display_flags = p_render_surface_to_show->display_flags; +//add more if needed osd_rndr-> = p_render_surface_to_show->; + + p_render_surface_to_show->state &= ~MP_XVMC_STATE_DISPLAY_PENDING; + p_render_surface_to_show->state |= MP_XVMC_STATE_OSD_SOURCE; + p_render_surface_to_show->p_osd_target_surface_render = osd_rndr; + + p_render_surface_to_show = osd_rndr; + p_render_surface_to_show->state = MP_XVMC_STATE_DISPLAY_PENDING; + + if(verbose > 3) + printf("vo_xvmc:draw_osd: surface_to_show changed to %p\n",osd_rndr); + }//endof if(BLEND) + if(subpicture_mode == BACKEND_SUBPICTURE){ + rez = XvMCBlendSubpicture(mDisplay, + p_render_surface_to_show->p_surface, + &subpicture, + 0, 0, subpicture.width, subpicture.height, + 0, 0, image_width, image_height); + + } + + }//if(BLEND||BACKEND) } static void xvmc_sync_surface(XvMCSurface * srf){ int status,rez; rez = XvMCGetSurfaceStatus(mDisplay,srf,&status); assert(rez==Success); - if( status & XVMC_RENDERING ) - XvMCSyncSurface(mDisplay, srf); -/* - rez = XvMCFlushSurface(mDisplay, srf); - assert(rez==Success); - - do { - usleep(1); - printf("waiting...\n"); - XvMCGetSurfaceStatus(mDisplay,srf,&status); - } while (status & XVMC_RENDERING); -*/ + if((status & XVMC_RENDERING) == 0) + return;//surface is already complete + if(!busy_wait){ + rez = XvMCFlushSurface(mDisplay, srf); + assert(rez==Success); + + do{ + usec_sleep(1000);//1ms (may be 20ms on linux) + XvMCGetSurfaceStatus(mDisplay,srf,&status); + } while (status & XVMC_RENDERING); + return;//done + } + + XvMCSyncSurface(mDisplay, srf); } static void flip_page(void){ int rez; int clipX,clipY,clipW,clipH; +int i,cfs; clipX = drwX-(vo_panscan_x>>1); clipY = drwY-(vo_panscan_y>>1); clipW = vo_dwidth+vo_panscan_x; - clipH = vo_dheight+vo_panscan_y;// - + clipH = vo_dheight+vo_panscan_y; + if( verbose > 3 ) printf("vo_xvmc: flip_page show(rndr=%p)\n\n",p_render_surface_to_show); if(p_render_surface_to_show == NULL) return; assert( p_render_surface_to_show->magic == MP_XVMC_RENDER_MAGIC ); //fixme assert( p_render_surface_to_show != p_render_surface_visible); - + + if(use_queue){ + // fill the queue until only n free surfaces remain + // after that start displaying + cfs = count_free_surfaces(); + show_queue[free_element++] = p_render_surface_to_show; + if(cfs > 3){//well have 3 free surfaces after add queue + if(free_element > 1)//a little voodoo magic + xvmc_sync_surface(show_queue[0]->p_surface); + return; + } + p_render_surface_to_show=show_queue[0]; + if(verbose > 4) + printf("vo_xvmc: flip_queue free_element=%d\n",free_element); + free_element--; + for(i=0; ip_surface); //the visible surface won't be displayed anymore, mark it as free - if( p_render_surface_visible!=NULL ) + if(p_render_surface_visible != NULL) p_render_surface_visible->state &= ~MP_XVMC_STATE_DISPLAY_PENDING; //!!fixme assert(p_render_surface_to_show->state & MP_XVMC_STATE_DISPLAY_PENDING); -// show it -// if(benchmark) - rez=XvMCPutSurface(mDisplay, p_render_surface_to_show->p_surface, vo_window, - 0, 0, image_width, image_height, - clipX, clipY, clipW, clipH, - 3);//p_render_surface_to_show->display_flags); + //show it, displaying is always vsynced, so skip it for benchmark + if(!benchmark){ + rez = XvMCPutSurface(mDisplay, p_render_surface_to_show->p_surface, + vo_window, + 0, 0, image_width, image_height, + clipX, clipY, clipW, clipH, + 3);//p_render_surface_to_show->display_flags); + if(rez != Success){ + printf("vo_xvmc: PutSurface failer, critical error!\n"); + assert(0); + } + } - assert(rez==Success); - p_render_surface_visible = p_render_surface_to_show; p_render_surface_to_show = NULL; } @@ -595,7 +1128,7 @@ int e=vo_x11_check_events(mDisplay); if(e&VO_EVENT_RESIZE) { e |= VO_EVENT_EXPOSE; - + XGetGeometry( mDisplay,vo_window,&mRoot,&drwX,&drwY,&vo_dwidth,&vo_dheight, &drwBorderWidth,&drwDepth ); drwX = drwY = 0; @@ -615,9 +1148,9 @@ int e=vo_x11_check_events(mDisplay); } if ( e & VO_EVENT_EXPOSE ) { - mDrawColorKey(drwX,drwY,vo_dwidth,vo_dheight); - if(p_render_surface_visible != NULL) - XvMCPutSurface(mDisplay, p_render_surface_visible->p_surface,vo_window, + mDrawColorKey(drwX,drwY,vo_dwidth,vo_dheight); + if(p_render_surface_visible != NULL) + XvMCPutSurface(mDisplay, p_render_surface_visible->p_surface,vo_window, 0, 0, image_width, image_height, drwX,drwY,vo_dwidth,vo_dheight, 3);//,p_render_surface_visible->display_flags);!! @@ -626,10 +1159,22 @@ int e=vo_x11_check_events(mDisplay); static void xvmc_free(void){ int i; + if( subpicture_alloc ){ + + XvMCDestroySubpicture(mDisplay,&subpicture); + deallocate_xvimage(); + + subpicture_alloc = 0; + + if(verbose > 3) + printf("vo_xvmc: subpicture destroyed\n"); + } if( number_of_surfaces ){ + XvMCDestroyMacroBlocks(mDisplay,&mv_blocks); XvMCDestroyBlocks(mDisplay,&data_blocks); + for(i=0; i 3) printf("vo_xvmc: Context sucessfuly freed\n"); number_of_surfaces = 0; + + if(verbose > 3) printf("vo_xvmc: Context sucessfuly freed\n"); } + + if( xv_port !=0 ){ XvUngrabPort(mDisplay,xv_port,CurrentTime); xv_port = 0; - if( verbose > 3) printf("vo_xvmc: xv_port sucessfuly ungrabed\n"); + if(verbose > 3) printf("vo_xvmc: xv_port sucessfuly ungrabed\n"); } } @@ -675,13 +1223,14 @@ int mode_id; mode_id = xvmc_find_surface_by_format(format, 16, 16, &qsurface_info, 1);//true=1 - quering if( mode_id == 0 ) return 0; - + flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_ACCEPT_STRIDE; - -// if(surfce_info.subpicture) -// flags|=VFCAP_OSD; + + if( (qsurface_info.subpicture_max_width != 0) && + (qsurface_info.subpicture_max_height != 0) ) + flags|=VFCAP_OSD; return flags; } @@ -698,11 +1247,6 @@ int rez; assert( rndr != NULL ); assert( rndr->magic == MP_XVMC_RENDER_MAGIC ); - if(rndr->p_past_surface != NULL) - xvmc_sync_surface(rndr->p_past_surface); - if(rndr->p_future_surface != NULL) - xvmc_sync_surface(rndr->p_future_surface); - rez = XvMCRenderSurface(mDisplay,&ctx,rndr->picture_structure, rndr->p_surface, rndr->p_past_surface, @@ -711,20 +1255,20 @@ int rez; rndr->filled_mv_blocks_num,rndr->start_mv_blocks_num, &mv_blocks,&data_blocks); #if 1 - if(rez!=Success) + if(rez != Success) { int i; printf("vo_xvmc::slice: RenderSirface returned %d\n",rez); - + printf("vo_xvmc::slice: pict=%d,flags=%x,start_blocks=%d,num_blocks=%d\n", rndr->picture_structure,rndr->flags,rndr->start_mv_blocks_num, rndr->filled_mv_blocks_num); printf("vo_xvmc::slice: this_surf=%p, past_surf=%p, future_surf=%p\n", rndr->p_surface,rndr->p_past_surface,rndr->p_future_surface); - for(i=0;ifilled_mv_blocks_num;i++){ + for(i=0; ifilled_mv_blocks_num; i++){ XvMCMacroBlock* testblock; - testblock=&mv_blocks.macro_blocks[i]; + testblock = &mv_blocks.macro_blocks[i]; printf("vo_xvmc::slice: mv_block - x=%d,y=%d,mb_type=0x%x,mv_type=0x%x,mv_field_select=%d\n", testblock->x,testblock->y,testblock->macroblock_type, @@ -734,9 +1278,7 @@ int rez; testblock->pad0); printf("vo_xvmc::slice: PMV[0][0][0/1]=(%d,%d)\n", testblock->PMV[0][0][0],testblock->PMV[0][0][1]); - } - } #endif assert(rez==Success); @@ -753,51 +1295,80 @@ int rez; return VO_TRUE; } +//XvMCHide hides the surface on next retrace, so +//check if the surface is not still displaying +static void check_osd_source(xvmc_render_state_t * src_rndr){ +xvmc_render_state_t * osd_rndr; +int stat; + //If this is source surface, check does the OSD rendering is compleate + if(src_rndr->state & MP_XVMC_STATE_OSD_SOURCE){ + if(verbose > 3) + printf("vo_xvmc: OSD surface=%p quering\n",src_rndr); + osd_rndr = src_rndr->p_osd_target_surface_render; + XvMCGetSurfaceStatus(mDisplay, osd_rndr->p_surface, &stat); + if(!(stat & XVMC_RENDERING)) + src_rndr->state &= ~MP_XVMC_STATE_OSD_SOURCE; + } +} +static int count_free_surfaces(){ +int i,num; + num=0; + for(i=0; i=0){//all surfaces are busy, but there is one that will be free + + //all surfaces are busy, but there is one that will be free //on next monitor retrace, we just have to wait - for(t=0;t<1000;t++){ -// usleep(10); //!!! - printf("vo_xvmc: waiting retrace\n"); - XvMCGetSurfaceStatus(mDisplay, surface_render[j].p_surface,&stat); - if( (stat & XVMC_DISPLAYING) == 0 ) return j; - } - assert(0);//10 seconds wait for surface to get free! - exit(1); + if(visible_rndr != NULL){ + printf("vo_xvmc: waiting retrace\n"); + for(t=0;t<1000;t++){ + usec_sleep(1000);//1ms + XvMCGetSurfaceStatus(mDisplay, visible_rndr->p_surface,&stat); + if( (stat & XVMC_DISPLAYING) == 0 ) + return visible_rndr; + } } - return -1; +//todo remove when stable + printf("vo_xvmc: no free surfaces, this should not happen in g1\n"); + for(i=0;istart_mv_blocks_num == 0); +assert(rndr->filled_mv_blocks_num == 0); +assert(rndr->next_free_data_block_num == 0); mpi->flags |= MP_IMGFLAG_DIRECT; //keep strides 0 to avoid field manipulations @@ -810,18 +1381,18 @@ assert(surface_render[getsrf].next_free_data_block_num == 0); mpi->planes[0] = (char*)data_blocks.blocks; mpi->planes[1] = (char*)mv_blocks.macro_blocks; mpi->priv = - mpi->planes[2] = (char*)&surface_render[getsrf]; - - surface_render[getsrf].picture_structure = 0; - surface_render[getsrf].flags = 0; - surface_render[getsrf].state = 0; - surface_render[getsrf].start_mv_blocks_num = 0; - surface_render[getsrf].filled_mv_blocks_num = 0; - surface_render[getsrf].next_free_data_block_num = 0; - + mpi->planes[2] = (char*)rndr; + + rndr->picture_structure = 0; + rndr->flags = 0; + rndr->state = 0; + rndr->start_mv_blocks_num = 0; + rndr->filled_mv_blocks_num = 0; + rndr->next_free_data_block_num = 0; + if( verbose > 3 ) - printf("vo_xvmc: get_image: .rndr=%p surface[%d]=%p \n", - mpi->priv,getsrf,surface_render[getsrf].p_surface); + printf("vo_xvmc: get_image: rndr=%p (surface=%p) \n", + rndr,rndr->p_surface); return VO_TRUE; } @@ -842,13 +1413,13 @@ static uint32_t control(uint32_t request, void *data, ... ) case VOCTRL_GET_PANSCAN: if ( !vo_config_count || !vo_fs ) return VO_FALSE; return VO_TRUE; - // indended, fallthrough to update panscan on fullscreen/windowed switch + // indended, fallthrough to update panscan on fullscreen/windowed switch case VOCTRL_SET_PANSCAN: if ( ( vo_fs && ( vo_panscan != vo_panscan_amount ) ) || ( !vo_fs && vo_panscan_amount ) ) { int old_y = vo_panscan_y; panscan_calc(); - + if(old_y != vo_panscan_y) { XClearWindow(mDisplay, vo_window); @@ -861,11 +1432,11 @@ static uint32_t control(uint32_t request, void *data, ... ) { va_list ap; int value; - + va_start(ap, data); value = va_arg(ap, int); va_end(ap); - + return(vo_xv_set_eq(xv_port, data, value)); } @@ -873,14 +1444,13 @@ static uint32_t control(uint32_t request, void *data, ... ) { va_list ap; int *value; - + va_start(ap, data); value = va_arg(ap, int*); va_end(ap); - + return(vo_xv_get_eq(xv_port, data, value)); } } return VO_NOTIMPL; } - -- cgit v1.2.3