mirror of
https://github.com/brl/mutter.git
synced 2025-02-16 13:24:09 +00:00
Add support for quad-buffer stereo
Track the stereo status of windows using the new EXT_stereo_tree GLX extension. When stereo is enabled or disabled, a restart is triggered via meta_restart() after a timeout, setting a _META_ENABLE_STEREO property on the root window to indicate whether we should turn on a stereo stage for clutter. The property avoids a loop, since we need to enable stereo *before* initializing Clutter and GL, but we need GL to figure out whether we have stereo windows. Stereo windows are drawn to the stage using new functionality in Cogl to setup a stereo context, select which buffer to draw to, and draw either the left or right buffer of a stereo texture_from_pixmap.
This commit is contained in:
parent
c249c3f3e5
commit
14d2f8fddc
@ -135,6 +135,8 @@ libmutter_la_SOURCES = \
|
||||
core/restart.c \
|
||||
core/session.c \
|
||||
core/session.h \
|
||||
core/stereo.c \
|
||||
core/stereo.h \
|
||||
core/stack.c \
|
||||
core/stack.h \
|
||||
core/stack-tracker.c \
|
||||
|
@ -26,6 +26,8 @@ struct _MetaCompositor
|
||||
gint64 server_time_query_time;
|
||||
gint64 server_time_offset;
|
||||
|
||||
int glx_opcode;
|
||||
|
||||
guint server_time_is_monotonic_time : 1;
|
||||
guint show_redraw : 1;
|
||||
guint debug : 1;
|
||||
@ -51,6 +53,9 @@ struct _MetaCompScreen
|
||||
|
||||
gint switch_workspace_in_progress;
|
||||
|
||||
guint stereo_tree_ext : 1;
|
||||
guint have_stereo_windows : 1;
|
||||
|
||||
MetaPluginManager *plugin_mgr;
|
||||
};
|
||||
|
||||
@ -72,4 +77,9 @@ gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
||||
|
||||
void meta_check_end_modal (MetaScreen *screen);
|
||||
|
||||
gboolean meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||
Window xwindow);
|
||||
void meta_compositor_select_stereo_notify (MetaScreen *screen,
|
||||
Window xwindow);
|
||||
|
||||
#endif /* META_COMPOSITOR_PRIVATE_H */
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "meta-window-group.h"
|
||||
#include "window-private.h" /* to check window->hidden */
|
||||
#include "display-private.h"
|
||||
#include "stereo.h"
|
||||
#include "util-private.h"
|
||||
#include <X11/extensions/shape.h>
|
||||
#include <X11/extensions/Xcomposite.h>
|
||||
@ -544,6 +545,101 @@ redirect_windows (MetaCompositor *compositor,
|
||||
}
|
||||
}
|
||||
|
||||
#define GLX_STEREO_TREE_EXT 0x20F5
|
||||
#define GLX_STEREO_NOTIFY_MASK_EXT 0x00000001
|
||||
#define GLX_STEREO_NOTIFY_EXT 0x00000000
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
unsigned long serial;
|
||||
Bool send_event;
|
||||
Display *display;
|
||||
int extension;
|
||||
int evtype;
|
||||
Drawable window;
|
||||
Bool stereo_tree;
|
||||
} StereoNotifyEvent;
|
||||
|
||||
static gboolean
|
||||
screen_has_stereo_tree_ext (MetaScreen *screen)
|
||||
{
|
||||
#if 0
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
const char *extensions_string;
|
||||
|
||||
static const char * (*query_extensions_string) (Display *display,
|
||||
int screen);
|
||||
|
||||
if (query_extensions_string == NULL)
|
||||
query_extensions_string =
|
||||
(const char * (*) (Display *, int))
|
||||
cogl_get_proc_address ("glXQueryExtensionsString");
|
||||
|
||||
extensions_string = query_extensions_string (xdisplay,
|
||||
meta_screen_get_screen_number (screen));
|
||||
|
||||
return strstr (extensions_string, "EXT_stereo_tree") != 0;
|
||||
#else
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#include <GL/gl.h>
|
||||
|
||||
gboolean
|
||||
meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
static int (*query_drawable) (Display *dpy,
|
||||
Drawable draw,
|
||||
int attribute,
|
||||
unsigned int *value);
|
||||
|
||||
if (info->stereo_tree_ext)
|
||||
{
|
||||
unsigned int stereo_tree = 0;
|
||||
|
||||
if (query_drawable == NULL)
|
||||
query_drawable =
|
||||
(int (*) (Display *, Drawable, int, unsigned int *))
|
||||
cogl_get_proc_address ("glXQueryDrawable");
|
||||
|
||||
query_drawable (xdisplay, xwindow, GLX_STEREO_TREE_EXT, &stereo_tree);
|
||||
|
||||
return stereo_tree != 0;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_select_stereo_notify (MetaScreen *screen,
|
||||
Window xwindow)
|
||||
{
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
static void (*select_event) (Display *dpy,
|
||||
Drawable draw,
|
||||
unsigned long event_mask);
|
||||
|
||||
if (info->stereo_tree_ext)
|
||||
{
|
||||
if (select_event == NULL)
|
||||
select_event =
|
||||
(void (*) (Display *, Drawable, unsigned long))
|
||||
cogl_get_proc_address ("glXSelectEvent");
|
||||
|
||||
select_event (xdisplay, xwindow, GLX_STEREO_NOTIFY_MASK_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
MetaScreen *screen)
|
||||
@ -566,6 +662,8 @@ meta_compositor_manage_screen (MetaCompositor *compositor,
|
||||
info->output = None;
|
||||
info->windows = NULL;
|
||||
|
||||
info->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
|
||||
|
||||
meta_screen_set_cm_selection (screen);
|
||||
|
||||
info->stage = clutter_stage_new ();
|
||||
@ -956,6 +1054,22 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type == GenericEvent &&
|
||||
event->xcookie.extension == compositor->glx_opcode)
|
||||
{
|
||||
if (event->xcookie.evtype == GLX_STEREO_NOTIFY_EXT)
|
||||
{
|
||||
StereoNotifyEvent *stereo_event = (StereoNotifyEvent *)(event->xcookie.data);
|
||||
window = meta_display_lookup_x_window (compositor->display, stereo_event->window);
|
||||
|
||||
if (window != NULL)
|
||||
{
|
||||
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
|
||||
meta_window_actor_stereo_notify (window_actor, stereo_event->stereo_tree);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (event->type == meta_display_get_damage_event_base (compositor->display) + XDamageNotify)
|
||||
{
|
||||
/* Core code doesn't handle damage events, so we need to extract the MetaWindow
|
||||
@ -1183,6 +1297,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
{
|
||||
GList *old_stack;
|
||||
MetaCompScreen *info = meta_screen_get_compositor_data (screen);
|
||||
int stereo_window_count = 0;
|
||||
|
||||
DEBUG_TRACE ("meta_compositor_sync_stack\n");
|
||||
|
||||
@ -1260,12 +1375,16 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
||||
* near the front of the other.)
|
||||
*/
|
||||
info->windows = g_list_prepend (info->windows, actor);
|
||||
if (meta_window_actor_is_stereo (actor))
|
||||
stereo_window_count++;
|
||||
|
||||
stack = g_list_remove (stack, window);
|
||||
old_stack = g_list_remove (old_stack, actor);
|
||||
}
|
||||
|
||||
sync_actor_stacking (info);
|
||||
|
||||
meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1431,6 +1550,7 @@ MetaCompositor *
|
||||
meta_compositor_new (MetaDisplay *display)
|
||||
{
|
||||
MetaCompositor *compositor;
|
||||
int glx_major_opcode, glx_first_event, glx_first_error;
|
||||
|
||||
if (!composite_at_least_version (display, 0, 3))
|
||||
return NULL;
|
||||
@ -1450,6 +1570,10 @@ meta_compositor_new (MetaDisplay *display)
|
||||
compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
|
||||
compositor,
|
||||
NULL);
|
||||
if (XQueryExtension (meta_display_get_xdisplay (display),
|
||||
"GLX",
|
||||
&glx_major_opcode, &glx_first_event, &glx_first_error))
|
||||
compositor->glx_opcode = glx_major_opcode;
|
||||
|
||||
return compositor;
|
||||
}
|
||||
|
@ -31,7 +31,8 @@
|
||||
|
||||
ClutterActor *meta_shaped_texture_new (void);
|
||||
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *texture);
|
||||
CoglTexture *texture,
|
||||
gboolean stereo);
|
||||
gboolean meta_shaped_texture_get_unobscured_bounds (MetaShapedTexture *stex,
|
||||
cairo_rectangle_int_t *unobscured_bounds);
|
||||
gboolean meta_shaped_texture_is_obscured (MetaShapedTexture *self);
|
||||
|
@ -36,6 +36,7 @@
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
#include <cogl/cogl-texture-pixmap-x11.h>
|
||||
#include <gdk/gdk.h> /* for gdk_rectangle_intersect() */
|
||||
#include "meta-cullable.h"
|
||||
|
||||
@ -69,8 +70,10 @@ G_DEFINE_TYPE_WITH_CODE (MetaShapedTexture, meta_shaped_texture, CLUTTER_TYPE_AC
|
||||
struct _MetaShapedTexturePrivate
|
||||
{
|
||||
MetaTextureTower *paint_tower;
|
||||
MetaTextureTower *paint_tower_right;
|
||||
|
||||
CoglTexture *texture;
|
||||
CoglTexture *texture_right;
|
||||
CoglTexture *mask_texture;
|
||||
|
||||
cairo_region_t *input_shape_region;
|
||||
@ -84,6 +87,7 @@ struct _MetaShapedTexturePrivate
|
||||
|
||||
guint tex_width, tex_height;
|
||||
|
||||
guint stereo : 1;
|
||||
guint create_mipmaps : 1;
|
||||
};
|
||||
|
||||
@ -112,8 +116,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
|
||||
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
|
||||
|
||||
priv->paint_tower = meta_texture_tower_new ();
|
||||
priv->paint_tower_right = NULL; /* demand create */
|
||||
|
||||
priv->texture = NULL;
|
||||
priv->texture_right = NULL;
|
||||
priv->mask_texture = NULL;
|
||||
priv->create_mipmaps = TRUE;
|
||||
}
|
||||
@ -150,11 +156,10 @@ meta_shaped_texture_dispose (GObject *object)
|
||||
MetaShapedTexture *self = (MetaShapedTexture *) object;
|
||||
MetaShapedTexturePrivate *priv = self->priv;
|
||||
|
||||
if (priv->paint_tower)
|
||||
meta_texture_tower_free (priv->paint_tower);
|
||||
priv->paint_tower = NULL;
|
||||
|
||||
g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
|
||||
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
|
||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||
g_clear_pointer (&priv->texture_right, cogl_object_unref);
|
||||
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||
|
||||
meta_shaped_texture_set_mask_texture (self, NULL);
|
||||
@ -233,49 +238,20 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_paint (ClutterActor *actor)
|
||||
paint_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *paint_tex)
|
||||
{
|
||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||
ClutterActor *actor = CLUTTER_ACTOR (stex);
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
guint tex_width, tex_height;
|
||||
guchar opacity;
|
||||
CoglContext *ctx;
|
||||
CoglFramebuffer *fb;
|
||||
CoglPipeline *pipeline = NULL;
|
||||
CoglTexture *paint_tex;
|
||||
ClutterActorBox alloc;
|
||||
cairo_region_t *blended_region = NULL;
|
||||
CoglPipelineFilter filter;
|
||||
|
||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||
return;
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
|
||||
clutter_actor_realize (CLUTTER_ACTOR (stex));
|
||||
|
||||
/* The GL EXT_texture_from_pixmap extension does allow for it to be
|
||||
* used together with SGIS_generate_mipmap, however this is very
|
||||
* rarely supported. Also, even when it is supported there
|
||||
* are distinct performance implications from:
|
||||
*
|
||||
* - Updating mipmaps that we don't need
|
||||
* - Having to reallocate pixmaps on the server into larger buffers
|
||||
*
|
||||
* So, we just unconditionally use our mipmap emulation code. If we
|
||||
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
|
||||
* see if it was supported (no API currently), and then if and only
|
||||
* if that was the case, set the clutter texture quality to HIGH.
|
||||
* Setting the texture quality to high without SGIS_generate_mipmap
|
||||
* support for TFP textures will result in fallbacks to XGetImage.
|
||||
*/
|
||||
if (priv->create_mipmaps)
|
||||
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
|
||||
else
|
||||
paint_tex = COGL_TEXTURE (priv->texture);
|
||||
|
||||
if (paint_tex == NULL)
|
||||
return;
|
||||
|
||||
tex_width = priv->tex_width;
|
||||
tex_height = priv->tex_height;
|
||||
|
||||
@ -291,8 +267,8 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
if (!clutter_actor_is_in_clone_paint (actor) && meta_actor_is_untransformed (actor, NULL, NULL))
|
||||
filter = COGL_PIPELINE_FILTER_NEAREST;
|
||||
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||
|
||||
opacity = clutter_actor_get_paint_opacity (actor);
|
||||
clutter_actor_get_allocation_box (actor, &alloc);
|
||||
@ -415,6 +391,74 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
||||
cairo_region_destroy (blended_region);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_paint (ClutterActor *actor)
|
||||
{
|
||||
MetaShapedTexture *stex = (MetaShapedTexture *) actor;
|
||||
MetaShapedTexturePrivate *priv = stex->priv;
|
||||
CoglFramebuffer *fb;
|
||||
gboolean stereo;
|
||||
CoglTexture *paint_tex;
|
||||
CoglTexture *paint_tex_right;
|
||||
|
||||
if (priv->clip_region && cairo_region_is_empty (priv->clip_region))
|
||||
return;
|
||||
|
||||
if (!CLUTTER_ACTOR_IS_REALIZED (CLUTTER_ACTOR (stex)))
|
||||
clutter_actor_realize (CLUTTER_ACTOR (stex));
|
||||
|
||||
/* The GL EXT_texture_from_pixmap extension does allow for it to be
|
||||
* used together with SGIS_generate_mipmap, however this is very
|
||||
* rarely supported. Also, even when it is supported there
|
||||
* are distinct performance implications from:
|
||||
*
|
||||
* - Updating mipmaps that we don't need
|
||||
* - Having to reallocate pixmaps on the server into larger buffers
|
||||
*
|
||||
* So, we just unconditionally use our mipmap emulation code. If we
|
||||
* wanted to use SGIS_generate_mipmap, we'd have to query COGL to
|
||||
* see if it was supported (no API currently), and then if and only
|
||||
* if that was the case, set the clutter texture quality to HIGH.
|
||||
* Setting the texture quality to high without SGIS_generate_mipmap
|
||||
* support for TFP textures will result in fallbacks to XGetImage.
|
||||
*/
|
||||
if (priv->create_mipmaps)
|
||||
paint_tex = meta_texture_tower_get_paint_texture (priv->paint_tower);
|
||||
else
|
||||
paint_tex = COGL_TEXTURE (priv->texture);
|
||||
|
||||
fb = cogl_get_draw_framebuffer ();
|
||||
|
||||
stereo = priv->stereo && cogl_framebuffer_get_is_stereo (fb);
|
||||
|
||||
if (stereo)
|
||||
{
|
||||
if (priv->create_mipmaps)
|
||||
paint_tex_right = meta_texture_tower_get_paint_texture (priv->paint_tower_right);
|
||||
else
|
||||
paint_tex_right = COGL_TEXTURE (priv->texture_right);
|
||||
}
|
||||
else
|
||||
paint_tex_right = NULL;
|
||||
|
||||
if (paint_tex != NULL)
|
||||
{
|
||||
if (stereo)
|
||||
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
|
||||
else
|
||||
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
|
||||
|
||||
paint_texture (stex, paint_tex);
|
||||
}
|
||||
|
||||
if (paint_tex_right != NULL)
|
||||
{
|
||||
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
|
||||
paint_texture (stex, paint_tex_right);
|
||||
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_shaped_texture_pick (ClutterActor *actor,
|
||||
const ClutterColor *color)
|
||||
@ -570,6 +614,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
||||
priv->create_mipmaps = create_mipmaps;
|
||||
base_texture = create_mipmaps ? priv->texture : NULL;
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
|
||||
|
||||
if (priv->stereo)
|
||||
{
|
||||
base_texture = create_mipmaps ? priv->texture_right : NULL;
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -668,6 +718,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
return FALSE;
|
||||
|
||||
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
||||
if (priv->stereo)
|
||||
meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
|
||||
|
||||
unobscured_region = effective_unobscured_region (stex);
|
||||
if (unobscured_region)
|
||||
@ -701,7 +753,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
||||
|
||||
static void
|
||||
set_cogl_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *cogl_tex)
|
||||
CoglTexture *cogl_tex,
|
||||
gboolean stereo)
|
||||
{
|
||||
MetaShapedTexturePrivate *priv;
|
||||
guint width, height;
|
||||
@ -712,8 +765,23 @@ set_cogl_texture (MetaShapedTexture *stex,
|
||||
|
||||
if (priv->texture != NULL)
|
||||
cogl_object_unref (priv->texture);
|
||||
if (priv->texture_right != NULL)
|
||||
cogl_object_unref (priv->texture_right);
|
||||
|
||||
priv->stereo = stereo;
|
||||
|
||||
priv->texture = cogl_tex;
|
||||
if (priv->stereo)
|
||||
{
|
||||
priv->texture_right = cogl_texture_pixmap_x11_new_right ((CoglTexturePixmapX11 *)cogl_tex);
|
||||
if (priv->paint_tower_right == NULL)
|
||||
priv->paint_tower_right = meta_texture_tower_new ();
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->texture_right = NULL;
|
||||
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
|
||||
}
|
||||
|
||||
if (cogl_tex != NULL)
|
||||
{
|
||||
@ -743,7 +811,11 @@ set_cogl_texture (MetaShapedTexture *stex,
|
||||
* damage. */
|
||||
|
||||
if (priv->create_mipmaps)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
|
||||
{
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower, cogl_tex);
|
||||
if (priv->stereo)
|
||||
meta_texture_tower_set_base_texture (priv->paint_tower_right, priv->texture_right);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -753,11 +825,12 @@ set_cogl_texture (MetaShapedTexture *stex,
|
||||
*/
|
||||
void
|
||||
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
||||
CoglTexture *texture)
|
||||
CoglTexture *texture,
|
||||
gboolean stereo)
|
||||
{
|
||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||
|
||||
set_cogl_texture (stex, texture);
|
||||
set_cogl_texture (stex, texture, stereo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -58,4 +58,11 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
|
||||
void meta_window_actor_effect_completed (MetaWindowActor *actor,
|
||||
gulong event);
|
||||
|
||||
void meta_window_actor_stereo_notify (MetaWindowActor *actor,
|
||||
gboolean stereo_tree);
|
||||
|
||||
gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
|
||||
|
||||
void meta_window_actor_detach (MetaWindowActor *self);
|
||||
|
||||
#endif /* META_WINDOW_ACTOR_PRIVATE_H */
|
||||
|
@ -94,6 +94,7 @@ struct _MetaWindowActorPrivate
|
||||
|
||||
guint visible : 1;
|
||||
guint argb32 : 1;
|
||||
guint stereo : 1;
|
||||
guint disposed : 1;
|
||||
guint redecorating : 1;
|
||||
|
||||
@ -157,7 +158,6 @@ static gboolean meta_window_actor_get_paint_volume (ClutterActor *actor,
|
||||
ClutterPaintVolume *volume);
|
||||
|
||||
|
||||
static void meta_window_actor_detach (MetaWindowActor *self);
|
||||
static gboolean meta_window_actor_has_shadow (MetaWindowActor *self);
|
||||
|
||||
static void meta_window_actor_handle_updates (MetaWindowActor *self);
|
||||
@ -318,6 +318,9 @@ meta_window_actor_constructed (GObject *object)
|
||||
if (format && format->type == PictTypeDirect && format->direct.alphaMask)
|
||||
priv->argb32 = TRUE;
|
||||
|
||||
priv->stereo = meta_compositor_window_is_stereo (screen, xwindow);
|
||||
meta_compositor_select_stereo_notify (screen, xwindow);
|
||||
|
||||
if (!priv->actor)
|
||||
{
|
||||
priv->actor = meta_shaped_texture_new ();
|
||||
@ -1130,7 +1133,7 @@ meta_window_actor_effect_completed (MetaWindowActor *self,
|
||||
* when the window is unmapped or when we want to update to a new
|
||||
* pixmap for a new size.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
meta_window_actor_detach (MetaWindowActor *self)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
@ -1145,7 +1148,7 @@ meta_window_actor_detach (MetaWindowActor *self)
|
||||
* you are supposed to be able to free a GLXPixmap after freeing the underlying
|
||||
* pixmap, but it certainly doesn't work with current DRI/Mesa
|
||||
*/
|
||||
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL);
|
||||
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), NULL, FALSE);
|
||||
cogl_flush();
|
||||
|
||||
XFreePixmap (xdisplay, priv->back_pixmap);
|
||||
@ -1669,11 +1672,15 @@ check_needs_pixmap (MetaWindowActor *self)
|
||||
meta_shaped_texture_set_create_mipmaps (META_SHAPED_TEXTURE (priv->actor),
|
||||
FALSE);
|
||||
|
||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
|
||||
if (priv->stereo)
|
||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new_left (ctx, priv->back_pixmap, FALSE, NULL));
|
||||
else
|
||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->back_pixmap, FALSE, NULL));
|
||||
|
||||
if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
|
||||
g_warning ("NOTE: Not using GLX TFP!\n");
|
||||
|
||||
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture);
|
||||
meta_shaped_texture_set_texture (META_SHAPED_TEXTURE (priv->actor), texture, priv->stereo);
|
||||
}
|
||||
|
||||
priv->needs_pixmap = FALSE;
|
||||
@ -2350,3 +2357,20 @@ meta_window_actor_set_updates_frozen (MetaWindowActor *self,
|
||||
meta_window_actor_thaw (self);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_window_actor_stereo_notify (MetaWindowActor *self,
|
||||
gboolean stereo_tree)
|
||||
{
|
||||
MetaWindowActorPrivate *priv = self->priv;
|
||||
MetaWindow *window = priv->window;
|
||||
|
||||
priv->stereo = stereo_tree;
|
||||
meta_window_actor_detach (self);
|
||||
}
|
||||
|
||||
gboolean
|
||||
meta_window_actor_is_stereo (MetaWindowActor *self)
|
||||
{
|
||||
return self->priv->stereo;
|
||||
}
|
||||
|
@ -447,6 +447,8 @@ meta_init (void)
|
||||
|
||||
meta_restart_init ();
|
||||
|
||||
meta_stereo_init ();
|
||||
|
||||
/*
|
||||
* Clutter can only be initialized after the UI.
|
||||
*/
|
||||
|
144
src/core/stereo.c
Normal file
144
src/core/stereo.c
Normal file
@ -0,0 +1,144 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* SECTION:stereo
|
||||
* @short_description: Keep track of whether we are a stereo compositor
|
||||
*
|
||||
* With GLX, we need to use a different GL context for stereo and
|
||||
* non-stereo support. Support for multiple GL contexts is unfinished
|
||||
* in Cogl and entirely lacking in Clutter, so it's by far easier
|
||||
* to just restart Mutter when we detect a stereo window.
|
||||
*
|
||||
* A property _MUTTER_ENABLE_STEREO is maintained on the root window
|
||||
* to know whether we should initialize clutter for stereo or not.
|
||||
* When the presence or absence of stereo windows mismatches the
|
||||
* stereo-enabled state for a sufficiently long period of time,
|
||||
* we restart Mutter.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
#include <gio/gunixinputstream.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
||||
#include <meta/main.h>
|
||||
#include "ui.h"
|
||||
#include "util-private.h"
|
||||
#include "display-private.h"
|
||||
#include "stereo.h"
|
||||
|
||||
static guint stereo_switch_id = 0;
|
||||
static gboolean stereo_enabled = FALSE;
|
||||
/* -1 so the first time meta_stereo_set_have_stereo_windows() is called
|
||||
* we avoid the short-circuit and set up a timeout to restart
|
||||
* if necessary */
|
||||
static gboolean stereo_have_windows = (gboolean)-1;
|
||||
static gboolean stereo_restart = FALSE;
|
||||
|
||||
#define STEREO_ENABLE_WAIT 1000
|
||||
#define STEREO_DISABLE_WAIT 5000
|
||||
|
||||
void
|
||||
meta_stereo_init (void)
|
||||
{
|
||||
Display *xdisplay = meta_ui_get_display ();
|
||||
Window root = DefaultRootWindow (xdisplay);
|
||||
Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
|
||||
Atom type;
|
||||
int format;
|
||||
unsigned long n_items, bytes_after;
|
||||
guchar *data;
|
||||
|
||||
XGetWindowProperty (xdisplay, root, atom_enable_stereo,
|
||||
0, 1, False, XA_INTEGER,
|
||||
&type, &format, &n_items, &bytes_after, &data);
|
||||
if (type == XA_INTEGER)
|
||||
{
|
||||
if (format == 32 && n_items == 1 && bytes_after == 0)
|
||||
{
|
||||
stereo_enabled = *(long *)data;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_warning ("Bad value for _MUTTER_ENABLE_STEREO property\n");
|
||||
}
|
||||
|
||||
XFree (data);
|
||||
}
|
||||
else if (type != None)
|
||||
{
|
||||
meta_warning ("Bad type for _MUTTER_ENABLE_STEREO property\n");
|
||||
}
|
||||
|
||||
meta_verbose ("On startup, _MUTTER_ENABLE_STEREO=%s",
|
||||
stereo_enabled ? "yes" : "no");
|
||||
clutter_x11_set_use_stereo_stage (stereo_enabled);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
meta_stereo_switch (gpointer data)
|
||||
{
|
||||
stereo_switch_id = 0;
|
||||
stereo_restart = TRUE;
|
||||
|
||||
meta_restart (stereo_have_windows ?
|
||||
_("Enabling stereo...") :
|
||||
_("Disabling stereo..."));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
meta_stereo_set_have_stereo_windows (gboolean have_windows)
|
||||
{
|
||||
have_windows = have_windows != FALSE;
|
||||
|
||||
if (!stereo_restart && have_windows != stereo_have_windows)
|
||||
{
|
||||
MetaDisplay *display = meta_get_display ();
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
Window root = DefaultRootWindow (xdisplay);
|
||||
Atom atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
|
||||
long value;
|
||||
|
||||
stereo_have_windows = have_windows;
|
||||
|
||||
if (stereo_have_windows)
|
||||
meta_verbose ("Detected stereo windows\n");
|
||||
else
|
||||
meta_verbose ("No stereo windows detected\n");
|
||||
|
||||
value = stereo_have_windows;
|
||||
XChangeProperty (xdisplay, root,
|
||||
atom_enable_stereo, XA_INTEGER, 32,
|
||||
PropModeReplace, (guchar *)&value, 1);
|
||||
|
||||
if (stereo_switch_id != 0)
|
||||
{
|
||||
g_source_remove (stereo_switch_id);
|
||||
stereo_switch_id = 0;
|
||||
}
|
||||
|
||||
if (stereo_have_windows != stereo_enabled)
|
||||
stereo_switch_id = g_timeout_add (stereo_have_windows ? STEREO_ENABLE_WAIT : STEREO_DISABLE_WAIT,
|
||||
meta_stereo_switch, NULL);
|
||||
}
|
||||
}
|
28
src/core/stereo.h
Normal file
28
src/core/stereo.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef META_STEREO_H
|
||||
#define META_STEREO_H
|
||||
|
||||
void meta_stereo_init (void);
|
||||
void meta_stereo_set_have_stereo_windows (gboolean have_windows);
|
||||
gboolean meta_stereo_is_restart (void);
|
||||
void meta_stereo_finish_restart (void);
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user