[MPlayer-dev-eng] patch for quadbuffered stereo using "-vo gl2:stereo"

Stuart Levy slevy at ncsa.uiuc.edu
Wed Nov 28 22:16:03 CET 2007


On Wed, Nov 28, 2007 at 08:59:23PM +0100, Reimar Döffinger wrote:
 [...]
> > +static void drawTextureDisplay ( float tex0, float tex1 )
> >  {
 [...]
> > +  itx0 = (int) (tex0 * texnumx);
> > +  itx1 = (int) ceilf(tex1 * texnumx);
> > +
> 
> Instead of this "mess", why not just adding a proper transformation
> matrix? You wouldn't even have to change drawTextureDisplay, just change
> the matrix one level above. In addition this would be much easier to
> adjust for e.g. left image above right image and similar things.

drawTextureDisplay() does need the extra information passed in,
since in stereo mode, it must draw only the left-half pixels of
the source image when drawing to GL_BACK_LEFT, and then the
right half pixels in the second pass, instead of the usual case
which draws all the pixels.  So just a transform matrix
wouldn't do.  Right?  And I need to compute which texture tiles
are covered by the necessary piece of source image, etc.
I could do the fxoff/fxscale conversions in a matrix -- something like
  glPushMatrix();
  glScalef( 1.0f/(tex1-tex0), 1.0f, 1.0f );
  glTranslatef( -tex0, 0.0f, 0.0f );
  ...
    glDrawTex(square->fx, square->fy, square->fw, square->fh, ... );
  ...
  glPopMatrix();
but is that any clearer?


> Please make any code that uses glDrawBuffer revert it to GL_BACK
> instead immediately afterwards.

OK, thanks.
 

> > +      if (quadbuffer_stereo)
> > +	  mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no Quadbuffered Stereo GLX support present\n");
> > +      else
> > +	  mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no GLX support present\n");
> 
> The old message was wrong anyway, and the one you add might not be right
> either, there can well be quadbuffer stereo support and it still will fail,
> e.g. because there is no doublebuffer support.
> It should just be replaced by something like "no suitable GLX visual found",
> and that is independent of this patch.

There's a new variant in the new attached patch -- how do you like this?
I think it might be nice to mention that quadbuffered stereo is required
in case of error, since most opengl implementations have all the
other requirements.

> > +#if 0
> > +  if (quadbuffer_stereo) {
> > +    /* v. Winckler's patch had just d_width /= 2, but that doesn't seem right either.
> > +     * Mplayer experts please help!  Meanwhile, leave this section out.
> > +     * Then users must still give explicit -x and -y options as in
> > +     *   mplayer -vo gl2:stereo -x <SCREENWIDTH> -y <SCREENHEIGHT>  movie...
> > +     * At least *that* works.  But default window doesn't, nor does -fs,
> > +     * both apparently confused by double-wide aspect ratio of stereo anim files.
> > +     */
> > +    width /= 2;
> > +    d_width /= 2;
> > +  }
> > +#endif
> 
> I guess you give the wrong -monitoraspect. If you want it automated you
> probably at least have to hack VOCTRL_UPDATE_SCREENINFO

Could you explain more about what should be updated?  I don't know even
what the fields mean, let alone which ones I'm free to change at what point.

Presumably mplayer is getting a correct idea about the monitor aspect;
for example, 1.777:1 on a 1920x1080 stereo-capable display.
And the pixels are square, both on the display and in the designed animation.

But the animation file might have a size like 3840x1080 or 2560x720,
i.e. 3.555:1.  To make this work right, somehow in the gl2:stereo code
I need to mislead mplayer about the image aspect ratio.
E.g. if the animation file is 3840x1080, then
  mplayer -vo gl2:stereo should open a 1920x1080 window.

Should I just go change vo_dwidth somewhere?  Or use something like
   initGl( quadbuffer_stereo ? vo_dwidth/2 : vo_dwidth, vo_dheight )
?
 
> >  //  glFlush();
> >    if (use_glFinish)
> > -  glFinish();
> > +    glFinish();
> 
> Cosmetic.

OK.  I hope you agree that code like

   if (use_glFinish)
   glFinish();

(with matching indentation on both lines)
is uglier than it should be,
but won't try to change that in this patch.
 
> > @@ -859,6 +924,8 @@
> >              "    3: use fragment program with gamma correction.\n"
> >              "    4: use fragment program with gamma correction via lookup.\n"
> >              "    5: use ATI-specific method (for older cards).\n"
> > +	    "  stereo\n"
> > +	    "    use quadbuffered stereo: left-half image to left eye, etc.\n"
> 
> No tabs please (unless the surrounding code uses them).

Righto.   Here's another try.


Index: libvo/vo_gl2.c
===================================================================
--- libvo/vo_gl2.c	(revision 25184)
+++ libvo/vo_gl2.c	(working copy)
@@ -7,6 +7,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <math.h>
 
 #include "config.h"
 #include "mp_msg.h"
@@ -46,6 +47,11 @@
 /* local data */
 static unsigned char *ImageData=NULL;
 
+// QuadBuffer Stereo
+static unsigned char quadbuffer_stereo = 0;
+
+
+
 #ifdef GL_WIN32
     static int gl_vinfo = 0;
     static HGLRC gl_context = 0;
@@ -358,23 +364,31 @@
 }
 
 
