Compare commits

..

19 Commits

Author SHA1 Message Date
Cédric Valmary
049b277ca5 Update Occitan translation 2016-10-11 17:53:17 +00:00
Pedro Albuquerque
9f23f466de Updated Portuguese translation 2015-11-24 08:06:28 +00:00
Rui Matos
461f193c00 compositor: Handle fences in the frontend X connection
Since mutter has two X connections and does damage handling on the
frontend while fence triggering is done on the backend, we have a race
between XDamageSubtract() and XSyncFenceTrigger() causing missed
redraws in the GL_EXT_X11_sync_object path.

If the fence trigger gets processed first by the server, any client
drawing that happens between that and the damage subtract being
processed and is completely contained in the last damage event box
that mutter got, won't be included in the current frame nor will it
cause a new damage event.

A simple fix for this would be XSync()ing on the frontend connection
after doing all the damage subtracts but that would add a round trip
on every frame again which defeats the asynchronous design of X
fences.

Instead, if we move fence handling to the frontend we automatically
get the right ordering between damage subtracts and fence triggers.

https://bugzilla.gnome.org/show_bug.cgi?id=728464
2015-08-13 14:50:22 +02:00
Ting-Wei Lan
9b1d436854 build: Fix return value in meta-sync-ring.c
https://bugzilla.gnome.org/show_bug.cgi?id=753380
2015-08-13 14:50:22 +02:00
Aaron Plattner
662d50460b compositor: Fix GL_EXT_x11_sync_object race condition
The compositor maintains a ring of shared fences with the X server in order to
properly synchronize rendering between the X server and the compositor's GPU
channel.  When all of the fences have been used, the compositor needs to reset
one so that it can be reused.  It does this by first waiting on the CPU for the
fence to become triggered, and then sending a request to the X server to reset
the fence.

If the compositor's GPU channel is busy processing other work (e.g. the desktop
switcher animation), then the X server may process the reset request before the
GPU has consumed the fence.  This causes the GPU channel to hang.

Fix the problem by having the compositor's GPU channel trigger its own fence
after waiting for the X server's fence.  Wait for that fence on the CPU before
sending the reset request to the X server.  This ensures that the GPU has
consumed the X11 fence before the server resets it.

Signed-off-by: Aaron Plattner <aplattner@nvidia.com>

https://bugzilla.gnome.org/show_bug.cgi?id=728464
2015-08-13 14:50:22 +02:00
Rui Matos
47cb21b36c compositor: Add support for GL_EXT_x11_sync_object
If GL advertises this extension we'll use it to synchronize X with GL
rendering instead of relying on the XSync() behavior with open source
drivers.

Some driver bugs were uncovered while working on this so if we have
had to reboot the ring a few times, something is probably wrong and
we're likely to just make things worse by continuing to try.  Let's
err on the side of caution, disable ourselves and fallback to the
XSync() path in the compositor.

https://bugzilla.gnome.org/show_bug.cgi?id=728464
2015-08-13 14:50:22 +02:00
Calvin Walton
8b75b41c4d Include libXrender as a dependency, link it to libmutter
Mutter uses a function from libXrender (XRenderFindStandardFormat in
src/x11/iconcache.c), but doesn't link to libXrender. This causes
link issues on systems using the gold linker, particularly with
-Wl,--as-needed.

Since mutter is using a function from libXrender, adding 'xrender'
as a dependency seems appropriate, and fixes the issue.

https://bugzilla.gnome.org/show_bug.cgi?id=746692
2015-03-28 13:44:09 +01:00
Jasper St. Pierre
c45c39bff3 launcher: Fix a crash that happens when TakeDevice has an error 2015-03-27 23:46:00 +01:00
Florian Müllner
8b80a70efc Bump version to 3.14.4
Update NEWS.
2015-03-23 18:41:32 +01:00
Florian Müllner
63ad42e1f6 window-x11: Fix height computation of shaded windows
Since commit 6e06648f7, we start out with the invisible frame parts
only, and then add the unconstrained rect's height (which consists of
the visible parts of both frame and client window) *unless* the window
is shaded. While we indeed don't want to add the client height in that
case, we need to explicitly include the visible frame parts now.

https://bugzilla.gnome.org/show_bug.cgi?id=746145
2015-03-23 18:40:19 +01:00
Rui Matos
6b3be51ca8 meta-background: Add a function to refresh all background instances
We need to reload the FBOs under some circumstances, this adds a way
to easily do so.

