summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--xine_sxfe_frontend.c585
1 files changed, 577 insertions, 8 deletions
diff --git a/xine_sxfe_frontend.c b/xine_sxfe_frontend.c
index d50b2e9b..54131c0f 100644
--- a/xine_sxfe_frontend.c
+++ b/xine_sxfe_frontend.c
@@ -4,7 +4,7 @@
* See the main source file 'xineliboutput.c' for copyright information and
* how to reach the author.
*
- * $Id: xine_sxfe_frontend.c,v 1.147 2011-02-26 12:38:18 phintuka Exp $
+ * $Id: xine_sxfe_frontend.c,v 1.148 2011-02-26 13:10:38 phintuka Exp $
*
*/
@@ -41,6 +41,16 @@
# include <X11/extensions/Xinerama.h>
#endif
+#ifdef HAVE_OPENGL
+# include <GL/glx.h>
+# ifdef HAVE_DLFCN
+# include <dlfcn.h>
+# endif
+# ifdef HAVE_PTHREAD
+# include <pthread.h>
+# endif
+#endif
+
#include <xine.h>
#define LOG_MODULENAME "[vdr-sxfe] "
@@ -165,6 +175,22 @@ typedef struct sxfe_s {
/* HUD stuff */
#ifdef HAVE_XRENDER
uint8_t hud_visible;
+#ifdef HAVE_OPENGL
+ GLXDrawable opengl_window;
+ GLXContext opengl_context;
+ int screen_width, screen_height;
+#if 0
+ int32_t opengl_frame_period;
+#endif
+ pthread_t opengl_drawing_thread;
+ pthread_mutex_t opengl_redraw_mutex;
+ pthread_cond_t opengl_redraw_cv;
+ Pixmap video_frame_pixmap;
+ GC video_frame_gc;
+ GLuint video_frame_texture;
+ GLuint osd_texture;
+ uint8_t opengl_deinit : 1;
+#endif
uint32_t *shape_mask_mem;
#ifdef HAVE_XSHAPE
Pixmap shape_mask_pixmap;
@@ -190,6 +216,20 @@ typedef struct sxfe_s {
} sxfe_t;
+#ifdef HAVE_OPENGL
+typedef int (*GLXGetVideoSyncProc) (unsigned int *count);
+typedef int (*GLXWaitVideoSyncProc) (int divisor,
+ int remainder,
+ unsigned int *count);
+typedef void (*GLXBindTexImageProc) (Display *display,
+ GLXDrawable drawable,
+ int buffer,
+ int *attribList);
+GLXGetVideoSyncProc getVideoSync;
+GLXWaitVideoSyncProc waitVideoSync;
+GLXBindTexImageProc bindTexImage;
+#endif
+
#define DOUBLECLICK_TIME 500 // ms
#define OSD_DEF_WIDTH 720
@@ -886,6 +926,16 @@ static int hud_osd_command(frontend_t *this_gen, struct osd_command_s *cmd)
return 1;
}
+#ifdef HAVE_OPENGL
+// Signals a change to the opengl drawing thread
+void opengl_trigger_drawing_thread(sxfe_t *this)
+{
+ pthread_mutex_lock(&this->opengl_redraw_mutex);
+ pthread_cond_signal(&this->opengl_redraw_cv);
+ pthread_mutex_unlock(&this->opengl_redraw_mutex);
+}
+#endif
+
static void hud_frame_output_cb (void *data,
int video_width, int video_height,
double video_pixel_aspect,
@@ -896,6 +946,13 @@ static void hud_frame_output_cb (void *data,
{
sxfe_t *this = (sxfe_t*)data;
+#ifdef HAVE_OPENGL
+ // Inform the opengl drawing thread
+ if (this->opengl_always || this->opengl_hud) {
+ opengl_trigger_drawing_thread(this);
+ }
+#endif
+
/* Call the original handler */
this->x.frame_output_handler(data,
video_width, video_height,
@@ -906,11 +963,14 @@ static void hud_frame_output_cb (void *data,
win_x, win_y);
/* Set the desitination position if the video window is active */
+#ifdef HAVE_OPENGL
+ if (!(this->opengl_always || this->opengl_hud))
+#endif
if (this->video_win_active) {
/* Clear the window if the size has changed */
if (this->video_win_changed) {
- Window win = this->window[this->fullscreen ? 1 : 0];
+ Window win = this->window[!!this->fullscreen];
GC gc = XCreateGC(this->display, win, 0, NULL);
XSetForeground(this->display, gc, 0x00000000);
XFillRectangle(this->display, win, gc, 0, 0, this->x.width-1, this->x.height-1);
@@ -1032,14 +1092,13 @@ static int hud_osd_open(sxfe_t *this)
this->xshape_hud = 0;
}
}
-
#endif
this->hud_visible = 0;
this->surf_win = xrender_surf_adopt(this->display, this->hud_window, this->hud_vis, HUD_MAX_WIDTH, HUD_MAX_HEIGHT);
this->surf_img = xrender_surf_new(this->display, this->hud_window, this->hud_vis, HUD_MAX_WIDTH, HUD_MAX_HEIGHT, 1);
- if (this->xshape_hud)
+ if (this->xshape_hud || this->opengl_hud || this->opengl_always)
this->surf_back_img = xrender_surf_new(this->display, this->hud_window, this->hud_vis,
DisplayWidth(this->display, this->screen),
DisplayHeight(this->display, this->screen), 1);
@@ -1103,12 +1162,14 @@ static void hud_osd_focus(sxfe_t *this, XFocusChangeEvent *fev)
if (fev->type == FocusIn) {
/* Show HUD again if sxfe window receives focus */
- XMapWindow(this->display, this->hud_window);
+ if (!(this->opengl_always || this->opengl_hud))
+ XMapWindow(this->display, this->hud_window);
}
else if (fev->type == FocusOut) {
/* Dismiss HUD window if focusing away from frontend window */
- XUnmapWindow(this->display, this->hud_window);
+ if (!(this->opengl_always || this->opengl_hud))
+ XUnmapWindow(this->display, this->hud_window);
}
XUnlockDisplay(this->display);
@@ -1333,6 +1394,489 @@ static void create_windows(sxfe_t *this)
XUnlockDisplay(this->display);
}
+#ifdef HAVE_OPENGL
+
+#if 0
+static void time_measure_start(struct timeval *time_start)
+{
+ gettimeofday(time_start, NULL);
+}
+
+static int time_measure_end(struct timeval *time_start)
+{
+ struct timeval time_end;
+ int diff;
+ gettimeofday(&time_end, NULL);
+ diff = time_end.tv_usec - time_start->tv_usec;
+ if (time_end.tv_usec < time_start->tv_usec) {
+ diff += 1000000;
+ }
+ return diff;
+}
+#endif
+
+static int opengl_init_dl(sxfe_t *this)
+{
+ void *dlhand;
+
+ // Get handles to important functions
+ dlhand = dlopen (NULL, RTLD_LAZY);
+ if (!dlhand) {
+ LOGERR("opengl_init(): dlopen failed (%s)", dlerror());
+ return -1;
+ }
+
+ void *(*glXGetProcAddressARB)(unsigned char *) = NULL;
+ glXGetProcAddressARB = (void *(*)(unsigned char *))dlsym(dlhand, "glXGetProcAddressARB");
+
+ if (glXGetProcAddressARB) {
+
+ if (!(waitVideoSync = (void *)glXGetProcAddressARB((unsigned char *)"glXWaitVideoSyncSGI"))) {
+ LOGMSG("glXGetProcAddressARB(glXWaitVideoSyncSGI) failed");
+ goto error;
+ }
+ if (!(getVideoSync = (void *)glXGetProcAddressARB((unsigned char *)"glXGetVideoSyncSGI"))) {
+ LOGMSG("glXGetProcAddressARB(glXGetVideoSyncSGI) failed");
+ goto error;
+ }
+ if (!(bindTexImage = (void *)glXGetProcAddressARB((unsigned char *)"glXBindTexImageEXT"))) {
+ LOGMSG("glXGetProcAddressARB(glXBindTexImageEXT) failed");
+ goto error;
+ }
+
+ } else {
+
+ LOGMSG("glXGetProcAddressARB not found");
+
+ dlerror();
+ bindTexImage = dlsym(dlhand,"glXBindTexImageEXT");
+ if (dlerror() != NULL) {
+ LOGMSG("opengl_init(): can not get pointer to glXBindTexImageEXT");
+ goto error;
+ }
+ getVideoSync = dlsym(dlhand,"glXGetVideoSyncSGI");
+ if (dlerror() != NULL) {
+ LOGMSG("opengl_init(): can not get pointer to glXGetVideoSyncSGI");
+ goto error;
+ }
+ waitVideoSync = dlsym(dlhand,"glXWaitVideoSyncSGI");
+ if (dlerror() != NULL) {
+ LOGMSG("opengl_init(): can not get pointer to glXWaitVideoSyncSGI");
+ goto error;
+ }
+ }
+
+ dlclose(dlhand);
+ return 0;
+
+ error:
+ dlclose(dlhand);
+ return -1;
+}
+
+static int opengl_init(sxfe_t *this)
+{
+ int glx_major, glx_minor;
+ Window root;
+ int n;
+ GLXFBConfig *fbconfigs;
+ GLXFBConfig fbcroot;
+ XSetWindowAttributes attr;
+ XVisualInfo *visinfo;
+ const char* gl_version;
+ int gl_major, gl_minor;
+ static const int fbc_attr[] = {
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT | GLX_WINDOW_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ GLX_BIND_TO_TEXTURE_RGBA_EXT, True,
+ GLX_DOUBLEBUFFER, True,
+ GLX_DEPTH_SIZE, 0,
+ GLX_ALPHA_SIZE, 0,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ None
+ };
+ int fbc_attr2[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER, 1,
+ None
+ };
+ static const int pixmapAttribs[] = {
+ GLX_TEXTURE_TARGET_EXT,
+ GLX_TEXTURE_2D_EXT,
+ GLX_TEXTURE_FORMAT_EXT,
+ GLX_TEXTURE_FORMAT_RGBA_EXT,
+ None
+ };
+ GLXPixmap glxpixmap;
+#if 0
+ int frame_period_average = 0;
+ int frame_period;
+ const int frame_period_required_samples = 100;
+ struct timeval t;
+ int i;
+ int unsigned sync;
+#endif
+ const char *glxExtensions;
+
+ // Get handles to important functions
+ if (opengl_init_dl(this) < 0) {
+ return -1;
+ }
+
+ // Get the GLX version
+ LOGVERBOSE("Get GLX version ...");
+ if (!glXQueryVersion (this->display, &glx_major, &glx_minor)) {
+ LOGMSG("no GLX support");
+ return -1;
+ }
+ LOGVERBOSE("GLX %d.%d", glx_major, glx_minor);
+
+ // Should have full GLX 1.3 for GL 1.2,
+ if (!(glx_major > 1 || glx_minor > 2)) {
+ const char* exts = glXQueryExtensionsString (this->display, this->screen);
+ if (!exts || !strstr (exts, "GLX_SGIX_fbconfig")) {
+ LOGMSG("no glx fbconfig support");
+ return -1;
+ }
+ }
+ LOGVERBOSE("Found GLX fbconfig support");
+
+ if (!(glx_major > 1 || glx_minor > 2)) {
+ LOGMSG("no glx 1.3 support");
+ return -1;
+ }
+
+ // Check for important extension
+ glxExtensions = glXQueryExtensionsString (this->display, this->screen);
+ if (!strstr (glxExtensions, "GLX_EXT_texture_from_pixmap")) {
+ LOGMSG("No texture from pixmap extension");
+ return -1;
+ }
+ LOGVERBOSE("Found texture from pixmap extension");
+ if (!strstr (glxExtensions, "GLX_SGI_video_sync")) {
+ LOGMSG("No sgi video sync extension");
+ return -1;
+ }
+ LOGVERBOSE("Found sgi video sync extension");
+
+ // Get handles to important functions
+ if (opengl_init_dl(this) < 0) {
+ return -1;
+ }
+
+ // Get properties of the root window
+ root = RootWindow (this->display, this->screen);
+ this->screen_width = DisplayWidth (this->display, this->screen);
+ this->screen_height = DisplayHeight (this->display, this->screen);
+
+ // Create the opengl window
+ if (!(fbconfigs = glXChooseFBConfig(this->display, this->screen, fbc_attr, &n))) {
+ LOGMSG("No glx frame buffer");
+ return -1;
+ }
+
+ fbcroot = fbconfigs[0];
+ XFree (fbconfigs);
+ visinfo = glXChooseVisual(this->display, this->screen, fbc_attr2);
+ attr.colormap = XCreateColormap (this->display, root, visinfo->visual, AllocNone);
+ attr.override_redirect = True;
+ this->opengl_window = XCreateWindow (this->display, root,
+ 0, 0, this->screen_width, this->screen_height, 0,
+ visinfo->depth, InputOutput,
+ visinfo->visual, CWColormap | CWOverrideRedirect, &attr);
+ XSelectInput(this->display, this->opengl_window,
+ StructureNotifyMask |
+ ExposureMask |
+ KeyPressMask |
+ ButtonPressMask |
+ FocusChangeMask);
+#ifdef HAVE_XSHAPE
+ if (this->xshape_hud)
+ XShapeCombineRectangles(this->display, this->opengl_window, ShapeInput, 0, 0, NULL, 0,
+ ShapeSet, Unsorted);
+#endif
+ this->opengl_context = glXCreateContext(this->display, visinfo, None, GL_TRUE);
+ XFree (visinfo);
+ if (this->opengl_context == NULL) {
+ LOGERR("Can't create glx context");
+ return -1;
+ }
+
+ glXMakeCurrent(this->display, this->opengl_window, this->opengl_context);
+ if (!(gl_version = (const char*) glGetString (GL_VERSION))) {
+ LOGERR("Failed to initialize GL");
+ return -1;
+ }
+ sscanf (gl_version, "%d.%d", &gl_major, &gl_minor);
+ if (!(gl_major > 1 || gl_minor > 1)) {
+ LOGMSG("No GL 1.2 support on your platform");
+ return -1;
+ }
+
+ if (!(gl_major > 1 || gl_minor > 2)) {
+ LOGMSG("No GL 1.3 support on your platform");
+ return -1;
+ }
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+ glOrtho (0, this->screen_width-1, 0, this->screen_height-1, 0, 65535);
+ glEnable(GL_TEXTURE_2D);
+ glEnable (GL_BLEND);
+ glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ // Hide cursor
+ set_cursor(this->display, this->opengl_window, 0);
+
+ // Associate video and hud with a texture
+ this->video_frame_pixmap = XCreatePixmap(this->display, this->opengl_window,
+ this->screen_width, this->screen_height,
+ DefaultDepth(this->display, this->screen));
+ this->video_frame_gc = XCreateGC(this->display, this->video_frame_pixmap, 0, NULL);
+ glxpixmap = glXCreatePixmap (this->display, fbcroot, this->video_frame_pixmap, pixmapAttribs);
+ glGenTextures (1, &this->video_frame_texture);
+ glBindTexture (GL_TEXTURE_2D, this->video_frame_texture);
+ bindTexImage (this->display, glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glxpixmap = glXCreatePixmap (this->display, fbcroot, this->surf_back_img->draw, pixmapAttribs);
+ glGenTextures (1, &this->osd_texture);
+ glBindTexture (GL_TEXTURE_2D, this->osd_texture);
+ bindTexImage (this->display, glxpixmap, GLX_FRONT_LEFT_EXT, NULL);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+#if 0
+ // Detect the frame rate
+ for (i = 0; i < frame_period_required_samples + 2; i++) {
+ if (i > 1) {
+ frame_period = time_measure_end(&t);
+ frame_period_average += frame_period;
+ }
+ time_measure_start(&t);
+ (*getVideoSync) (&sync);
+ (*waitVideoSync) (2, (sync + 1) % 2, &sync);
+ }
+ frame_period_average /= frame_period_required_samples;
+ this->opengl_frame_period = frame_period_average;
+ LOGMSG("opengl_init(): average frame period is %d us", this->opengl_frame_period);
+#endif
+
+ return 0;
+}
+
+// Frees all opengl related resources
+static void opengl_deinit(sxfe_t *this)
+{
+ XFreePixmap(this->display, this->video_frame_pixmap);
+ glXDestroyContext(this->display, this->opengl_context);
+ XDestroyWindow(this->display, this->opengl_window);
+}
+
+// Handles video output
+static void *opengl_draw_frame_thread(void *arg)
+{
+ sxfe_t *this=(sxfe_t *) arg;
+ int unsigned sync;
+ int unsigned prev_sync = 0;
+ int draw_frame = 0, window_mapped = 0, keep_osd_open = 0;
+ int prev_hud_visible = 0;
+ int16_t video_x0, video_y0, video_x1, video_y1;
+ int16_t osd_x0 ,osd_y0, osd_x1, osd_y1;
+ GLfloat osd_alpha = 0;
+ GLfloat osd_alpha_step = 0.2;
+ static int unsigned count = 0;
+ int16_t win_width = -1, win_height = -1;
+ int16_t win_x = -1, win_y = -1;
+ XRectangle xrect;
+ XDouble video_tex_width, video_tex_height;
+ int first_frame = 1;
+
+ while (1) {
+
+ // Wait for trigger
+ pthread_mutex_lock(&this->opengl_redraw_mutex);
+ pthread_cond_wait(&this->opengl_redraw_cv, &this->opengl_redraw_mutex);
+ pthread_mutex_unlock(&this->opengl_redraw_mutex);
+ count++;
+
+ // Check if we should exit
+ if (this->opengl_deinit)
+ break;
+
+ // Check if we need to change the shape of the window
+ if (win_x != this->x.xpos || win_y != this->x.ypos ||
+ win_width != this->x.width || win_height != this->x.height) {
+
+ // Update sizes
+ win_x = this->x.xpos;
+ win_y = this->x.ypos;
+ win_width = this->x.width;
+ win_height = this->x.height;
+ xrect.x = win_x;
+ xrect.y = win_y;
+ xrect.width = win_width;
+ xrect.height = win_height;
+
+ // Set the shape of the opengl window
+#ifdef HAVE_XSHAPE
+ if (this->xshape_hud)
+ XShapeCombineRectangles(this->display, this->opengl_window, ShapeBounding, 0, 0, &xrect, 1, ShapeSet, 0);
+#endif
+ }
+ LOGVERBOSE("win_x=%d win_y=%d win_width=%d win_height=%d", win_x, win_y, win_width, win_height);
+ // Update the global alpha value of the OSD
+ keep_osd_open = 0;
+ if (this->hud_visible) {
+ if (osd_alpha < 1.0) {
+ osd_alpha += osd_alpha_step;
+ if (osd_alpha > 1.0)
+ osd_alpha = 1.0;
+ }
+ } else {
+ this->video_win_active = 0;
+ if (osd_alpha > 0.0) {
+ osd_alpha -= osd_alpha_step;
+ if (osd_alpha < 0.0)
+ osd_alpha = 0.0;
+ keep_osd_open = 1;
+ }
+ }
+ LOGVERBOSE("osd_alpha=%.2f keep_osd_open=%d", osd_alpha, keep_osd_open);
+
+ // Decide if we need to do something
+ draw_frame = (this->hud_visible || keep_osd_open || this->opengl_always);
+ if ((this->opengl_hud && this->hud_visible && !prev_hud_visible) ||
+ (this->opengl_always && first_frame)) {
+ LOGDBG("redirecting video to opengl frame texture");
+ xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) this->video_frame_pixmap);
+ draw_frame = 0; // first frame not yet available in pixmap
+ osd_alpha -= 2*osd_alpha_step; // delay the osd
+ }
+ if (this->opengl_hud && !this->hud_visible && prev_hud_visible && !keep_osd_open) {
+ LOGDBG("redirecting video to window");
+ xine_port_send_gui_data(this->x.video_port, XINE_GUI_SEND_DRAWABLE_CHANGED,
+ (void*) this->window[this->fullscreen ? 1 : 0]);
+ draw_frame = 1; // draw the last frame
+ }
+ if (draw_frame) {
+ LOGVERBOSE("drawing frame nr %d", count);
+ XLockDisplay(this->display);
+ video_tex_width = 1.0;
+ video_tex_height = 1.0;
+ if (this->video_win_active) {
+ video_x0 = win_x + this->video_win_x;
+ video_y0 = win_y + this->video_win_y;
+ video_tex_width = ((XDouble)win_width) / (XDouble)this->screen_width;
+ video_tex_height = ((XDouble)win_height) / (XDouble)this->screen_height;
+ video_x1 = video_x0 + (this->video_win_w - 1);
+ video_y1 = video_y0 + (this->video_win_h - 1);
+ } else {
+ video_x0 = win_x;
+ video_y0 = win_y;
+ video_x1 = video_x0 + this->screen_width - 1;
+ video_y1 = video_y0 + this->screen_height - 1;
+ }
+ osd_x0 = win_x;
+ osd_y0 = win_y;
+ osd_x1 = osd_x0 + this->screen_width - 1;
+ osd_y1 = osd_y0 + this->screen_height - 1;
+ video_y0 = (this->screen_height - 1) - video_y0;
+ video_y1 = (this->screen_height - 1) - video_y1;
+ osd_y0 = (this->screen_height - 1) - osd_y0;
+ osd_y1 = (this->screen_height - 1) - osd_y1;
+ LOGVERBOSE("video_x0=%d video_y0=%d video_x1=%d video_y1=%d", video_x0, video_y0, video_x1, video_y1);
+ LOGVERBOSE("osd_x0=%d osd_y0=%d osd_x1=%d osd_y1=%d", osd_x0, osd_y0, osd_x1, osd_y1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glBindTexture (GL_TEXTURE_2D, this->video_frame_texture);
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, video_tex_height); glVertex3f(video_x0, video_y1 , 0.0);
+ glTexCoord2f(video_tex_width, video_tex_height); glVertex3f(video_x1, video_y1, 0.0);
+ glTexCoord2f(video_tex_width, 0.0); glVertex3f(video_x1, video_y0, 0.0);
+ glTexCoord2f(0.0, 0.0); glVertex3f(video_x0, video_y0, 0.0);
+ glEnd();
+ if (this->hud_visible || keep_osd_open) {
+ glColor4f(1.0f, 1.0f, 1.0f, osd_alpha);
+ glBindTexture (GL_TEXTURE_2D, this->osd_texture);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 1.0); glVertex3f(osd_x0, osd_y1 , 0.0);
+ glTexCoord2f(1.0, 1.0); glVertex3f(osd_x1, osd_y1, 0.0);
+ glTexCoord2f(1.0, 0.0); glVertex3f(osd_x1, osd_y0, 0.0);
+ glTexCoord2f(0.0, 0.0); glVertex3f(osd_x0, osd_y0, 0.0);
+ glEnd();
+ }
+ glXSwapBuffers(this->display, this->opengl_window);
+ XUnlockDisplay(this->display);
+ first_frame = 0;
+ }
+
+ if (this->hud_visible && prev_hud_visible && !window_mapped) {
+ (*getVideoSync) (&sync);
+ (*waitVideoSync) (2, (sync + 1) % 2, &sync); // ensure that window shows correct frame
+ LOGDBG("mapping opengl window");
+ XLockDisplay(this->display);
+ XRaiseWindow (this->display, this->opengl_window);
+ XMapWindow(this->display, this->opengl_window);
+ XUnlockDisplay(this->display);
+ window_mapped = 1;
+ }
+ if (!this->hud_visible && !prev_hud_visible && window_mapped && !keep_osd_open) {
+ LOGDBG("unmapping opengl window");
+ XLockDisplay(this->display);
+ XLowerWindow (this->display, this->opengl_window);
+ XUnmapWindow(this->display, this->opengl_window);
+ XUnlockDisplay(this->display);
+ window_mapped = 0;
+ }
+ if (!keep_osd_open) {
+ prev_hud_visible = this->hud_visible;
+ }
+ prev_sync = sync;
+ }
+
+ // Free resources
+ opengl_deinit(this);
+ return NULL;
+}
+
+static int opengl_start(sxfe_t *this)
+{
+ LOGDBG("sxfe_display_open: starting opengl drawing thread");
+ pthread_mutex_init(&this->opengl_redraw_mutex, NULL);
+ pthread_cond_init(&this->opengl_redraw_cv, NULL);
+
+ XLockDisplay (this->display);
+ if (opengl_init(this) < 0) {
+ LOGMSG("OpenGL initialization failed");
+ XUnlockDisplay (this->display);
+ return 0;
+ }
+ XUnlockDisplay (this->display);
+
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ if (pthread_create(&this->opengl_drawing_thread, NULL, opengl_draw_frame_thread, (void *)this)) {
+ pthread_attr_destroy(&attr);
+ LOGERR("sxfe_display_open: can not start OpenGL drawing thread");
+ this->opengl_always = this->opengl_hud = 0; /* avoid pthread_join segfault */
+ return 0;
+ }
+ pthread_attr_destroy(&attr);
+
+ return 1;
+}
+
+#endif
+
/*
* sxfe_display_open
*
@@ -1520,9 +2064,18 @@ static int sxfe_display_open(frontend_t *this_gen,
XUnlockDisplay (this->display);
#ifdef HAVE_XRENDER
+ // Init the osd window
if (!hud_osd_open(this))
return 0;
-#endif
+
+# ifdef HAVE_OPENGL
+ // Start the drawing thread
+ if (this->opengl_always || this->opengl_hud) {
+ if (!opengl_start(this))
+ return 0;
+ }
+# endif // HAVE_OPENGL
+#endif // HAVE_XRENDER
return 1;
}
@@ -1628,7 +2181,7 @@ static void sxfe_toggle_fullscreen(fe_t *this_gen, int fullscreen)
}
if (fullscreen < 0)
- fullscreen = this->fullscreen ? 0 : 1;
+ fullscreen = !this->fullscreen;
this->fe.fe_display_config((frontend_t*)this, -1, -1, this->origwidth, this->origheight,
fullscreen,
@@ -1744,6 +2297,11 @@ static void XKeyEvent_handler(sxfe_t *this, XKeyEvent *kev)
*/
static void XConfigureEvent_handler(sxfe_t *this, XConfigureEvent *cev)
{
+#ifdef HAVE_OPENGL
+ if (cev->window == this->opengl_window)
+ return;
+#endif
+
/* Move and resize HUD along with main or fullscreen window */
#ifdef HAVE_XRENDER
if(this->hud)
@@ -1995,6 +2553,17 @@ static void sxfe_display_close(frontend_t *this_gen)
if(this->display) {
+#ifdef HAVE_OPENGL
+ if (this->opengl_always || this->opengl_hud) {
+ void *status;
+ this->opengl_deinit = 1;
+ opengl_trigger_drawing_thread(this);
+ if (pthread_join(this->opengl_drawing_thread, &status)) {
+ LOGERR("sxfe_display_close: can not join opengl drawing thread!");
+ }
+ }
+#endif
+
#ifdef HAVE_XRENDER
hud_osd_close(this);
#endif