[MPlayer-dev-eng] New stereo output mode for OpenGL video driver
Wolfgang Draxinger
wdraxinger.maillist at draxit.de
Sun Dec 18 23:53:54 CET 2011
Hi,
I added support for a new stereo output mode in the OpenGL video output
driver.
Besides the (well known) shutter glasses based stereoscopic displays
(which are covered with the OpenGL Quadbuffer Stereo mode) there's
another class of stereoscopic displays, which use a grid of
spatially interlaced modulators (for circular polarizer separation
lambda/2 retarders inbetween the front linear polarizer and a lambda/4
retarder). There are displays with row, column and checkerboard
interlacing, though row and checkerboard interlacing are most common
(column interlacing is mostly used for parallax barrier and lenticular
prism based separation).
This patch extends the OpenGL video output driver with 4 new stereo
output modes for row and column interlacing. I don't own a checkerboard
display so I haven't implemented it yet.
To implement the interlacing OpenGL polygon stipple patterns are
applied. For a shift to OpenGL-3 core profile this should be moved into a
fragment shader that samples from either texture based on the fragment
coordinate.
Cheers,
Wolfgang Draxinger
Patch follows:
diff --git a/libvo/gl_common.c b/libvo/gl_common.c
index cbfa3ce..340cff2 100644
--- a/libvo/gl_common.c
+++ b/libvo/gl_common.c
@@ -92,6 +92,7 @@ void (GLAPIENTRY *mpglColorMaterial)(GLenum, GLenum);
void (GLAPIENTRY *mpglShadeModel)(GLenum);
void (GLAPIENTRY *mpglGetIntegerv)(GLenum, GLint *);
void (GLAPIENTRY *mpglColorMask)(GLboolean, GLboolean, GLboolean, GLboolean);
+void (GLAPIENTRY *mpglPolygonStipple)(const GLubyte*);
/**
* \defgroup glextfunctions OpenGL extension functions
@@ -447,6 +448,7 @@ static const extfunc_desc_t extfuncs[] = {
DEF_FUNC_DESC(ShadeModel),
DEF_FUNC_DESC(GetIntegerv),
DEF_FUNC_DESC(ColorMask),
+ DEF_FUNC_DESC(PolygonStipple),
// here start the real extensions
{&mpglGenBuffers, NULL, {"glGenBuffers", "glGenBuffersARB", NULL}},
@@ -1588,6 +1590,169 @@ void glDisableYUVConversion(GLenum target, int type) {
}
}
+/* Stipple patterns for row and column interlacing.
+ * Used for interlaced stereo output. */
+
+static uint8_t const stipple_row_even[]={
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+};
+
+static uint8_t const stipple_row_odd[]={
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+ 0x00,0x00,0x00,0x00,
+ 0xff,0xff,0xff,0xff,
+};
+
+static uint8_t const stipple_column_even[]={
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+ 0xaa,0xaa,0xaa,0xaa,
+};
+
+static uint8_t const stipple_column_odd[]={
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+ 0x55,0x55,0x55,0x55,
+};
+
+/* TODO:
+ * In the current implementation the interlacing happens relative
+ * to the OpenGL viewport. However to reliably work on display that
+ * employ interlacing for stereo image spearation, the interlacing
+ * must happen relative to the screen origin.
+ *
+ * This leaves to be implemented:
+ * - at window move events the origin of the window interior origin
+ * in screen coordinates must be determined and that taken into
+ * account choosing the stipple pattern.
+ * - a nice have to feature was retrieving the EDID of the display
+ * showing the sub screen in which the mplayer window is placed,
+ * and using vendor/model information therein to load from a
+ * (compiled in) database which interlacing order to use.
+ *
+ * A further nice-to-have feature was a anti-ghost implementation
+ * where the image of the other eye, multiplied with a value
+ * -1 < x < 0 is added to compensate for ghosting.
+ */
+
void glEnable3DLeft(int type) {
GLint buffer;
switch (type) {
@@ -1613,6 +1778,30 @@ void glEnable3DLeft(int type) {
}
mpglDrawBuffer(buffer);
break;
+ case GL_3D_ROWINTERLACE_ODD:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_row_odd);
+ break;
+ case GL_3D_ROWINTERLACE_EVEN:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_row_even);
+ break;
+ case GL_3D_COLUMNINTERLACE_ODD:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_column_odd);
+ break;
+ case GL_3D_COLUMNINTERLACE_EVEN:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_column_even);
+ break;
}
}
@@ -1641,6 +1830,30 @@ void glEnable3DRight(int type) {
}
mpglDrawBuffer(buffer);
break;
+ case GL_3D_ROWINTERLACE_ODD:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_row_even);
+ break;
+ case GL_3D_ROWINTERLACE_EVEN:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_row_odd);
+ break;
+ case GL_3D_COLUMNINTERLACE_ODD:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_column_even);
+ break;
+ case GL_3D_COLUMNINTERLACE_EVEN:
+ mpglEnable(GL_POLYGON_STIPPLE);
+ mpglPixelStorei(GL_UNPACK_ALIGNMENT,1);
+ mpglPixelStorei(GL_UNPACK_ROW_LENGTH,0);
+ mpglPolygonStipple(stipple_column_odd);
+ break;
}
}
@@ -1668,6 +1881,13 @@ void glDisable3D(int type) {
}
mpglDrawBuffer(buffer);
break;
+ case GL_3D_ROWINTERLACE_ODD:
+ case GL_3D_ROWINTERLACE_EVEN:
+ case GL_3D_COLUMNINTERLACE_ODD:
+ case GL_3D_COLUMNINTERLACE_EVEN:
+ glDisable(GL_POLYGON_STIPPLE);
+ mpglPolygonStipple(NULL);
+ break;
}
}
diff --git a/libvo/gl_common.h b/libvo/gl_common.h
index 52b8999..f0fec03 100644
--- a/libvo/gl_common.h
+++ b/libvo/gl_common.h
@@ -389,6 +389,10 @@ void glDisableYUVConversion(GLenum target, int type);
#define GL_3D_RED_CYAN 1
#define GL_3D_GREEN_MAGENTA 2
#define GL_3D_QUADBUFFER 3
+#define GL_3D_ROWINTERLACE_ODD 4
+#define GL_3D_ROWINTERLACE_EVEN 5
+#define GL_3D_COLUMNINTERLACE_ODD 6
+#define GL_3D_COLUMNINTERLACE_EVEN 7
void glEnable3DLeft(int type);
void glEnable3DRight(int type);
@@ -493,6 +497,7 @@ extern void (GLAPIENTRY *mpglColorMaterial)(GLenum, GLenum);
extern void (GLAPIENTRY *mpglShadeModel)(GLenum);
extern void (GLAPIENTRY *mpglGetIntegerv)(GLenum, GLint *);
extern void (GLAPIENTRY *mpglColorMask)(GLboolean, GLboolean, GLboolean, GLboolean);
+extern void (GLAPIENTRY *mpglPolygonStipple)(const GLubyte*);
extern void (GLAPIENTRY *mpglGenBuffers)(GLsizei, GLuint *);
extern void (GLAPIENTRY *mpglDeleteBuffers)(GLsizei, const GLuint *);
diff --git a/libvo/vo_gl.c b/libvo/vo_gl.c
index e16a521..40d0d8c 100644
--- a/libvo/vo_gl.c
+++ b/libvo/vo_gl.c
@@ -1297,6 +1297,10 @@ static int preinit_internal(const char *arg, int allow_sw)
" 1: side-by-side to red-cyan stereo\n"
" 2: side-by-side to green-magenta stereo\n"
" 3: side-by-side to quadbuffer stereo\n"
+ " 4: side-by-side to row interlaced (left to even) stereo\n"
+ " 5: side-by-side to row interlaced (left to odd) stereo\n"
+ " 6: side-by-side to column interlaced (left to even) stereo\n"
+ " 7: side-by-side to column interlaced (left to odd) stereo\n"
" backend=<n>\n"
" -1: auto-select\n"
" 0: Win32/WGL\n"
More information about the MPlayer-dev-eng
mailing list