-static void drawTextureDisplay (void)
+static void drawTextureDisplay ( float tex0, float tex1 )
 {
   struct TexSquare *square = texgrid;
   int x, y;
+  int itx0, itx1;
+  GLfloat fxoff = tex0;
+  GLfloat fxscale = 1.0f / (tex1 - tex0);
 
+
   glColor3f(1.0,1.0,1.0);
 
+  itx0 = (int) (tex0 * texnumx);
+  itx1 = (int) ceilf(tex1 * texnumx);
+
   if (image_format == IMGFMT_YV12)
     glEnableYUVConversion(GL_TEXTURE_2D, use_yuv);
   for (y = 0; y < texnumy; y++) {
     int thish = texture_height;
     if (y == texnumy - 1 && image_height % texture_height)
       thish = image_height % texture_height;
-    for (x = 0; x < texnumx; x++) {
+    for (x = itx0; x < itx1; x++) {
       int thisw = texture_width;
       if (x == texnumx - 1 && image_width % texture_width)
         thisw = image_width % texture_width;
+      square = texgrid + y*texnumx + x;
       glBindTexture (GL_TEXTURE_2D, square->texobj);
       if (image_format == IMGFMT_YV12) {
         ActiveTexture(GL_TEXTURE1);
@@ -390,11 +404,10 @@
                     0, 0, thisw, thish, 0);
       }
 
-      glDrawTex(square->fx, square->fy, square->fw, square->fh,
+      glDrawTex((square->fx - fxoff) * fxscale, square->fy, square->fw * fxscale, square->fh,
                 0, 0, texture_width, texture_height,
                 texture_width, texture_height,
                 0, image_format == IMGFMT_YV12, 0);
-      square++;
     } /* for all texnumx */
   } /* for all texnumy */
   if (image_format == IMGFMT_YV12)
@@ -432,18 +445,26 @@
 
 static void draw_alpha_32(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb32(w,h,src,srca,stride,ImageData+4*(y0*image_width+x0),4*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb32(w,h,src,srca,stride,ImageData+4*(y0*image_width+x0+image_width/2),4*image_width);
 }
 
 static void draw_alpha_24(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb24(w,h,src,srca,stride,ImageData+3*(y0*image_width+x0),3*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb24(w,h,src,srca,stride,ImageData+3*(y0*image_width+x0+image_width/2),3*image_width);
 }
 
 static void draw_alpha_16(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb16(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb16(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0+image_width/2),2*image_width);
 }
 
 static void draw_alpha_15(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
    vo_draw_alpha_rgb15(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0),2*image_width);
+   if (quadbuffer_stereo)
+      vo_draw_alpha_rgb15(w,h,src,srca,stride,ImageData+2*(y0*image_width+x0+image_width/2),2*image_width);
 }
 
 static void draw_alpha_null(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride){
@@ -483,6 +504,11 @@
     /* furthermore it must be RGBA (not color indexed) ... */
     res = glXGetConfig(dpy, vi_list + i, GLX_RGBA, &val);
     if (res || val == False) continue;
+    /* assure quadbuffered stereo if requested */
+    if (quadbuffer_stereo) {
+      res = glXGetConfig(dpy, vi_list + i, GLX_STEREO, &val);
+      if (res || val == False) continue;
+    }
     /* prefer less depth buffer size, */
     res = glXGetConfig(dpy, vi_list + i, GLX_DEPTH_SIZE, &val);
     if (res) continue;
@@ -530,7 +556,8 @@
   }
     vinfo = choose_glx_visual(mDisplay,mScreen,&vinfo_buf) < 0 ? NULL : &vinfo_buf;
     if (vinfo == NULL) {
-      mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no GLX support present\n");
+      mp_msg(MSGT_VO, MSGL_FATAL, "[gl2] no suitable GLX visual found%s\n",
+        quadbuffer_stereo ? " (need quadbuffered stereo for '-vo gl2:stereo')" : "");
       return -1;
     }
 
@@ -593,8 +620,16 @@
 
   glClearColor( 0.0f,0.0f,0.0f,0.0f );
   glClear( GL_COLOR_BUFFER_BIT );
+  if ( quadbuffer_stereo ) {
+    glDrawBuffer(GL_BACK_LEFT);
+    drawTextureDisplay( 0.0f, 0.5f );
+    glDrawBuffer(GL_BACK_RIGHT);
+    drawTextureDisplay( 0.5f, 1.0f );
+    glDrawBuffer(GL_BACK);
 
-  drawTextureDisplay ();
+  } else { 
+    drawTextureDisplay ( 0.0f, 1.0f );
+  }
 
   return 0;
 }
@@ -611,6 +646,20 @@
   image_width = width;
   image_format = format;
 
+#if 0
+  if (quadbuffer_stereo) {
+    /* v. Winckler's patch had just d_width /= 2, but that doesn't seem right either.
+     * Mplayer experts please help!  Meanwhile, leave this section out.
+     * Then users must still give explicit -x and -y options as in
+     *   mplayer -vo gl2:stereo -x <SCREENWIDTH> -y <SCREENHEIGHT>  movie...
+     * At least *that* works.  But default window doesn't, nor does -fs,
+     * both apparently confused by double-wide aspect ratio of stereo anim files.
+     */
+    width /= 2;
+    d_width /= 2;
+  }
+#endif
+
   int_pause = 0;
 
 #ifdef HAVE_NEW_GUI
@@ -718,13 +767,21 @@
 static void draw_osd(void)
 {
   if (ImageData)
-    vo_draw_text(image_width,image_height,draw_alpha_fnc);
+    vo_draw_text( quadbuffer_stereo ? image_width/2 : image_width, image_height,draw_alpha_fnc);
 }
 
 static void
 flip_page(void)
 {
-  drawTextureDisplay();
+  if ( quadbuffer_stereo ) {
+    glDrawBuffer( GL_BACK_LEFT );
+    drawTextureDisplay( 0.0f, 0.5f );
+    glDrawBuffer( GL_BACK_RIGHT );
+    drawTextureDisplay( 0.5f, 1.0f );
+    glDrawBuffer( GL_BACK );
+  } else {
+    drawTextureDisplay( 0.0f, 1.0f );
+  }
 
 //  glFlush();
   if (use_glFinish)
@@ -732,7 +789,9 @@
   swapGlBuffers();
 
   if (vo_fs) // Avoid flickering borders in fullscreen mode
+  {
     glClear (GL_COLOR_BUFFER_BIT);
+  }
 }
 
 static int draw_slice(uint8_t *src[], int stride[], int w,int h,int x,int y)
@@ -837,6 +896,7 @@
 static opt_t subopts[] = {
   {"yuv",          OPT_ARG_INT,  &use_yuv,      (opt_test_f)int_non_neg},
   {"glfinish",     OPT_ARG_BOOL, &use_glFinish, NULL},
+  {"stereo",       OPT_ARG_BOOL, &quadbuffer_stereo,    NULL},
   {NULL}
 };
 
@@ -859,6 +919,8 @@
             "    3: use fragment program with gamma correction.\n"
             "    4: use fragment program with gamma correction via lookup.\n"
             "    5: use ATI-specific method (for older cards).\n"
+            "  stereo\n"
+            "    use quadbuffered stereo: left-half image to left eye, etc.\n"
             "\n" );
     return -1;
   }



More information about the MPlayer-dev-eng mailing list