[MPlayer-dev-eng] [PATCH] Improved DGA vertical retrace sync
Fredrik Noring
noring at nocrew.org
Tue Sep 24 00:54:52 CEST 2002
mån 2002-09-23 klockan 23.30 skrev Arpi:
> - does more than 3 (display, render, waiting) buffers has any sense?
Not in the current implementation, except that Mplayer seems to drift
between the number of draw_frame calls compared to the number of
flip_page calls especially when fast-forwarding, so four or five
frames does sometimes help (I haven't investigated this too much). A
notion of frame references in the Mplayer video driver API would
probably solve this...
If Mplayer sometime would support a more advanced video driver API,
more than three frames could make much sense. Consider the case where
Mplayer pre-renders 12 frames ahead, and a sudden temporary disruptive
scheduling problem occurs (like heavy disk activity or whatever).
Now, since almost half-a-second of frames have been pre-rendered, the
only _critical_ thing Mplayer must do meanwhile is simply issue page
flippings. And since the buffers are located in the memory of the
graphics card in this case, the cpu cost of flipping is practically
zero. If the scheduling prolem disappears shortly, Mplayer can resume
filling the pre-render buffers and the user who is watching the video
didn't notice any problems at all.
That would be neat, wouldn't it?
> - it should honor the -double/-nodouble flag, and by default (nodouble)
> use only one buffer with no buffer flipping. you've just removed the
> if(!vo_doublebuffering) check.
Sorry. The attached patch below should fix this. Why have you selected
nodouble as default? It does not make much sense to me.
> most vga cards can trigger an IRQ at vsync, it should be possible to
> develop a kernel driver which can catch that.
Well, yes... But (assuming we still talk about the DGA interface), this
would have to be implemented in the XFree86 server and since they plan
on removing the DGA extension in XFree86 5, they will probably not go
ahead with something like that.
Fredrik
Index: vo_dga.c
===================================================================
RCS file: /cvsroot/mplayer/main/libvo/vo_dga.c,v
retrieving revision 1.46
diff -u -r1.46 vo_dga.c
--- vo_dga.c 28 Aug 2002 21:32:31 -0000 1.46
+++ vo_dga.c 23 Sep 2002 23:05:34 -0000
@@ -374,14 +374,26 @@
static int vo_dga_XServer_mode = 0;// index in mode list for resolution
// XServer is running
-static int vo_dga_dbf_mem_offset; // offset in bytes for alternative
- // framebuffer (0 if dbf is not
- // possible)
-static int vo_dga_dbf_y_offset; // y offset (in scanlines)
-static int
- vo_dga_dbf_current; // current buffer (0 or 1)
+#define MAX_NR_VIDEO_BUFFERS 5
+
+#define VIDEO_BUFFER_DRAW \
+ (vo_dga_video_buffer[vo_dga_current_video_buffer % \
+ vo_dga_nr_video_buffers])
+
+#define VIDEO_BUFFER_DISPLAY \
+ (vo_dga_video_buffer[(vo_dga_current_video_buffer + \
+ vo_dga_nr_video_buffers - 1) % \
+ vo_dga_nr_video_buffers])
+
+static int vo_dga_nr_video_buffers; // Total number of frame buffers.
+static int vo_dga_current_video_buffer; // Buffer available for rendering.
+
+static struct video_buffer
+{
+ int y;
+ uint8_t *data;
+} vo_dga_video_buffer[MAX_NR_VIDEO_BUFFERS];
-static unsigned char *vo_dga_base;
static Display *vo_dga_dpy;
/* saved src and dst dimensions for SwScaler */
@@ -421,7 +433,7 @@
offset = vo_dga_width * y0 +x0;
buffer_stride = vo_dga_width;
- d = (&((char *)vo_dga_base)[vo_dga_vp_offset + vo_dga_dbf_current * vo_dga_dbf_mem_offset]);
+ d = VIDEO_BUFFER_DRAW.data;
switch( HW_MODE.vdm_mplayer_depth ){
@@ -468,7 +480,7 @@
char *s, *d;
s = *src;
- d = (&((char *)vo_dga_base)[vo_dga_vp_offset + vo_dga_dbf_current * vo_dga_dbf_mem_offset]);
+ d = VIDEO_BUFFER_DRAW.data;
switch(SRC_MODE.vdm_conversion_func){
case VDM_CONV_NATIVE:
@@ -479,18 +491,18 @@
numlines,
vo_dga_bytes_per_line+vo_dga_vp_skip,
vo_dga_bytes_per_line);
-
+
// DBG-COde
#if 0
- d = (&((char *)vo_dga_base)[vo_dga_vp_offset + vo_dga_dbf_current * vo_dga_dbf_mem_offset]);
+ d = VIDEO_BUFFER_DRAW.data;
fillblock(d, 0, 10, 0x800000ff);
fillblock(d, 10, 10, 0x8000ff00);
fillblock(d, 20, 10, 0x80ff0000);
fillblock(d, 30, 10, 0xff0000ff);
fillblock(d, 40, 10, 0x800000ff);
fillblock(d, 50, 10, 0x0f0000ff);
-#endif
+#endif
break;
case VDM_CONV_15TO16:
{
@@ -539,20 +551,28 @@
static void draw_osd(void)
{ vo_draw_text(vo_dga_src_width,vo_dga_src_height,draw_alpha); }
-static void flip_page( void ){
-
- if(vo_dga_dbf_mem_offset != 0){
+static void switch_video_buffers(void)
+{
+ vo_dga_current_video_buffer =
+ (vo_dga_current_video_buffer + 1) % vo_dga_nr_video_buffers;
+}
+static void flip_page( void )
+{
+ if(1 < vo_dga_nr_video_buffers)
+ {
#ifdef HAVE_DGA2
- XDGASetViewport (vo_dga_dpy, XDefaultScreen(vo_dga_dpy),
- 0, vo_dga_dbf_current * vo_dga_dbf_y_offset,
- XDGAFlipRetrace);
+ XDGASetViewport(vo_dga_dpy, XDefaultScreen(vo_dga_dpy),
+ 0,
+ VIDEO_BUFFER_DISPLAY.y,
+ XDGAFlipRetrace);
#else
- XF86DGASetViewPort (vo_dga_dpy, XDefaultScreen(vo_dga_dpy),
- 0, vo_dga_dbf_current * vo_dga_dbf_y_offset);
+ XF86DGASetViewPort(vo_dga_dpy, XDefaultScreen(vo_dga_dpy),
+ 0,
+ VIDEO_BUFFER_DISPLAY.y);
#endif
- vo_dga_dbf_current = 1 - vo_dga_dbf_current;
- }
+ switch_video_buffers();
+ }
}
//---------------------------------------------------------
@@ -561,13 +581,18 @@
int w,int h,int x,int y )
{
if (scale_srcW) {
- uint8_t *dst[3] = {vo_dga_base + vo_dga_dbf_current * vo_dga_dbf_mem_offset + vo_dga_vp_offset, NULL, NULL};
+ uint8_t *dst[3] =
+ {
+ VIDEO_BUFFER_DRAW.data + vo_dga_vp_offset,
+ 0,
+ 0
+ };
SwScale_YV12slice(src,stride,y,h,
dst,
/*scale_dstW*/ vo_dga_width * HW_MODE.vdm_bytespp, HW_MODE.vdm_bitspp,
scale_srcW, scale_srcH, scale_dstW, scale_dstH);
} else {
- yuv2rgb( vo_dga_base + vo_dga_dbf_current * vo_dga_dbf_mem_offset + vo_dga_vp_offset +
+ yuv2rgb(VIDEO_BUFFER_DRAW.data + vo_dga_vp_offset +
(vo_dga_width * y +x) * HW_MODE.vdm_bytespp,
src[0], src[1], src[2],
w,h, vo_dga_width * HW_MODE.vdm_bytespp,
@@ -796,6 +821,35 @@
//---------------------------------------------------------
+static void init_video_buffers(XDGAMode *modeline, uint8_t *buffer_base,
+ int use_multiple_buffers)
+{
+ int bytes_per_buffer =
+ modeline->viewportHeight * modeline->bytesPerScanline;
+ int i;
+
+ if(use_multiple_buffers)
+ vo_dga_nr_video_buffers =
+ modeline->pixmapHeight / modeline->viewportHeight;
+ else
+ vo_dga_nr_video_buffers = 1;
+
+ vo_dga_current_video_buffer = 0;
+
+ if(MAX_NR_VIDEO_BUFFERS < vo_dga_nr_video_buffers)
+ vo_dga_nr_video_buffers = MAX_NR_VIDEO_BUFFERS;
+
+ for(i = 0; i < vo_dga_nr_video_buffers; i++)
+ {
+ vo_dga_video_buffer[i].y = i * modeline->viewportHeight;
+ vo_dga_video_buffer[i].data =
+ buffer_base + i * bytes_per_buffer;
+
+ // Clear video buffer.
+ memset(vo_dga_video_buffer[i].data, 0, bytes_per_buffer);
+ }
+}
+
static uint32_t config( uint32_t width, uint32_t height,
uint32_t d_width,uint32_t d_height,
uint32_t flags,char *title,uint32_t format)
@@ -808,8 +862,9 @@
// needed to change DGA video mode
int modecount, mX=VO_DGA_INVALID_RES, mY=VO_DGA_INVALID_RES , mVBI=100000, mMaxY=0, i,j=0;
int dga_modenum;
- XDGAMode *modelines=NULL;
+ XDGAMode *modelines=NULL, *modeline;
XDGADevice *dgadevice;
+ unsigned char *vo_dga_base;
int max_vpy_pos;
#else
#ifdef HAVE_XF86VM
@@ -947,6 +1002,7 @@
vo_dga_width = modelines[j].bytesPerScanline / HW_MODE.vdm_bytespp ;
dga_modenum = modelines[j].num;
max_vpy_pos = modelines[j].maxViewportY;
+ modeline = modelines + j;
XFree(modelines);
modelines = NULL;
@@ -1120,50 +1176,12 @@
XGrabPointer (vo_dga_dpy, DefaultRootWindow(vo_dga_dpy), True,
ButtonPressMask,GrabModeAsync, GrabModeAsync,
None, None, CurrentTime);
-// TODO: chekc if mem of graphics adaptor is large enough for dbf
-
- // set up variables for double buffering ...
- // note: set vo_dga_dbf_mem_offset to NULL to disable doublebuffering
-
- vo_dga_dbf_y_offset = y_off + vo_dga_src_height;
- vo_dga_dbf_mem_offset = vo_dga_width * HW_MODE.vdm_bytespp * vo_dga_dbf_y_offset;
- vo_dga_dbf_current = 0;
-
- if(!vo_doublebuffering) vo_dga_dbf_mem_offset = 0;
-
- // if(format ==IMGFMT_YV12 )
- //vo_dga_dbf_mem_offset = 0;
- // disable doublebuffering for YV12
+ init_video_buffers(modeline, vo_dga_base, vo_doublebuffering);
-#ifdef HAVE_DGA2
- if(vo_dga_vp_height>max_vpy_pos){
- vo_dga_dbf_mem_offset = 0;
- vd_printf(VD_INFO, "vo_dga: Not enough memory for double buffering!\n");
- }
-#endif
+ vd_printf(VD_DBG, "vo_dga: Using %d frame buffer%s.\n",
+ vo_dga_nr_video_buffers, vo_dga_nr_video_buffers == 1 ? "" : "s");
- // now clear screen
- {
- int size = vo_dga_width *
- (vo_dga_vp_height + (vo_dga_dbf_mem_offset != 0 ?
- (vo_dga_src_height+y_off) : 0)) *
- HW_MODE.vdm_bytespp;
-#ifndef HAVE_DGA2
- vd_printf(VD_DBG, "vo_dga: wanted size=%d, fb-size=%d\n", size, ram);
- if(size>ram*1024){
- vo_dga_dbf_mem_offset = 0;
- vd_printf(VD_INFO, "vo_dga: Not enough memory for double buffering!\n");
- size -= (vo_dga_src_height+y_off) * vo_dga_width * HW_MODE.vdm_bytespp;
- }
-#endif
-
- vd_printf(VD_INFO, "vo_dga: Clearing framebuffer (%d bytes). If mplayer exits", size);
- vd_printf(VD_INFO, " here, you haven't enough memory on your card.\n");
- fflush(stdout);
- memset(vo_dga_base, 0, size);
- }
- vd_printf(VD_INFO, "vo_dga: Doublebuffering is %s.\n", vo_dga_dbf_mem_offset ? "enabled" : "disabled");
vo_dga_is_running = 1;
return 0;
}
More information about the MPlayer-dev-eng
mailing list