https://bugzilla.gnome.org/show_bug.cgi?id=739178
2015-03-20 17:11:30 +01:00
Samir Ribic
46d57bf0ac Updated Bosnian translation 2015-03-14 23:06:25 +00:00
Alban Browaeys
8dd7102909 MetaBackgroundActor: glsl: do not mix int and float.
Implicit conversion from int to float is not supported by
GLSL ES.

Fixes:
(gnome-shell:8954): Cogl-WARNING **: Shader compilation failed:
1:2: P0004: High precision not supported, instead compiling high precision as medium precision
4:17: S0001: Type mismatch in arithmetic operation between 'int' and 'float'
when one trigger the overview mode on Mali 400 r1p1 GPU.

https://bugzilla.gnome.org/show_bug.cgi?id=745442
2015-03-03 22:10:43 +01:00
Chris Wilson
7a57e59fcc compositor: Update composite overlay window before unredirecting
The current ordering updates the clip shape of the composite overlay
window after unredirecting the target window. This has the effect of
forcing X to clear the target window and sending an expose to the
application to repaint - causing an unsightly flash. If we update the
shape first, then unredirect, X restores the background of the root
window (sending no expose events as no one is interested) and the
background is typically NONE for the root window. Then the unredirect
paints the contents of the composite backing pixmap over top without
requiring a round trip and waiting for the client to repaint - thus no
flashing.

Fixes regression from

commit d6282716b2
Author: Jasper St. Pierre <jstpierre@mecheye.net>
Date:   Fri Dec 6 17:10:44 2013 -0500

    compositor: Simplify the unredirected window management code

Cc: Jasper St. Pierre <jstpierre@mecheye.net>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

https://bugzilla.gnome.org/show_bug.cgi?id=743858
2015-02-02 15:43:01 +01:00
Rui Matos
6772758a64 display: Fix moving grab op check
We were regarding META_GRAB_OP_KEYBOARD_RESIZING_UNKNOWN as a move.

https://bugzilla.gnome.org/show_bug.cgi?id=743254
2015-01-20 17:52:54 +01:00
Florian Müllner
08ba9c689e place: Fix workspace check when collecting relevant windows
When looking for space to place a new window, other non-minimized
windows on the same workspace should be taken into account. However
the current check does not work correctly when the placed window is
located on all workspaces, so handle that case explicitly.

https://bugzilla.gnome.org/show_bug.cgi?id=743217
2015-01-20 00:43:05 +01:00
Muhammet Kara
bdb2dac244 Updated Turkish translation 2015-01-03 08:30:58 +00:00
Florian Müllner
dd9b1ce440 Bump GLib requirement
We have depended on GTask for a while now, bump the GLib requirement
to a new enough version to include that.

https://bugzilla.gnome.org/show_bug.cgi?id=698995
2014-12-29 17:53:52 +01:00
Matej Urbančič
878f0e6443 Updated Slovenian translation 2014-12-26 19:37:02 +01:00
19 changed files with 4443 additions and 8494 deletions

14
NEWS
View File

