Re: specifing visual for X11 window
Reimar Döffinger <[email protected]> Sun, 29 Feb 2004 23:06:06 +0100
| Newsgroups | gmane.comp.video.mplayer.g2.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello,
>>I've been working on an OpenGL vo module for G2.
>>What I need is a way to make sure the window that is passed to the
>>config function is usable for OpenGL.
>
> Is there any case where the normal native visual type for the display
> wouldn't be the best? IMO the X code should always use this type of
> visual anyway. And sometimes, the window will be created well before
> the vo is known (think of playing in an existing window) so I think
> the vo driver just has to fail if it can't use the visual given to
> it...
I don't really know. I just tried it the way the G1 vo's do it, but the
visual returned by glXMatchVisual didn't work with the one the window had...
>>The best idea I had so far was adding a XVisualInfo* part to
>>vo_instance_t and if it's set the window will be created using this visual.
>>Would this be acceptable / do you have any other ideas (except creating
>>the window in the vo module, this would give the same mess as in G1).
>
> No, X-specific stuff is definitely not acceptable in the generic vo
> api... Some of us will even be building --without-x! Of course you can
> use #ifdefs but that's a mess, especially if we want vo modules to be
> dynamic loaded plugins (in which case the structs need to be
> binary-compatible).
I though/feared so. But I found a way around the problem. Do you know a
way to find out which visual a window uses?
I currently use
XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &vinfo);
(copyed from x11_helper.c, create_window function), but that sure isn't
really good...
In case someone's interested I attached this vo (but please consider it
pre-alpha ;-) )
Greetings,
Reimar Döffinger
_______________________________________________
MPlayer-G2-dev mailing list
[email protected]
http://mplayerhq.hu/mailman/listinfo/mplayer-g2-dev
vo_gl.c
(text/plain, 12.1 KB)
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "config.h"
#include "mp_msg.h"
#include "video_out.h"
#include "video/vfcap.h"
#include "video/img_format.h"
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/gl.h>
#include <GL/glx.h>
#define DEFAULT_INTERNAL_FORMAT GL_RGB
static void unimpl ()
{
mp_msg (MSGT_VO, MSGL_ERR, "[gl] unimplemented function!\n");
}
struct vo_priv_s {
Window window;
Display *display;
int img_width;
int img_height;
int d_width;
int d_height;
char numPlanes;
char numTextures; // how many textures have been allocated by glGenTextures
GLuint planeTexture[4];
GLint planeInternalFormat[4];
GLsizei planeTextureWidth[4];
GLsizei planeTextureHeight[4];
int planeWidth[4];
int planeHeight[4];
char planeBytesPerPixel[4];
GLenum planeFormat[4];
GLenum planeType[4];
char supportYUV;
char useGL12;
char listCreated;
GLuint glDisplayList;
XVisualInfo vinfo;
GLXContext context;
};
static void resize (struct vo_instance_s *vo, int src[4])
{
mp_msg (MSGT_VO, MSGL_V, "[gl] resize ");
mp_msg (MSGT_VO, MSGL_V, "(%i, %i, %i, %i),", vo->x, vo->y, vo->w, vo->h);
if (src)
mp_msg (MSGT_VO, MSGL_V, "(%i, %i, %i, %i)\n", src[0], src[1], src[2], src[3]);
else
mp_msg (MSGT_VO, MSGL_V, "NULL\n");
glViewport (vo->x, vo->y, vo->w, vo->h);
if (src) {
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
// FIXME: how do we find out when we should flip ??
glTranslatef (-src[0], -src[1], 0);
glOrtho (0, src[2], src[3], 0, -1, 1);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
}
}
static int control (struct vo_instance_s *vo, int request, void *data, ...)
{
switch (request) {
case VOCTRL_SET_WINDOW:
vo->priv->window = *((Window *) data);
if (!vo->priv->context) {
vo->priv->context =
glXCreateContext (vo->priv->display, &vo->priv->vinfo, NULL, True);
} else glFinish();
glXMakeCurrent (vo->priv->display, vo->priv->window, vo->priv->context);
return VO_TRUE;
case VOCTRL_MOVE_DEST:
vo->x = ((int *)data)[0];
vo->y = ((int *)data)[1];
resize(vo, NULL);
return VO_TRUE;
case VOCTRL_RESIZE_DEST:
vo->w = ((int *)data)[0];
vo->h = ((int *)data)[1];
resize(vo, NULL);
return VO_TRUE;
case VOCTRL_RESIZE_SRC:
resize(vo, data);
return VO_TRUE;
}
return VO_NOTIMPL;
}
static unsigned int query_format (struct vo_instance_s *vo,
unsigned int format, int width, int height)
{
const int supported =
VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP |
VFCAP_HWSCALE_DOWN | VFCAP_FLIP;
switch (format) {
case IMGFMT_BGR24:
case IMGFMT_Y800:
return supported;
}
return 0;
}
static vo_buffer_t *get_buffer (struct vo_instance_s *vo)
{
int i;
vo_buffer_t *buffer = calloc (sizeof (vo_buffer_t), 1);
buffer->status = 0;
for (i = 0; i < vo->priv->numPlanes; i++) {
buffer->planes[i] =
calloc (vo->priv->planeWidth[i] * vo->priv->planeHeight[i] *
vo->priv->planeBytesPerPixel[i], 1);
buffer->stride[i] =
vo->priv->planeWidth[i] * vo->priv->planeBytesPerPixel[i];
}
return buffer;
}
static void release_buffer (struct vo_instance_s *vo, vo_buffer_t * buffer)
{
int i;
for (i = 0; i < vo->priv->numPlanes; i++)
free (buffer->planes[i]);
free (buffer);
}
static void uninit (struct vo_instance_s *vo)
{
glDeleteTextures (vo->priv->numTextures, vo->priv->planeTexture);
vo->priv->numTextures = 0;
glDeleteLists (vo->priv->glDisplayList, 1);
vo->priv->listCreated = 0;
if (vo->priv->context)
glXDestroyContext (vo->priv->display, vo->priv->context);
free (vo->priv);
free (vo);
}
typedef struct {
int pixelBytes;
GLint internalFormat;
GLenum format;
GLenum type;
int width_div;
int height_div;
} PlaneInfo;
typedef struct {
unsigned int format;
char numPlanes;
PlaneInfo plane[4];
} FormatInfo;
FormatInfo formatInfos[] = {
{
IMGFMT_RGB8, 1, {
{1, 0, GL_RGB, GL_UNSIGNED_BYTE_2_3_3_REV, 1, 1},
}
}, {
IMGFMT_RGB15, 1, {
{2, 0, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 1},
}
}, {
IMGFMT_RGB16, 1, {
{2, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, 1, 1},
}
}, {
IMGFMT_RGB24, 1, {
{3, 0, GL_RGB, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
IMGFMT_RGB32, 1, {
{4, 0, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
IMGFMT_BGR8, 1, {
{1, 0, GL_RGB, GL_UNSIGNED_BYTE_3_3_2, 1, 1},
}
}, {
IMGFMT_BGR15, 1, {
{2, 0, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, 1, 1},
}
}, {
IMGFMT_BGR16, 1, {
{2, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, 1},
}
}, {
IMGFMT_BGR24, 1, {
{3, 0, GL_BGR, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
IMGFMT_BGR32, 1, {
{4, 0, GL_BGRA, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
IMGFMT_Y800, 1, {
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
IMGFMT_YV12, 3, {
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1},
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 2, 2},
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 2, 2},
}
}, {
IMGFMT_444P, 3, {
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1},
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1},
{1, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, 1},
}
}, {
0, 0, {
{0, 0, 0, 0, 0, 0},
}
}
};
static void analyzeFormat (struct vo_instance_s *vo, unsigned int format)
{
int i = 0;
FormatInfo *fi;
while (formatInfos[i].format != 0 && formatInfos[i].format != format)
i++;
if (formatInfos[i].format != format) {
mp_msg (MSGT_VO, MSGL_ERR,
"[gl] Unknown image format. This shouldn't happen!\n");
};
fi = &formatInfos[i];
vo->priv->numPlanes = fi->numPlanes;
for (i = 0; i < fi->numPlanes; i++) {
vo->priv->planeWidth[i] = vo->priv->img_width / fi->plane[i].width_div;
vo->priv->planeHeight[i] = vo->priv->img_height / fi->plane[i].height_div;
vo->priv->planeBytesPerPixel[i] = fi->plane[i].pixelBytes;
if (fi->plane[i].internalFormat != 0)
vo->priv->planeInternalFormat[i] = fi->plane[i].internalFormat;
else
vo->priv->planeInternalFormat[i] = DEFAULT_INTERNAL_FORMAT;
vo->priv->planeFormat[i] = fi->plane[i].format;
vo->priv->planeType[i] = fi->plane[i].type;
}
}
static void createTextures (struct vo_instance_s *vo)
{
int i;
char *texInitData = NULL;
char initVal = 0;
int tmp, size;
if (vo->priv->numTextures > 0)
glDeleteTextures (vo->priv->numTextures, vo->priv->planeTexture);
glGenTextures (vo->priv->numPlanes, vo->priv->planeTexture);
vo->priv->numTextures = vo->priv->numPlanes;
for (i = 0; i < vo->priv->numPlanes; i++) {
tmp = 1;
while (tmp < vo->priv->planeWidth[i])
tmp *= 2;
vo->priv->planeTextureWidth[i] = tmp;
tmp = 1;
while (tmp < vo->priv->planeHeight[i])
tmp *= 2;
vo->priv->planeTextureHeight[i] = tmp;
mp_msg (MSGT_VO, MSGL_V,
"[gl] Allocating texture of size %dx%d ...\n",
vo->priv->planeTextureWidth[i], vo->priv->planeTextureHeight[i]);
size = vo->priv->planeTextureWidth[i] * vo->priv->planeTextureHeight[i];
texInitData = malloc (size);
if (i == 0)
initVal = 0;
else
initVal = 128; // no green borders in YUV
memset (texInitData, initVal, size);
glBindTexture (GL_TEXTURE_2D, vo->priv->planeTexture[i]);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D (GL_TEXTURE_2D, 0, vo->priv->planeInternalFormat[i],
vo->priv->planeTextureWidth[i],
vo->priv->planeTextureHeight[i], 0, GL_LUMINANCE,
GL_UNSIGNED_BYTE, texInitData);
mp_msg (MSGT_VO, MSGL_V, "[gl] glTexImage2D finished with %d\n",
glGetError ());
free (texInitData);
}
}
static void createDisplayList (struct vo_instance_s *vo)
{
int i;
GLfloat xcov[4], ycov[4];
if (vo->priv->listCreated)
glDeleteLists (vo->priv->glDisplayList, 1);
vo->priv->glDisplayList = glGenLists (1);
for (i = 0; i < vo->priv->numPlanes; i++) {
xcov[i] =
(GLfloat) vo->priv->planeWidth[i] /
(GLfloat) vo->priv->planeTextureWidth[i];
ycov[i] =
(GLfloat) vo->priv->planeHeight[i] /
(GLfloat) vo->priv->planeTextureHeight[i];
}
glNewList (vo->priv->glDisplayList, GL_COMPILE);
if (vo->priv->numPlanes == 1) {
i = 0;
glBindTexture (GL_TEXTURE_2D, vo->priv->planeTexture[i]);
glBegin (GL_QUADS);
glTexCoord2f (0, 0);
glVertex2i (0, 0);
glTexCoord2f (xcov[i], 0);
glVertex2i (vo->priv->img_width, 0);
glTexCoord2f (xcov[i], ycov[i]);
glVertex2i (vo->priv->img_width, vo->priv->img_height);
glTexCoord2f (0, ycov[i]);
glVertex2i (0, vo->priv->img_height);
glEnd ();
} else
unimpl ();
glEndList ();
vo->priv->listCreated = 1;
}
static int config (struct vo_instance_s *vo, int width, int height,
int d_width, int d_height, unsigned int format)
{
int dest_coords[] = {0, 0, width, height};
vo->priv->img_width = width;
vo->priv->img_height = height;
vo->priv->d_width = d_width;
vo->priv->d_height = d_height;
vo->buffer_w = width;
vo->buffer_h = height;
vo->w = d_width;
vo->h = d_height;
analyzeFormat (vo, format);
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glClearColor (0, 0, 0, 0);
createTextures (vo);
createDisplayList (vo);
resize (vo, dest_coords);
return VO_TRUE;
}
static void updateTexture (struct vo_instance_s *vo, int planeNr, int x,
int y, int w, int h, unsigned char *data)
{
mp_msg (MSGT_VO, MSGL_DBG1, "[gl] updateTexture (%i, %i, %i, %i, %i)\n", planeNr, x, y, w, h);
glBindTexture (GL_TEXTURE_2D, vo->priv->planeTexture[planeNr]);
glTexSubImage2D (GL_TEXTURE_2D, 0, x, y, w, h,
vo->priv->planeFormat[planeNr],
vo->priv->planeType[planeNr], data);
}
static void draw_slice (struct vo_instance_s *vo, vo_buffer_t * buffer,
unsigned char *src[], int stride[], int w, int h,
int x, int y)
{
mp_msg (MSGT_VO, MSGL_DBG1, "[gl] draw_slice\n",stride[0]);
}
static int frame_done (struct vo_instance_s *vo, vo_buffer_t * buffer)
{
int i;
mp_msg (MSGT_VO, MSGL_DBG1, "[gl] frame_done\n");
for (i = 0; i < vo->priv->numPlanes; i++)
updateTexture (vo, i, 0, 0, vo->buffer_w, vo->buffer_h, buffer->planes[i]);
glCallList (vo->priv->glDisplayList);
glFlush ();
return 0;
}
static void show_frame (struct vo_instance_s *vo, vo_buffer_t * buffer,
unsigned int time_pos)
{
mp_msg (MSGT_VO, MSGL_DBG1, "[gl] show_frame\n");
glXSwapBuffers (vo->priv->display, vo->priv->window);
glClear (GL_COLOR_BUFFER_BIT);
}
static vo_instance_t *preinit (char *args, void *x11_display)
{
vo_instance_t *vo;
if (!x11_display)
return NULL; // X11 not available
vo = calloc (sizeof (vo_instance_t), 1);
vo->priv = calloc (sizeof (struct vo_priv_s), 1);
memset (vo->priv, 0, sizeof (struct vo_priv_s));
vo->priv->numTextures = 0;
vo->priv->useGL12 = 1;
vo->priv->supportYUV = 0;
vo->priv->display = x11_display;
XMatchVisualInfo(vo->priv->display, DefaultScreen(vo->priv->display), 24, TrueColor, &vo->priv->vinfo);
#if 0
if (arg) {
if (strcmp (arg, "gl11") == 0) {
useGL12 = 0;
} else if (strcmp (arg, "glyuv") == 0) {
supportYUV = 1;
} else {
printf ("[gl] Unknown subdevice: %s\n", arg);
return ENOSYS;
}
}
#endif
vo->buffer_flags = 0;
vo->num_buffers = 0;
// functions:
vo->query_format = query_format;
vo->control = control;
vo->config = config;
vo->draw_slice = draw_slice;
vo->frame_done = frame_done;
vo->show_frame = show_frame;
vo->uninit = uninit;
vo->get_buffer = get_buffer;
vo->release_buffer = release_buffer;
return vo;
}
vo_info_t vo_driver_gl = {
MODULE_TYPE_VO, MODULE_VERSION, preinit, "gl", "OpenGL driver",
"Reimar Döffinger", "Reimar Döffinger", NULL,
VO_MODULE_CAPS_X11 | VO_MODULE_CAPS_WINDOW | VO_MODULE_CAPS_GUI, NULL,
NULL, 0
};