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
};