@@ -1,3 +1,17 @@
3.14.4
======
* Fix flash on unredirection [Chris; #743858]
* Fix incompatibility with GLES2 GLSL [Alban; #745442]
* Add function to refresh all background instances [Rui; #739178]
* Fix geometry of shaded windows [Florian; #746145]
* Misc. bug fixes [Florian, Rui; #698995, #743217, #743254]
Contributors:
Alban Browaeys, Rui Matos, Florian Müllner, Chris Wilson
Translations:
Matej Urbančič [sl], Muhammet Kara [tr], Samir Ribic [bs]
3.14.3
======
* Fix crash when trying to unredirect a destroyed window [Florian; #740133]

View File

@@ -2,7 +2,7 @@ AC_PREREQ(2.62)
m4_define([mutter_major_version], [3])
m4_define([mutter_minor_version], [14])
m4_define([mutter_micro_version], [3])
m4_define([mutter_micro_version], [4])
m4_define([mutter_version],
[mutter_major_version.mutter_minor_version.mutter_micro_version])
@@ -72,7 +72,7 @@ CLUTTER_PACKAGE=clutter-1.0
MUTTER_PC_MODULES="
gtk+-3.0 >= 3.9.11
gio-unix-2.0 >= 2.25.10
gio-unix-2.0 >= 2.35.1
pango >= 1.2.0
cairo >= 1.10.0
gsettings-desktop-schemas >= 3.7.3
@@ -90,6 +90,7 @@ MUTTER_PC_MODULES="
xkeyboard-config
xkbcommon >= 0.4.3
xkbcommon-x11
xrender
x11-xcb
xcb-randr
"
@@ -314,6 +315,11 @@ fi
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
AC_CHECK_DECL([GL_EXT_x11_sync_object],
[],
[AC_MSG_ERROR([GL_EXT_x11_sync_object definition not found, please update your GL headers])],
[#include <GL/glx.h>])
#### Warnings (last since -Werror can disturb other tests)
# Stay command-line compatible with the gnome-common configure option. Here

4046
po/bs.po

File diff suppressed because it is too large Load Diff

3564
po/oc.po

File diff suppressed because it is too large Load Diff

1430
po/pt.po

File diff suppressed because it is too large Load Diff

1214
po/sl.po

File diff suppressed because it is too large Load Diff

1940
po/tr.po

File diff suppressed because it is too large Load Diff

View File

@@ -126,6 +126,8 @@ libmutter_la_SOURCES = \
compositor/meta-surface-actor.h \
compositor/meta-surface-actor-x11.c \
compositor/meta-surface-actor-x11.h \
compositor/meta-sync-ring.c \
compositor/meta-sync-ring.h \
compositor/meta-texture-rectangle.c \
compositor/meta-texture-rectangle.h \
compositor/meta-texture-tower.c \

View File

@@ -130,8 +130,8 @@ take_device (Login1Session *session_proxy,
{
gboolean ret = FALSE;
GVariant *fd_variant = NULL;
GUnixFDList *fd_list = NULL;
int fd = -1;
GUnixFDList *fd_list;
if (!login1_session_call_take_device_sync (session_proxy,
dev_major,

View File

@@ -15,7 +15,8 @@ struct _MetaCompositor
{
MetaDisplay *display;
guint repaint_func_id;
guint pre_paint_func_id;
guint post_paint_func_id;
gint64 server_time_query_time;
gint64 server_time_offset;
@@ -40,6 +41,7 @@ struct _MetaCompositor
MetaPluginManager *plugin_mgr;
gboolean frame_has_updated_xsurfaces;
gboolean have_x11_sync_object;
};
/* Wait 2ms after vblank before starting to draw next frame */

View File

@@ -79,6 +79,7 @@
#include "frame.h"
#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include "meta-sync-ring.h"
#include "backends/x11/meta-backend-x11.h"
@@ -125,7 +126,11 @@ meta_switch_workspace_completed (MetaCompositor *compositor)
void
meta_compositor_destroy (MetaCompositor *compositor)
{
clutter_threads_remove_repaint_func (compositor->repaint_func_id);
clutter_threads_remove_repaint_func (compositor->pre_paint_func_id);
clutter_threads_remove_repaint_func (compositor->post_paint_func_id);
if (compositor->have_x11_sync_object)
meta_sync_ring_destroy ();
}
static void
@@ -468,13 +473,11 @@ meta_compositor_manage (MetaCompositor *compositor)
MetaDisplay *display = compositor->display;
Display *xdisplay = display->xdisplay;
MetaScreen *screen = display->screen;
MetaBackend *backend = meta_get_backend ();
meta_screen_set_cm_selection (display->screen);
{
MetaBackend *backend = meta_get_backend ();
compositor->stage = meta_backend_get_stage (backend);
}
compositor->stage = meta_backend_get_stage (backend);
/* We use connect_after() here to accomodate code in GNOME Shell that,
* when benchmarking drawing performance, connects to ::after-paint
@@ -510,7 +513,7 @@ meta_compositor_manage (MetaCompositor *compositor)
compositor->output = screen->composite_overlay_window;
xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (meta_get_backend ()));
xwin = meta_backend_x11_get_xwindow (META_BACKEND_X11 (backend));
XReparentWindow (xdisplay, xwin, compositor->output, 0, 0);
@@ -530,6 +533,8 @@ meta_compositor_manage (MetaCompositor *compositor)
* contents until we show the stage.
*/
XMapWindow (xdisplay, compositor->output);
compositor->have_x11_sync_object = meta_sync_ring_init (xdisplay);
}
redirect_windows (display->screen);
@@ -614,6 +619,7 @@ set_unredirected_window (MetaCompositor *compositor,
meta_window_actor_set_unredirected (window_actor, FALSE);
}
meta_shape_cow_for_window (compositor, window);
compositor->unredirected_window = window;
if (compositor->unredirected_window != NULL)
@@ -621,8 +627,6 @@ set_unredirected_window (MetaCompositor *compositor,
MetaWindowActor *window_actor = META_WINDOW_ACTOR (meta_window_get_compositor_private (compositor->unredirected_window));
meta_window_actor_set_unredirected (window_actor, TRUE);
}
meta_shape_cow_for_window (compositor, compositor->unredirected_window);
}
void
@@ -732,6 +736,9 @@ meta_compositor_process_event (MetaCompositor *compositor,
process_damage (compositor, (XDamageNotifyEvent *) event, window);
}
if (compositor->have_x11_sync_object)
meta_sync_ring_handle_event (event);
/* Clutter needs to know about MapNotify events otherwise it will
think the stage is invisible */
if (!meta_is_wayland_compositor () && event->type == MapNotify)
@@ -1045,11 +1052,12 @@ frame_callback (CoglOnscreen *onscreen,
}
}
static void
pre_paint_windows (MetaCompositor *compositor)
static gboolean
meta_pre_paint_func (gpointer data)
{
GList *l;
MetaWindowActor *top_window;
MetaCompositor *compositor = data;
if (compositor->onscreen == NULL)
{
@@ -1061,7 +1069,7 @@ pre_paint_windows (MetaCompositor *compositor)
}
if (compositor->windows == NULL)
return;
return TRUE;
top_window = g_list_last (compositor->windows)->data;
@@ -1078,10 +1086,12 @@ pre_paint_windows (MetaCompositor *compositor)
{
/* We need to make sure that any X drawing that happens before
* the XDamageSubtract() for each window above is visible to
* subsequent GL rendering; the only standardized way to do this
* is EXT_x11_sync_object, which isn't yet widely available. For
* now, we count on details of Xorg and the open source drivers,
* and hope for the best otherwise.
* subsequent GL rendering; the standardized way to do this is
* GL_EXT_X11_sync_object. Since this isn't implemented yet in
* mesa, we also have a path that relies on the implementation
* of the open source drivers.
*
* Anything else, we just hope for the best.
*
* Xorg and open source driver specifics:
*
@@ -1096,17 +1106,28 @@ pre_paint_windows (MetaCompositor *compositor)
* round trip request at this point is sufficient to flush the
* GLX buffers.
*/
XSync (compositor->display->xdisplay, False);
compositor->frame_has_updated_xsurfaces = FALSE;
if (compositor->have_x11_sync_object)
compositor->have_x11_sync_object = meta_sync_ring_insert_wait ();
else
XSync (compositor->display->xdisplay, False);
}
return TRUE;
}
static gboolean
meta_repaint_func (gpointer data)
meta_post_paint_func (gpointer data)
{
MetaCompositor *compositor = data;
pre_paint_windows (compositor);
if (compositor->frame_has_updated_xsurfaces)
{
if (compositor->have_x11_sync_object)
compositor->have_x11_sync_object = meta_sync_ring_after_frame ();
compositor->frame_has_updated_xsurfaces = FALSE;
}
return TRUE;
}
@@ -1141,10 +1162,16 @@ meta_compositor_new (MetaDisplay *display)
G_CALLBACK (on_shadow_factory_changed),
compositor);
compositor->repaint_func_id = clutter_threads_add_repaint_func (meta_repaint_func,
compositor,
NULL);
compositor->pre_paint_func_id =
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_PRE_PAINT,
meta_pre_paint_func,
compositor,
NULL);
compositor->post_paint_func_id =
clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
meta_post_paint_func,
compositor,
NULL);
return compositor;
}

View File

@@ -115,7 +115,7 @@ typedef enum {
#define FRAGMENT_SHADER_CODE \
"float t = 2.0 * length(position);\n" \
"t = min(t, 1.0);\n" \
"float pixel_brightness = 1 - t * vignette_sharpness;\n" \
"float pixel_brightness = 1.0 - t * vignette_sharpness;\n" \
"cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \
typedef struct _MetaBackgroundLayer MetaBackgroundLayer;

View File

@@ -71,6 +71,8 @@ enum
G_DEFINE_TYPE (MetaBackground, meta_background, G_TYPE_OBJECT)
static GSList *all_backgrounds = NULL;
static void
free_fbos (MetaBackground *self)
{
@@ -291,6 +293,8 @@ meta_background_dispose (GObject *object)
static void
meta_background_finalize (GObject *object)
{
all_backgrounds = g_slist_remove (all_backgrounds, object);
G_OBJECT_CLASS (meta_background_parent_class)->finalize (object);
}
@@ -333,6 +337,7 @@ meta_background_init (MetaBackground *self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
META_TYPE_BACKGROUND,
MetaBackgroundPrivate);
all_backgrounds = g_slist_prepend (all_backgrounds, self);
}
static void
@@ -899,3 +904,12 @@ meta_background_set_blend (MetaBackground *self,
free_wallpaper_texture (self);
mark_changed (self);
}
void
meta_background_refresh_all (void)
{
GSList *l;
for (l = all_backgrounds; l; l = l->next)
mark_changed (l->data);
}

View File

@@ -0,0 +1,592 @@
/*
* This is based on an original C++ implementation for compiz that
* carries the following copyright notice:
*
*
* Copyright © 2011 NVIDIA Corporation
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of NVIDIA
* Corporation not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. NVIDIA Corporation makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* NVIDIA CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
* AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
* SOFTWARE.
*
* Authors: James Jones <jajones@nvidia.com>
*/
#include <string.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include <X11/extensions/sync.h>
#include <cogl/cogl.h>
#include <clutter/clutter.h>
#include <meta/util.h>
#include "meta-sync-ring.h"
/* Theory of operation:
*
* We use a ring of NUM_SYNCS fence objects. On each frame we advance
* to the next fence in the ring. For each fence we do:
*
* 1. fence is XSyncTriggerFence()'d and glWaitSync()'d
* 2. NUM_SYNCS / 2 frames later, fence should be triggered
* 3. fence is XSyncResetFence()'d
* 4. NUM_SYNCS / 2 frames later, fence should be reset
* 5. go back to 1 and re-use fence
*
* glClientWaitSync() and XAlarms are used in steps 2 and 4,
* respectively, to double-check the expectections.
*/
#define NUM_SYNCS 10
#define MAX_SYNC_WAIT_TIME (1 * 1000 * 1000 * 1000) /* one sec */
#define MAX_REBOOT_ATTEMPTS 2
typedef enum
{
META_SYNC_STATE_READY,
META_SYNC_STATE_WAITING,
META_SYNC_STATE_DONE,
META_SYNC_STATE_RESET_PENDING,
} MetaSyncState;
typedef struct
{
Display *xdisplay;
XSyncFence xfence;
GLsync gl_x11_sync;
GLsync gpu_fence;
XSyncCounter xcounter;
XSyncAlarm xalarm;
XSyncValue next_counter_value;
MetaSyncState state;
} MetaSync;
typedef struct
{
Display *xdisplay;
int xsync_event_base;
int xsync_error_base;
GHashTable *alarm_to_sync;
MetaSync *syncs_array[NUM_SYNCS];
guint current_sync_idx;
MetaSync *current_sync;
guint warmup_syncs;
guint reboots;
} MetaSyncRing;
static MetaSyncRing meta_sync_ring = { 0 };
static XSyncValue SYNC_VALUE_ZERO;
static XSyncValue SYNC_VALUE_ONE;
static const char* (*meta_gl_get_string) (GLenum name);
static void (*meta_gl_get_integerv) (GLenum pname,
GLint *params);
static const char* (*meta_gl_get_stringi) (GLenum name,
GLuint index);
static void (*meta_gl_delete_sync) (GLsync sync);
static GLenum (*meta_gl_client_wait_sync) (GLsync sync,
GLbitfield flags,
GLuint64 timeout);
static void (*meta_gl_wait_sync) (GLsync sync,
GLbitfield flags,
GLuint64 timeout);
static GLsync (*meta_gl_import_sync) (GLenum external_sync_type,
GLintptr external_sync,
GLbitfield flags);
static GLsync (*meta_gl_fence_sync) (GLenum condition,
GLbitfield flags);
static MetaSyncRing *
meta_sync_ring_get (void)
{
if (meta_sync_ring.reboots > MAX_REBOOT_ATTEMPTS)
return NULL;
return &meta_sync_ring;
}
static gboolean
load_gl_symbol (const char *name,
void **func)
{
*func = cogl_get_proc_address (name);
if (!*func)
{
meta_verbose ("MetaSyncRing: failed to resolve required GL symbol \"%s\"\n", name);
return FALSE;
}
return TRUE;
}
static gboolean
check_gl_extensions (void)
{
ClutterBackend *backend;
CoglContext *cogl_context;
CoglDisplay *cogl_display;
CoglRenderer *cogl_renderer;
backend = clutter_get_default_backend ();
cogl_context = clutter_backend_get_cogl_context (backend);
cogl_display = cogl_context_get_display (cogl_context);
cogl_renderer = cogl_display_get_renderer (cogl_display);
switch (cogl_renderer_get_driver (cogl_renderer))
{
case COGL_DRIVER_GL3:
{
int num_extensions, i;
gboolean arb_sync = FALSE;
gboolean x11_sync_object = FALSE;
meta_gl_get_integerv (GL_NUM_EXTENSIONS, &num_extensions);
for (i = 0; i < num_extensions; ++i)
{
const char *ext = meta_gl_get_stringi (GL_EXTENSIONS, i);
if (g_strcmp0 ("GL_ARB_sync", ext) == 0)
arb_sync = TRUE;
else if (g_strcmp0 ("GL_EXT_x11_sync_object", ext) == 0)
x11_sync_object = TRUE;
}
return arb_sync && x11_sync_object;
}
case COGL_DRIVER_GL:
{
const char *extensions = meta_gl_get_string (GL_EXTENSIONS);
return (extensions != NULL &&
strstr (extensions, "GL_ARB_sync") != NULL &&
strstr (extensions, "GL_EXT_x11_sync_object") != NULL);
}
default:
break;
}
return FALSE;
}
static gboolean
load_required_symbols (void)
{
static gboolean success = FALSE;
if (success)
return TRUE;
/* We don't link against libGL directly because cogl may want to
* use something else. This assumes that cogl has been initialized
* and dynamically loaded libGL at this point.
*/
if (!load_gl_symbol ("glGetString", (void **) &meta_gl_get_string))
goto out;
if (!load_gl_symbol ("glGetIntegerv", (void **) &meta_gl_get_integerv))
goto out;
if (!load_gl_symbol ("glGetStringi", (void **) &meta_gl_get_stringi))
goto out;
if (!check_gl_extensions ())
{
meta_verbose ("MetaSyncRing: couldn't find required GL extensions\n");
goto out;
}
if (!load_gl_symbol ("glDeleteSync", (void **) &meta_gl_delete_sync))
goto out;
if (!load_gl_symbol ("glClientWaitSync", (void **) &meta_gl_client_wait_sync))
goto out;
if (!load_gl_symbol ("glWaitSync", (void **) &meta_gl_wait_sync))
goto out;
if (!load_gl_symbol ("glImportSyncEXT", (void **) &meta_gl_import_sync))
goto out;
if (!load_gl_symbol ("glFenceSync", (void **) &meta_gl_fence_sync))
goto out;
success = TRUE;
out:
return success;
}
static void
meta_sync_insert (MetaSync *self)
{
g_return_if_fail (self->state == META_SYNC_STATE_READY);
XSyncTriggerFence (self->xdisplay, self->xfence);
XFlush (self->xdisplay);
meta_gl_wait_sync (self->gl_x11_sync, 0, GL_TIMEOUT_IGNORED);
self->gpu_fence = meta_gl_fence_sync (GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
self->state = META_SYNC_STATE_WAITING;
}
static GLenum
meta_sync_check_update_finished (MetaSync *self,
GLuint64 timeout)
{
GLenum status = GL_WAIT_FAILED;
switch (self->state)
{
case META_SYNC_STATE_DONE:
status = GL_ALREADY_SIGNALED;
break;
case META_SYNC_STATE_WAITING:
status = meta_gl_client_wait_sync (self->gpu_fence, 0, timeout);
if (status == GL_ALREADY_SIGNALED || status == GL_CONDITION_SATISFIED)
{
self->state = META_SYNC_STATE_DONE;
meta_gl_delete_sync (self->gpu_fence);
self->gpu_fence = 0;
}
break;
default:
break;
}
g_warn_if_fail (status != GL_WAIT_FAILED);
return status;
}
static void
meta_sync_reset (MetaSync *self)
{
XSyncAlarmAttributes attrs;
int overflow;
g_return_if_fail (self->state == META_SYNC_STATE_DONE);
XSyncResetFence (self->xdisplay, self->xfence);
attrs.trigger.wait_value = self->next_counter_value;
XSyncChangeAlarm (self->xdisplay, self->xalarm, XSyncCAValue, &attrs);
XSyncSetCounter (self->xdisplay, self->xcounter, self->next_counter_value);
XSyncValueAdd (&self->next_counter_value,
self->next_counter_value,
SYNC_VALUE_ONE,
&overflow);
self->state = META_SYNC_STATE_RESET_PENDING;
}
static void
meta_sync_handle_event (MetaSync *self,
XSyncAlarmNotifyEvent *event)
{
g_return_if_fail (event->alarm == self->xalarm);
g_return_if_fail (self->state == META_SYNC_STATE_RESET_PENDING);
self->state = META_SYNC_STATE_READY;
}
static MetaSync *
meta_sync_new (Display *xdisplay)
{
MetaSync *self;
XSyncAlarmAttributes attrs;
self = g_malloc0 (sizeof (MetaSync));
self->xdisplay = xdisplay;
self->xfence = XSyncCreateFence (xdisplay, DefaultRootWindow (xdisplay), FALSE);
self->gl_x11_sync = 0;
self->gpu_fence = 0;
self->xcounter = XSyncCreateCounter (xdisplay, SYNC_VALUE_ZERO);
attrs.trigger.counter = self->xcounter;
attrs.trigger.value_type = XSyncAbsolute;
attrs.trigger.wait_value = SYNC_VALUE_ONE;
attrs.trigger.test_type = XSyncPositiveTransition;
attrs.events = TRUE;
self->xalarm = XSyncCreateAlarm (xdisplay,
XSyncCACounter |
XSyncCAValueType |
XSyncCAValue |
XSyncCATestType |
XSyncCAEvents,
&attrs);
XSyncIntToValue (&self->next_counter_value, 1);
self->state = META_SYNC_STATE_READY;
return self;
}
static void
meta_sync_import (MetaSync *self)
{
g_return_if_fail (self->gl_x11_sync == 0);
self->gl_x11_sync = meta_gl_import_sync (GL_SYNC_X11_FENCE_EXT, self->xfence, 0);
}
static Bool
alarm_event_predicate (Display *dpy,
XEvent *event,
XPointer data)
{
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return False;
if (event->type == ring->xsync_event_base + XSyncAlarmNotify)
{
if (((MetaSync *) data)->xalarm == ((XSyncAlarmNotifyEvent *) event)->alarm)
return True;
}
return False;
}
static void
meta_sync_free (MetaSync *self)
{
/* When our assumptions don't hold, something has gone wrong but we
* don't know what, so we reboot the ring. While doing that, we
* trigger fences before deleting them to try to get ourselves out
* of a potentially stuck GPU state.
*/
switch (self->state)
{
case META_SYNC_STATE_WAITING:
meta_gl_delete_sync (self->gpu_fence);
break;
case META_SYNC_STATE_DONE:
/* nothing to do */
break;
case META_SYNC_STATE_RESET_PENDING:
{
XEvent event;
XIfEvent (self->xdisplay, &event, alarm_event_predicate, (XPointer) self);
meta_sync_handle_event (self, (XSyncAlarmNotifyEvent *) &event);
}
/* fall through */
case META_SYNC_STATE_READY:
XSyncTriggerFence (self->xdisplay, self->xfence);
XFlush (self->xdisplay);
break;
default:
break;
}
meta_gl_delete_sync (self->gl_x11_sync);
XSyncDestroyFence (self->xdisplay, self->xfence);
XSyncDestroyCounter (self->xdisplay, self->xcounter);
XSyncDestroyAlarm (self->xdisplay, self->xalarm);
g_free (self);
}
gboolean
meta_sync_ring_init (Display *xdisplay)
{
gint major, minor;
guint i;
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return FALSE;
g_return_val_if_fail (xdisplay != NULL, FALSE);
g_return_val_if_fail (ring->xdisplay == NULL, FALSE);
if (!load_required_symbols ())
return FALSE;
if (!XSyncQueryExtension (xdisplay, &ring->xsync_event_base, &ring->xsync_error_base) ||
!XSyncInitialize (xdisplay, &major, &minor))
return FALSE;
XSyncIntToValue (&SYNC_VALUE_ZERO, 0);
XSyncIntToValue (&SYNC_VALUE_ONE, 1);
ring->xdisplay = xdisplay;
ring->alarm_to_sync = g_hash_table_new (NULL, NULL);
for (i = 0; i < NUM_SYNCS; ++i)
{
MetaSync *sync = meta_sync_new (ring->xdisplay);
ring->syncs_array[i] = sync;
g_hash_table_replace (ring->alarm_to_sync, (gpointer) sync->xalarm, sync);
}
/* Since the connection we create the X fences on isn't the same as
* the one used for the GLX context, we need to XSync() here to
* ensure glImportSync() succeeds. */
XSync (xdisplay, False);
for (i = 0; i < NUM_SYNCS; ++i)
meta_sync_import (ring->syncs_array[i]);
ring->current_sync_idx = 0;
ring->current_sync = ring->syncs_array[0];
ring->warmup_syncs = 0;
return TRUE;
}
void
meta_sync_ring_destroy (void)
{
guint i;
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return;
g_return_if_fail (ring->xdisplay != NULL);
ring->current_sync_idx = 0;
ring->current_sync = NULL;
ring->warmup_syncs = 0;
for (i = 0; i < NUM_SYNCS; ++i)
meta_sync_free (ring->syncs_array[i]);
g_hash_table_destroy (ring->alarm_to_sync);
ring->xsync_event_base = 0;
ring->xsync_error_base = 0;
ring->xdisplay = NULL;
}
static gboolean
meta_sync_ring_reboot (Display *xdisplay)
{
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return FALSE;
meta_sync_ring_destroy ();
ring->reboots += 1;
if (!meta_sync_ring_get ())
{
meta_warning ("MetaSyncRing: Too many reboots -- disabling\n");
return FALSE;
}
return meta_sync_ring_init (xdisplay);
}
gboolean
meta_sync_ring_after_frame (void)
{
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return FALSE;
g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
if (ring->warmup_syncs >= NUM_SYNCS / 2)
{
guint reset_sync_idx = (ring->current_sync_idx + NUM_SYNCS - (NUM_SYNCS / 2)) % NUM_SYNCS;
MetaSync *sync_to_reset = ring->syncs_array[reset_sync_idx];
GLenum status = meta_sync_check_update_finished (sync_to_reset, 0);
if (status == GL_TIMEOUT_EXPIRED)
{
meta_warning ("MetaSyncRing: We should never wait for a sync -- add more syncs?\n");
status = meta_sync_check_update_finished (sync_to_reset, MAX_SYNC_WAIT_TIME);
}
if (status != GL_ALREADY_SIGNALED && status != GL_CONDITION_SATISFIED)
{
meta_warning ("MetaSyncRing: Timed out waiting for sync object.\n");
return meta_sync_ring_reboot (ring->xdisplay);
}
meta_sync_reset (sync_to_reset);
}
else
{
ring->warmup_syncs += 1;
}
ring->current_sync_idx += 1;
ring->current_sync_idx %= NUM_SYNCS;
ring->current_sync = ring->syncs_array[ring->current_sync_idx];
return TRUE;
}
gboolean
meta_sync_ring_insert_wait (void)
{
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return FALSE;
g_return_val_if_fail (ring->xdisplay != NULL, FALSE);
if (ring->current_sync->state != META_SYNC_STATE_READY)
{
meta_warning ("MetaSyncRing: Sync object is not ready -- were events handled properly?\n");
if (!meta_sync_ring_reboot (ring->xdisplay))
return FALSE;
}
meta_sync_insert (ring->current_sync);
return TRUE;
}
void
meta_sync_ring_handle_event (XEvent *xevent)
{
XSyncAlarmNotifyEvent *event;
MetaSync *sync;
MetaSyncRing *ring = meta_sync_ring_get ();
if (!ring)
return;
g_return_if_fail (ring->xdisplay != NULL);
if (xevent->type != (ring->xsync_event_base + XSyncAlarmNotify))
return;
event = (XSyncAlarmNotifyEvent *) xevent;
sync = g_hash_table_lookup (ring->alarm_to_sync, (gpointer) event->alarm);
if (sync)
meta_sync_handle_event (sync, event);
}

View File

@@ -0,0 +1,14 @@
#ifndef _META_SYNC_RING_H_
#define _META_SYNC_RING_H_
#include <glib.h>
#include <X11/Xlib.h>
gboolean meta_sync_ring_init (Display *dpy);
void meta_sync_ring_destroy (void);
gboolean meta_sync_ring_after_frame (void);
gboolean meta_sync_ring_insert_wait (void);
void meta_sync_ring_handle_event (XEvent *event);
#endif /* _META_SYNC_RING_H_ */

View File

@@ -1214,7 +1214,7 @@ meta_grab_op_is_moving (MetaGrabOp op)
if (!grab_op_is_window (op))
return FALSE;
return (op & META_GRAB_OP_WINDOW_DIR_MASK) == 0;
return !meta_grab_op_is_resizing (op);
}
/**

View File

@@ -779,7 +779,8 @@ meta_window_place (MetaWindow *window,
if (w != window &&
meta_window_showing_on_its_workspace (w) &&
meta_window_located_on_workspace (w, window->workspace))
(window->on_all_workspaces ||
meta_window_located_on_workspace (w, window->workspace)))
windows = g_list_prepend (windows, w);
tmp = tmp->next;

View File

@@ -57,6 +57,8 @@ struct _MetaBackground
MetaBackgroundPrivate *priv;
};
void meta_background_refresh_all (void);
GType meta_background_get_type (void);
MetaBackground *meta_background_new (MetaScreen *screen);

View File

@@ -1073,9 +1073,10 @@ meta_window_x11_move_resize_internal (MetaWindow *window,
/* Compute new frame size */
new_w = window->rect.width + borders.invisible.left + borders.invisible.right;
new_h = borders.invisible.top + borders.invisible.bottom;
if (!window->shaded)
new_h += window->rect.height;
if (window->shaded)
new_h = borders.total.top + borders.total.bottom;
else
new_h = window->rect.height + borders.invisible.top + borders.invisible.bottom;
if (new_w != window->frame->rect.width ||
new_h != window->frame->rect.height)