mirror of
https://github.com/brl/mutter.git
synced 2024-11-24 09:00:42 -05: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
4c765238ae
commit
c15c8facfe
@ -319,6 +319,8 @@ libmutter_@LIBMUTTER_API_VERSION@_la_SOURCES = \
|
|||||||
core/stack.h \
|
core/stack.h \
|
||||||
core/stack-tracker.c \
|
core/stack-tracker.c \
|
||||||
core/stack-tracker.h \
|
core/stack-tracker.h \
|
||||||
|
core/stereo.c \
|
||||||
|
core/stereo.h \
|
||||||
core/util.c \
|
core/util.c \
|
||||||
meta/util.h \
|
meta/util.h \
|
||||||
core/util-private.h \
|
core/util-private.h \
|
||||||
|
@ -21,6 +21,10 @@ struct _MetaCompositor
|
|||||||
gint64 server_time_query_time;
|
gint64 server_time_query_time;
|
||||||
gint64 server_time_offset;
|
gint64 server_time_offset;
|
||||||
|
|
||||||
|
int glx_opcode;
|
||||||
|
guint stereo_tree_ext : 1;
|
||||||
|
guint have_stereo_windows : 1;
|
||||||
|
|
||||||
guint server_time_is_monotonic_time : 1;
|
guint server_time_is_monotonic_time : 1;
|
||||||
guint no_mipmaps : 1;
|
guint no_mipmaps : 1;
|
||||||
|
|
||||||
@ -61,6 +65,11 @@ void meta_end_modal_for_plugin (MetaCompositor *compositor,
|
|||||||
gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
gint64 meta_compositor_monotonic_time_to_server_time (MetaDisplay *display,
|
||||||
gint64 monotonic_time);
|
gint64 monotonic_time);
|
||||||
|
|
||||||
|
gboolean meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||||
|
Window xwindow);
|
||||||
|
void meta_compositor_select_stereo_notify (MetaScreen *screen,
|
||||||
|
Window xwindow);
|
||||||
|
|
||||||
void meta_compositor_flash_window (MetaCompositor *compositor,
|
void meta_compositor_flash_window (MetaCompositor *compositor,
|
||||||
MetaWindow *window);
|
MetaWindow *window);
|
||||||
|
|
||||||
|
@ -70,6 +70,8 @@
|
|||||||
#include "meta-window-group-private.h"
|
#include "meta-window-group-private.h"
|
||||||
#include "window-private.h" /* to check window->hidden */
|
#include "window-private.h" /* to check window->hidden */
|
||||||
#include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
|
#include "display-private.h" /* for meta_display_lookup_x_window() and meta_display_cancel_touch() */
|
||||||
|
#include "stack-tracker.h"
|
||||||
|
#include "stereo.h"
|
||||||
#include "util-private.h"
|
#include "util-private.h"
|
||||||
#include "backends/meta-dnd-private.h"
|
#include "backends/meta-dnd-private.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
@ -487,6 +489,97 @@ redirect_windows (MetaScreen *screen)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
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 extensions_string && strstr (extensions_string, "EXT_stereo_tree") != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <GL/gl.h>
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_compositor_window_is_stereo (MetaScreen *screen,
|
||||||
|
Window xwindow)
|
||||||
|
{
|
||||||
|
MetaCompositor *compositor = get_compositor_for_screen (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 (compositor->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)
|
||||||
|
{
|
||||||
|
MetaCompositor *compositor = get_compositor_for_screen (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 (compositor->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
|
void
|
||||||
meta_compositor_manage (MetaCompositor *compositor)
|
meta_compositor_manage (MetaCompositor *compositor)
|
||||||
{
|
{
|
||||||
@ -495,6 +588,8 @@ meta_compositor_manage (MetaCompositor *compositor)
|
|||||||
MetaScreen *screen = display->screen;
|
MetaScreen *screen = display->screen;
|
||||||
MetaBackend *backend = meta_get_backend ();
|
MetaBackend *backend = meta_get_backend ();
|
||||||
|
|
||||||
|
compositor->stereo_tree_ext = screen_has_stereo_tree_ext (screen);
|
||||||
|
|
||||||
meta_screen_set_cm_selection (display->screen);
|
meta_screen_set_cm_selection (display->screen);
|
||||||
|
|
||||||
compositor->stage = meta_backend_get_stage (backend);
|
compositor->stage = meta_backend_get_stage (backend);
|
||||||
@ -759,6 +854,23 @@ meta_compositor_process_event (MetaCompositor *compositor,
|
|||||||
if (window)
|
if (window)
|
||||||
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
process_damage (compositor, (XDamageNotifyEvent *) event, window);
|
||||||
}
|
}
|
||||||
|
else if (!meta_is_wayland_compositor () &&
|
||||||
|
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);
|
||||||
|
meta_stack_tracker_queue_sync_stack (window->screen->stack_tracker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (compositor->have_x11_sync_object)
|
if (compositor->have_x11_sync_object)
|
||||||
meta_sync_ring_handle_event (event);
|
meta_sync_ring_handle_event (event);
|
||||||
@ -969,6 +1081,7 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
|||||||
GList *stack)
|
GList *stack)
|
||||||
{
|
{
|
||||||
GList *old_stack;
|
GList *old_stack;
|
||||||
|
int stereo_window_count = 0;
|
||||||
|
|
||||||
/* This is painful because hidden windows that we are in the process
|
/* This is painful because hidden windows that we are in the process
|
||||||
* of animating out of existence. They'll be at the bottom of the
|
* of animating out of existence. They'll be at the bottom of the
|
||||||
@ -1044,6 +1157,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
|||||||
* near the front of the other.)
|
* near the front of the other.)
|
||||||
*/
|
*/
|
||||||
compositor->windows = g_list_prepend (compositor->windows, actor);
|
compositor->windows = g_list_prepend (compositor->windows, actor);
|
||||||
|
if (meta_window_actor_is_stereo (actor))
|
||||||
|
stereo_window_count++;
|
||||||
|
|
||||||
stack = g_list_remove (stack, window);
|
stack = g_list_remove (stack, window);
|
||||||
old_stack = g_list_remove (old_stack, actor);
|
old_stack = g_list_remove (old_stack, actor);
|
||||||
@ -1051,6 +1166,8 @@ meta_compositor_sync_stack (MetaCompositor *compositor,
|
|||||||
|
|
||||||
sync_actor_stacking (compositor);
|
sync_actor_stacking (compositor);
|
||||||
|
|
||||||
|
meta_stereo_set_have_stereo_windows (stereo_window_count > 0);
|
||||||
|
|
||||||
if (compositor->top_window_actor)
|
if (compositor->top_window_actor)
|
||||||
g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
|
g_signal_handlers_disconnect_by_func (compositor->top_window_actor,
|
||||||
on_top_window_actor_destroyed,
|
on_top_window_actor_destroyed,
|
||||||
@ -1259,6 +1376,17 @@ meta_compositor_new (MetaDisplay *display)
|
|||||||
meta_post_paint_func,
|
meta_post_paint_func,
|
||||||
compositor,
|
compositor,
|
||||||
NULL);
|
NULL);
|
||||||
|
if (!meta_is_wayland_compositor ())
|
||||||
|
{
|
||||||
|
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||||
|
int glx_major_opcode, glx_first_event, glx_first_error;
|
||||||
|
|
||||||
|
if (XQueryExtension (xdisplay,
|
||||||
|
"GLX",
|
||||||
|
&glx_major_opcode, &glx_first_event, &glx_first_error))
|
||||||
|
compositor->glx_opcode = glx_major_opcode;
|
||||||
|
}
|
||||||
|
|
||||||
return compositor;
|
return compositor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,8 +30,9 @@
|
|||||||
#include <meta/meta-shaped-texture.h>
|
#include <meta/meta-shaped-texture.h>
|
||||||
|
|
||||||
ClutterActor *meta_shaped_texture_new (void);
|
ClutterActor *meta_shaped_texture_new (void);
|
||||||
void meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_textures (MetaShapedTexture *stex,
|
||||||
CoglTexture *texture);
|
CoglTexture *texture,
|
||||||
|
CoglTexture *texture_right);
|
||||||
void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_is_y_inverted (MetaShapedTexture *stex,
|
||||||
gboolean is_y_inverted);
|
gboolean is_y_inverted);
|
||||||
void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
|
void meta_shaped_texture_set_snippet (MetaShapedTexture *stex,
|
||||||
|
@ -89,8 +89,10 @@ typedef struct
|
|||||||
struct _MetaShapedTexturePrivate
|
struct _MetaShapedTexturePrivate
|
||||||
{
|
{
|
||||||
MetaTextureTower *paint_tower;
|
MetaTextureTower *paint_tower;
|
||||||
|
MetaTextureTower *paint_tower_right;
|
||||||
|
|
||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
|
CoglTexture *texture_right;
|
||||||
CoglTexture *mask_texture;
|
CoglTexture *mask_texture;
|
||||||
CoglSnippet *snippet;
|
CoglSnippet *snippet;
|
||||||
|
|
||||||
@ -161,8 +163,10 @@ meta_shaped_texture_init (MetaShapedTexture *self)
|
|||||||
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
|
priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self);
|
||||||
|
|
||||||
priv->paint_tower = meta_texture_tower_new ();
|
priv->paint_tower = meta_texture_tower_new ();
|
||||||
|
priv->paint_tower_right = NULL; /* demand create */
|
||||||
|
|
||||||
priv->texture = NULL;
|
priv->texture = NULL;
|
||||||
|
priv->texture_right = NULL;
|
||||||
priv->mask_texture = NULL;
|
priv->mask_texture = NULL;
|
||||||
priv->create_mipmaps = TRUE;
|
priv->create_mipmaps = TRUE;
|
||||||
priv->is_y_inverted = TRUE;
|
priv->is_y_inverted = TRUE;
|
||||||
@ -229,11 +233,11 @@ meta_shaped_texture_dispose (GObject *object)
|
|||||||
MetaShapedTexture *self = (MetaShapedTexture *) object;
|
MetaShapedTexture *self = (MetaShapedTexture *) object;
|
||||||
MetaShapedTexturePrivate *priv = self->priv;
|
MetaShapedTexturePrivate *priv = self->priv;
|
||||||
|
|
||||||
if (priv->paint_tower)
|
g_clear_pointer (&priv->paint_tower, meta_texture_tower_free);
|
||||||
meta_texture_tower_free (priv->paint_tower);
|
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
|
||||||
priv->paint_tower = NULL;
|
|
||||||
|
|
||||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
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);
|
g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
|
||||||
|
|
||||||
meta_shaped_texture_set_mask_texture (self, NULL);
|
meta_shaped_texture_set_mask_texture (self, NULL);
|
||||||
@ -431,8 +435,9 @@ paint_clipped_rectangle (CoglFramebuffer *fb,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_cogl_texture (MetaShapedTexture *stex,
|
set_cogl_textures (MetaShapedTexture *stex,
|
||||||
CoglTexture *cogl_tex)
|
CoglTexture *cogl_tex,
|
||||||
|
CoglTexture *cogl_tex_right)
|
||||||
{
|
{
|
||||||
MetaShapedTexturePrivate *priv;
|
MetaShapedTexturePrivate *priv;
|
||||||
guint width, height;
|
guint width, height;
|
||||||
@ -443,10 +448,13 @@ set_cogl_texture (MetaShapedTexture *stex,
|
|||||||
|
|
||||||
if (priv->texture)
|
if (priv->texture)
|
||||||
cogl_object_unref (priv->texture);
|
cogl_object_unref (priv->texture);
|
||||||
|
if (priv->texture_right)
|
||||||
|
cogl_object_unref (priv->texture_right);
|
||||||
|
|
||||||
g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
|
g_clear_pointer (&priv->saved_base_surface, cairo_surface_destroy);
|
||||||
|
|
||||||
priv->texture = cogl_tex;
|
priv->texture = cogl_tex;
|
||||||
|
priv->texture_right = cogl_tex_right;
|
||||||
|
|
||||||
if (cogl_tex != NULL)
|
if (cogl_tex != NULL)
|
||||||
{
|
{
|
||||||
@ -460,6 +468,9 @@ set_cogl_texture (MetaShapedTexture *stex,
|
|||||||
height = 0;
|
height = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cogl_tex_right != NULL)
|
||||||
|
cogl_object_ref (cogl_tex_right);
|
||||||
|
|
||||||
if (priv->tex_width != width ||
|
if (priv->tex_width != width ||
|
||||||
priv->tex_height != height)
|
priv->tex_height != height)
|
||||||
{
|
{
|
||||||
@ -475,8 +486,23 @@ set_cogl_texture (MetaShapedTexture *stex,
|
|||||||
* previous buffer. We only queue a redraw in response to surface
|
* previous buffer. We only queue a redraw in response to surface
|
||||||
* damage. */
|
* damage. */
|
||||||
|
|
||||||
|
if (cogl_tex_right != NULL)
|
||||||
|
{
|
||||||
|
if (priv->paint_tower_right == NULL)
|
||||||
|
priv->paint_tower_right = meta_texture_tower_new ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_clear_pointer (&priv->paint_tower_right, meta_texture_tower_free);
|
||||||
|
}
|
||||||
|
|
||||||
if (priv->create_mipmaps)
|
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->paint_tower_right)
|
||||||
|
meta_texture_tower_set_base_texture (priv->paint_tower_right, cogl_tex_right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -485,6 +511,7 @@ do_paint (MetaShapedTexture *stex,
|
|||||||
CoglTexture *paint_tex,
|
CoglTexture *paint_tex,
|
||||||
cairo_region_t *clip_region)
|
cairo_region_t *clip_region)
|
||||||
{
|
{
|
||||||
|
ClutterActor *actor = CLUTTER_ACTOR (stex);
|
||||||
MetaShapedTexturePrivate *priv = stex->priv;
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
guint tex_width, tex_height;
|
guint tex_width, tex_height;
|
||||||
guchar opacity;
|
guchar opacity;
|
||||||
@ -700,7 +727,9 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
|
MetaShapedTexture *stex = META_SHAPED_TEXTURE (actor);
|
||||||
MetaShapedTexturePrivate *priv = stex->priv;
|
MetaShapedTexturePrivate *priv = stex->priv;
|
||||||
CoglTexture *paint_tex = NULL;
|
CoglTexture *paint_tex = NULL;
|
||||||
|
CoglTexture *paint_tex_right = NULL;
|
||||||
CoglFramebuffer *fb;
|
CoglFramebuffer *fb;
|
||||||
|
gboolean stereo;
|
||||||
|
|
||||||
if (!priv->texture)
|
if (!priv->texture)
|
||||||
return;
|
return;
|
||||||
@ -737,7 +766,32 @@ meta_shaped_texture_paint (ClutterActor *actor)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
fb = cogl_get_draw_framebuffer ();
|
fb = cogl_get_draw_framebuffer ();
|
||||||
do_paint (META_SHAPED_TEXTURE (actor), fb, paint_tex, priv->clip_region);
|
|
||||||
|
stereo = priv->texture_right && 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);
|
||||||
|
|
||||||
|
if (!paint_tex_right)
|
||||||
|
paint_tex_right = COGL_TEXTURE (priv->texture_right);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
paint_tex_right = NULL;
|
||||||
|
|
||||||
|
if (stereo)
|
||||||
|
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_LEFT);
|
||||||
|
do_paint (stex, fb, paint_tex, priv->clip_region);
|
||||||
|
if (stereo)
|
||||||
|
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
|
||||||
|
|
||||||
|
if (paint_tex_right != NULL)
|
||||||
|
{
|
||||||
|
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_RIGHT);
|
||||||
|
do_paint (stex, fb, paint_tex_right, priv->clip_region);
|
||||||
|
cogl_framebuffer_set_stereo_mode (fb, COGL_STEREO_BOTH);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -859,6 +913,12 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
|
|||||||
priv->create_mipmaps = create_mipmaps;
|
priv->create_mipmaps = create_mipmaps;
|
||||||
base_texture = create_mipmaps ? priv->texture : NULL;
|
base_texture = create_mipmaps ? priv->texture : NULL;
|
||||||
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
|
meta_texture_tower_set_base_texture (priv->paint_tower, base_texture);
|
||||||
|
|
||||||
|
if (priv->paint_tower_right)
|
||||||
|
{
|
||||||
|
base_texture = create_mipmaps ? priv->texture_right : NULL;
|
||||||
|
meta_texture_tower_set_base_texture (priv->paint_tower_right, base_texture);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -987,6 +1047,8 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|||||||
shrink_backing_region (stex, &clip);
|
shrink_backing_region (stex, &clip);
|
||||||
|
|
||||||
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
|
||||||
|
if (priv->paint_tower_right)
|
||||||
|
meta_texture_tower_update_area (priv->paint_tower_right, x, y, width, height);
|
||||||
|
|
||||||
unobscured_region = effective_unobscured_region (stex);
|
unobscured_region = effective_unobscured_region (stex);
|
||||||
if (unobscured_region)
|
if (unobscured_region)
|
||||||
@ -1019,17 +1081,18 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meta_shaped_texture_set_texture:
|
* meta_shaped_texture_set_textures:
|
||||||
* @stex: The #MetaShapedTexture
|
* @stex: The #MetaShapedTexture
|
||||||
* @pixmap: The #CoglTexture to display
|
* @pixmap: The #CoglTexture to display
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
meta_shaped_texture_set_texture (MetaShapedTexture *stex,
|
meta_shaped_texture_set_textures (MetaShapedTexture *stex,
|
||||||
CoglTexture *texture)
|
CoglTexture *texture,
|
||||||
|
CoglTexture *texture_right)
|
||||||
{
|
{
|
||||||
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
g_return_if_fail (META_IS_SHAPED_TEXTURE (stex));
|
||||||
|
|
||||||
set_cogl_texture (stex, texture);
|
set_cogl_textures (stex, texture, texture_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -187,7 +187,7 @@ meta_surface_actor_wayland_dispose (GObject *object)
|
|||||||
MetaShapedTexture *stex =
|
MetaShapedTexture *stex =
|
||||||
meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||||
|
|
||||||
meta_shaped_texture_set_texture (stex, NULL);
|
meta_shaped_texture_set_textures (stex, NULL, NULL);
|
||||||
if (priv->surface)
|
if (priv->surface)
|
||||||
{
|
{
|
||||||
g_object_remove_weak_pointer (G_OBJECT (priv->surface),
|
g_object_remove_weak_pointer (G_OBJECT (priv->surface),
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include <cogl/winsys/cogl-texture-pixmap-x11.h>
|
#include <cogl/winsys/cogl-texture-pixmap-x11.h>
|
||||||
|
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
|
#include "compositor-private.h"
|
||||||
#include "window-private.h"
|
#include "window-private.h"
|
||||||
#include "meta-shaped-texture-private.h"
|
#include "meta-shaped-texture-private.h"
|
||||||
#include "meta-cullable.h"
|
#include "meta-cullable.h"
|
||||||
@ -43,6 +44,7 @@ struct _MetaSurfaceActorX11Private
|
|||||||
MetaDisplay *display;
|
MetaDisplay *display;
|
||||||
|
|
||||||
CoglTexture *texture;
|
CoglTexture *texture;
|
||||||
|
CoglTexture *texture_right;
|
||||||
Pixmap pixmap;
|
Pixmap pixmap;
|
||||||
Damage damage;
|
Damage damage;
|
||||||
|
|
||||||
@ -58,6 +60,8 @@ struct _MetaSurfaceActorX11Private
|
|||||||
guint size_changed : 1;
|
guint size_changed : 1;
|
||||||
|
|
||||||
guint unredirected : 1;
|
guint unredirected : 1;
|
||||||
|
|
||||||
|
guint stereo : 1;
|
||||||
};
|
};
|
||||||
typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
|
typedef struct _MetaSurfaceActorX11Private MetaSurfaceActorX11Private;
|
||||||
|
|
||||||
@ -94,7 +98,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
|
|||||||
* you are supposed to be able to free a GLXPixmap after freeing the underlying
|
* 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
|
* pixmap, but it certainly doesn't work with current DRI/Mesa
|
||||||
*/
|
*/
|
||||||
meta_shaped_texture_set_texture (stex, NULL);
|
meta_shaped_texture_set_textures (stex, NULL, NULL);
|
||||||
cogl_flush ();
|
cogl_flush ();
|
||||||
|
|
||||||
meta_error_trap_push (display);
|
meta_error_trap_push (display);
|
||||||
@ -103,6 +107,7 @@ detach_pixmap (MetaSurfaceActorX11 *self)
|
|||||||
meta_error_trap_pop (display);
|
meta_error_trap_pop (display);
|
||||||
|
|
||||||
g_clear_pointer (&priv->texture, cogl_object_unref);
|
g_clear_pointer (&priv->texture, cogl_object_unref);
|
||||||
|
g_clear_pointer (&priv->texture_right, cogl_object_unref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -114,23 +119,35 @@ set_pixmap (MetaSurfaceActorX11 *self,
|
|||||||
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
CoglContext *ctx = clutter_backend_get_cogl_context (clutter_get_default_backend ());
|
||||||
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
MetaShapedTexture *stex = meta_surface_actor_get_texture (META_SURFACE_ACTOR (self));
|
||||||
CoglError *error = NULL;
|
CoglError *error = NULL;
|
||||||
CoglTexture *texture;
|
CoglTexturePixmapX11 *texture;
|
||||||
|
CoglTexturePixmapX11 *texture_right;
|
||||||
|
|
||||||
g_assert (priv->pixmap == None);
|
g_assert (priv->pixmap == None);
|
||||||
priv->pixmap = pixmap;
|
priv->pixmap = pixmap;
|
||||||
|
|
||||||
texture = COGL_TEXTURE (cogl_texture_pixmap_x11_new (ctx, priv->pixmap, FALSE, &error));
|
if (priv->stereo)
|
||||||
|
texture = cogl_texture_pixmap_x11_new_left (ctx, pixmap, FALSE, &error);
|
||||||
|
else
|
||||||
|
texture = cogl_texture_pixmap_x11_new (ctx, pixmap, FALSE, &error);
|
||||||
|
|
||||||
|
if (priv->stereo)
|
||||||
|
texture_right = cogl_texture_pixmap_x11_new_right (texture);
|
||||||
|
else
|
||||||
|
texture_right = NULL;
|
||||||
|
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to allocate stex texture: %s", error->message);
|
g_warning ("Failed to allocate stex texture: %s", error->message);
|
||||||
cogl_error_free (error);
|
cogl_error_free (error);
|
||||||
}
|
}
|
||||||
else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (COGL_TEXTURE_PIXMAP_X11 (texture))))
|
else if (G_UNLIKELY (!cogl_texture_pixmap_x11_is_using_tfp_extension (texture)))
|
||||||
g_warning ("NOTE: Not using GLX TFP!\n");
|
g_warning ("NOTE: Not using GLX TFP!\n");
|
||||||
|
|
||||||
priv->texture = texture;
|
priv->texture = COGL_TEXTURE (texture);
|
||||||
meta_shaped_texture_set_texture (stex, texture);
|
if (priv->stereo)
|
||||||
|
priv->texture_right = COGL_TEXTURE (texture_right);
|
||||||
|
|
||||||
|
meta_shaped_texture_set_textures (stex, COGL_TEXTURE (texture), COGL_TEXTURE (texture_right));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -433,8 +450,8 @@ reset_texture (MetaSurfaceActorX11 *self)
|
|||||||
/* Setting the texture to NULL will cause all the FBO's cached by the
|
/* Setting the texture to NULL will cause all the FBO's cached by the
|
||||||
* shaped texture's MetaTextureTower to be discarded and recreated.
|
* shaped texture's MetaTextureTower to be discarded and recreated.
|
||||||
*/
|
*/
|
||||||
meta_shaped_texture_set_texture (stex, NULL);
|
meta_shaped_texture_set_textures (stex, NULL, NULL);
|
||||||
meta_shaped_texture_set_texture (stex, priv->texture);
|
meta_shaped_texture_set_textures (stex, priv->texture, priv->texture_right);
|
||||||
}
|
}
|
||||||
|
|
||||||
MetaSurfaceActor *
|
MetaSurfaceActor *
|
||||||
@ -443,12 +460,17 @@ meta_surface_actor_x11_new (MetaWindow *window)
|
|||||||
MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
|
MetaSurfaceActorX11 *self = g_object_new (META_TYPE_SURFACE_ACTOR_X11, NULL);
|
||||||
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||||
MetaDisplay *display = meta_window_get_display (window);
|
MetaDisplay *display = meta_window_get_display (window);
|
||||||
|
Window xwindow;
|
||||||
|
|
||||||
g_assert (!meta_is_wayland_compositor ());
|
g_assert (!meta_is_wayland_compositor ());
|
||||||
|
|
||||||
priv->window = window;
|
priv->window = window;
|
||||||
priv->display = display;
|
priv->display = display;
|
||||||
|
|
||||||
|
xwindow = meta_window_x11_get_toplevel_xwindow (window);
|
||||||
|
priv->stereo = meta_compositor_window_is_stereo (display->screen, xwindow);
|
||||||
|
meta_compositor_select_stereo_notify (display->screen, xwindow);
|
||||||
|
|
||||||
g_signal_connect_object (priv->display, "gl-video-memory-purged",
|
g_signal_connect_object (priv->display, "gl-video-memory-purged",
|
||||||
G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED);
|
G_CALLBACK (reset_texture), self, G_CONNECT_SWAPPED);
|
||||||
|
|
||||||
@ -479,3 +501,21 @@ meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
|
|||||||
priv->last_height = height;
|
priv->last_height = height;
|
||||||
meta_shaped_texture_set_fallback_size (stex, width, height);
|
meta_shaped_texture_set_fallback_size (stex, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
|
||||||
|
gboolean stereo_tree)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||||
|
|
||||||
|
priv->stereo = stereo_tree != FALSE;
|
||||||
|
detach_pixmap (self);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self)
|
||||||
|
{
|
||||||
|
MetaSurfaceActorX11Private *priv = meta_surface_actor_x11_get_instance_private (self);
|
||||||
|
|
||||||
|
return priv->stereo;
|
||||||
|
}
|
||||||
|
@ -64,6 +64,11 @@ MetaSurfaceActor * meta_surface_actor_x11_new (MetaWindow *window);
|
|||||||
void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
|
void meta_surface_actor_x11_set_size (MetaSurfaceActorX11 *self,
|
||||||
int width, int height);
|
int width, int height);
|
||||||
|
|
||||||
|
void meta_surface_actor_x11_stereo_notify (MetaSurfaceActorX11 *self,
|
||||||
|
gboolean stereo_tree);
|
||||||
|
|
||||||
|
gboolean meta_surface_actor_x11_is_stereo (MetaSurfaceActorX11 *self);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __META_SURFACE_ACTOR_X11_H__ */
|
#endif /* __META_SURFACE_ACTOR_X11_H__ */
|
||||||
|
@ -60,4 +60,9 @@ MetaSurfaceActor *meta_window_actor_get_surface (MetaWindowActor *self);
|
|||||||
void meta_window_actor_update_surface (MetaWindowActor *self);
|
void meta_window_actor_update_surface (MetaWindowActor *self);
|
||||||
MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
|
MetaWindowActor *meta_window_actor_from_window (MetaWindow *window);
|
||||||
|
|
||||||
|
void meta_window_actor_stereo_notify (MetaWindowActor *actor,
|
||||||
|
gboolean stereo_tree);
|
||||||
|
|
||||||
|
gboolean meta_window_actor_is_stereo (MetaWindowActor *actor);
|
||||||
|
|
||||||
#endif /* META_WINDOW_ACTOR_PRIVATE_H */
|
#endif /* META_WINDOW_ACTOR_PRIVATE_H */
|
||||||
|
@ -2321,3 +2321,25 @@ screen_cast_window_iface_init (MetaScreenCastWindowInterface *iface)
|
|||||||
iface->transform_relative_position = meta_window_actor_transform_relative_position;
|
iface->transform_relative_position = meta_window_actor_transform_relative_position;
|
||||||
iface->capture_into = meta_window_actor_capture_into;
|
iface->capture_into = meta_window_actor_capture_into;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_actor_stereo_notify (MetaWindowActor *self,
|
||||||
|
gboolean stereo_tree)
|
||||||
|
{
|
||||||
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
|
||||||
|
if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
|
||||||
|
meta_surface_actor_x11_stereo_notify (META_SURFACE_ACTOR_X11 (priv->surface),
|
||||||
|
stereo_tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_window_actor_is_stereo (MetaWindowActor *self)
|
||||||
|
{
|
||||||
|
MetaWindowActorPrivate *priv = self->priv;
|
||||||
|
|
||||||
|
if (META_IS_SURFACE_ACTOR_X11 (priv->surface))
|
||||||
|
return meta_surface_actor_x11_is_stereo (META_SURFACE_ACTOR_X11 (priv->surface));
|
||||||
|
else
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include <meta/main.h>
|
#include <meta/main.h>
|
||||||
#include "util-private.h"
|
#include "util-private.h"
|
||||||
#include "display-private.h"
|
#include "display-private.h"
|
||||||
|
#include "stereo.h"
|
||||||
#include <meta/errors.h>
|
#include <meta/errors.h>
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include <meta/prefs.h>
|
#include <meta/prefs.h>
|
||||||
@ -582,6 +583,9 @@ meta_init (void)
|
|||||||
|
|
||||||
meta_init_backend (backend_gtype);
|
meta_init_backend (backend_gtype);
|
||||||
|
|
||||||
|
if (!meta_is_wayland_compositor ())
|
||||||
|
meta_stereo_init ();
|
||||||
|
|
||||||
meta_clutter_init ();
|
meta_clutter_init ();
|
||||||
|
|
||||||
#ifdef HAVE_WAYLAND
|
#ifdef HAVE_WAYLAND
|
||||||
|
153
src/core/stereo.c
Normal file
153
src/core/stereo.c
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/* -*- 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <meta/util.h>
|
||||||
|
#include "display-private.h"
|
||||||
|
#include "stereo.h"
|
||||||
|
#include "util-private.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;
|
||||||
|
Window root;
|
||||||
|
Atom atom_enable_stereo;
|
||||||
|
Atom type;
|
||||||
|
int format;
|
||||||
|
unsigned long n_items, bytes_after;
|
||||||
|
guchar *data;
|
||||||
|
|
||||||
|
xdisplay = XOpenDisplay (NULL);
|
||||||
|
if (xdisplay == NULL)
|
||||||
|
meta_fatal ("Unable to open X display %s\n", XDisplayName (NULL));
|
||||||
|
|
||||||
|
root = DefaultRootWindow (xdisplay);
|
||||||
|
atom_enable_stereo = XInternAtom (xdisplay, "_MUTTER_ENABLE_STEREO", False);
|
||||||
|
|
||||||
|
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);
|
||||||
|
XCloseDisplay (xdisplay);
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
@ -676,7 +676,7 @@ meta_wayland_surface_apply_pending_state (MetaWaylandSurface *surface,
|
|||||||
snippet = meta_wayland_buffer_create_snippet (pending->buffer);
|
snippet = meta_wayland_buffer_create_snippet (pending->buffer);
|
||||||
is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
|
is_y_inverted = meta_wayland_buffer_is_y_inverted (pending->buffer);
|
||||||
|
|
||||||
meta_shaped_texture_set_texture (stex, texture);
|
meta_shaped_texture_set_textures (stex, texture, NULL);
|
||||||
meta_shaped_texture_set_snippet (stex, snippet);
|
meta_shaped_texture_set_snippet (stex, snippet);
|
||||||
meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
|
meta_shaped_texture_set_is_y_inverted (stex, is_y_inverted);
|
||||||
g_clear_pointer (&snippet, cogl_object_unref);
|
g_clear_pointer (&snippet, cogl_object_unref);
|
||||||
|
Loading…
Reference in New Issue
Block a user