Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GdkGLContext: Never use glXSwapIntervalSGI on composited WMs #1

Closed
wants to merge 639 commits into from

Conversation

alexlarsson
Copy link

Delaying the copy of the backbuffer to the front buffer until
the vblank doesn't make sense when the frontbuffer is not the
real screen, as the copy will not flicker anyway. It is the
responsibility of the compositor to sync its drawing of the
window to the vblank.

The other reason to delay to vblank is to avoid rendering all the
time and sync each frame to the actual frame rate. However, we
already handle this in Gtk+ via the frame clock, so this should
not be needed.

baedert and others added 30 commits September 6, 2014 11:39
We were actually setting an input shape larger than the window
in !csd, and this was confusing at least openbox.

https://bugzilla.gnome.org/736064
It turns out GtkCellRendererAccel does not deal well with focus
being elsewhere. Adding an entry here makes this much easier to
reproduce.
Grab keyboard/mouse on the toplevel, and grab the focus to the
cell editable, so we actually see the key events.
This is not automatic, and with grabs in place, it is awkward
to have focus moved elsewhere, so stop editing whenever the
cell editable loses focus.
(gnome-shell-extension-prefs:22382): GLib-GObject-WARNING **: invalid cast from 'GtkInvisible' to 'GtkWindow'
(gnome-shell-extension-prefs:22382): Gtk-CRITICAL **: gtk_window_set_transient_for: assertion 'parent == NULL || GTK_IS_WINDOW (parent)' failed

 GNOME#1  0x00007fffeeb81a12 in g_log (log_domain=log_domain@entry=0x7fffeeea3464 "GLib-GObject", log_level=log_level@entry=G_LOG_LEVEL_WARNING, format=format@entry=0x7fffeeeaa878 "invalid cast from '%s' to '%s'") at gmessages.c:1079
 GNOME#2  0x00007fffeee9c2a9 in g_type_check_instance_cast (type_instance=0xb314c0, iface_type=iface_type@entry=9020048) at gtype.c:4021
 GNOME#3  0x00007ffff0a06e25 in gtk_tooltip_set_last_window (tooltip=tooltip@entry=0xbb8c10, window=<optimized out>) at gtktooltip.c:910
 GNOME#4  0x00007ffff0a08dfd in _gtk_tooltip_handle_event (event=event@entry=0xbf72c0) at gtktooltip.c:1538
 GNOME#5  0x00007ffff090d7a9 in gtk_main_do_event (event=0xbf72c0) at gtkmain.c:1785
 GNOME#6  0x00007ffff0496ab2 in gdk_event_source_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at gdkeventsource.c:364
 GNOME#7  0x00007fffeeb7a8c3 in g_main_dispatch (context=0x807300) at gmain.c:3067

https://bugzilla.gnome.org/show_bug.cgi?id=736131
Just pretend that the main widget is an empty widget the size of the
overlay.
Makes it possible to write testcases where no size requests are run on
overlay widgets before size_allocate() is called.

Testcase included.
... just because there is no style context instantiated yet. Instead,
instantiate a style context during realize() and ask it.

Fixes problems with dim labels not being dimmed on first show.

Testcase included.

https://bugzilla.gnome.org/show_bug.cgi?id=735240
Add a grab on the editable widget, so that we can capture
also shortcuts which are bound in the application itself.

https://bugzilla.gnome.org/736203
The previous commit was sloppy with parameter types.
When GtkApplicationWindow has a menubar, we don't chain up
to the GtkWindow size_allocate, which used to position the
popovers. Move that to _gtk_window_set_allocation() which
is always called by GtkApplicationWindow.

https://bugzilla.gnome.org/show_bug.cgi?id=736205
When closing the application window before closing the inspector window,
the selected widget will be set to NULL once and all the property pages
will try to g_object_weak_unref that NULL widget, so bail out in
gtk_inspector_prop_list_set_object if it's NULL.

https://bugzilla.gnome.org/show_bug.cgi?id=736201
This one makes it more obvious that it is a tree with multiple
columns and not just multiline text.

https://bugzilla.gnome.org/show_bug.cgi?id=528800
Its seems that gtk_gesture_get_last_event may return NULL,
protect against that to avoid critical warnings.
This is needed for shm_open, according to its man page.

https://bugzilla.gnome.org//show_bug.cgi?id=698031
This is a bandaid fix that makes the origin case work again
by switching RGBA window. The arrow case is still unreliable.

https://bugzilla.gnome.org/show_bug.cgi?id=732916
The target value is only relevant if we're actually animating.
Don't look at it otherwise.

https://bugzilla.gnome.org/show_bug.cgi?id=736178
This is an expected keybinding, and it is not hard to support.
Note that we use a private ::escape signal instead of using
::cancel directly, since we want to be able to suppress the
cancellation when we are on a progress page.

https://bugzilla.gnome.org/show_bug.cgi?id=579625
This lets you get the paint gl context for a window (if available).
This is useful so that you can create GL contexts that share e.g.
render buffers with this context.
When we draw the render buffer in gtkglarea we do this directly
via gl to the back buffer, and we also clear the drawn area in the
normal double buffer surface to transparent. This means when we later
draw the double buffer surface to the back buffer the gl content will
be seen (unless the app drew more on the double buffer).

The gl drawing onto the back buffer is hit on a fast-path in
gdk_cairo_draw_gl_render_buffer() that is only enabled if drawing to
the real cairo target (i.e. to the window, with no push_group()
active) with a trivial transformation. If any of this is not right we
fall back to the software path that reads back the render buffer pixels
and composites with cairo.
We need to change the source x/y depending on the final clip.
The areas in the final image is made up of these parts:

1) Areas with pure cairo rendering, no gl
2) Areas with gl rendering and no cairo region on top
3) Areas with gl rendering and further cairo drawing on top of that

This commit avoids:
* Blending the cairo surface in case 1, we use a SRC operation instead.
* Applying the cairo surface at all in case 2, this is not needed.
* Clearing the cairo surface to transparent in any case but 3.
* Clearing the back buffer at all, since we never blend over it (glareas
  are opaque for now).

The only complexity is that to track area type 3 we have to know when
widgets are drawn after a gl render. We track this by adding a new method
gdk_window_mark_paint_from_clip() which is called from the core GtkWidget
drawing code in the right place.

This requirement to call gdk_window_mark_paint_from_clip() is only really
effective if you mix cairo and gl drawing, so its not *really* a regression
for code using gdk without GtkWidget drawing, as it will not affect anything
unless you also use the newer gl features in your app.
We can always ignore the alpha blending, because this function
is always called on native windows (has_impl). It is in fact
checked the first thing in the function.
This allows us to avoid state changes in the common case.
This broke DRI2, as we ended up calling glXDestroyPixmap after
the real pixmap had been freed by cairo. We're not really
using the saved pixmap anyway, so just free it when done.
This is needed to ensure all the data is on the pixmap before
we read it back from X via gl.
This uses GL_GREMEDY_frame_terminator to mark the end of a frame,
which lets tools like apitrace to do a much better job.
This does not fully work atm, but it is a start.
The way GdkGLPixelFormat and the framebuffer setup worked matched the
traditional GLX way that GL has worked where you create a native
window and do negotiations for the framebuffer details on that.

This doesn't really match the current model where Gdk owns the
gl rendering and presenting to the toplevel and child widgets work
by using renderbuffers. Additionally, it completely fails on wayland
as there we have to actually allocate the surface buffer for the
toplevel, and there can be only one, with only one framebuffer
config, so we can't expose some API to let the user create different
ones.

So, in the new world we change context creation to:

GdkGLContext *gdk_window_create_gl_context (GdkWindow    *window,
                                            GdkGLProfile  profile,
                                            GError      **error);

Which creates a context for the native window that backs this
particular window, which cannot be bound to another window. The
framebuffer config chosen for the context is the one described by the
window visual (i.e. same bitdept, has alpha if window is rgba visual,
no aux buffers). Anything that requires rendering with other kinds
of buffers (stencil, depth, etc) need to do that with render buffers.

This simplifies the APIs a lot, and allows a sane wayland
implementation. Limiting the context to a single window also fixes
some remaining issues with making contexts current.
Rather than hardcoding the bit-blit in end_paint() we call flush.
However, there are some complications:
 * flush using swapbuffers may need to draw more on the back
   buffer than just the current dirty area. So, we let the backend
   add more area to expose.

 * We also keep track of the *actual* update area via activate_update_area.
   So that we can push this as the damaged area for e.g. wayland
   with swap_buffer_with_damage.

 * Since this is pretty complex we make the flush operation non-public.
   This should not be needed anyway, as gdk is in full control of the
   paint loop.

 * Due to the cost of the above we only use GL for drawing a toplevel
   if anything in it is using gl (paint_context is not NULL). The
   env var GDK_ALWAYS_USE_GL overrides this for debugging.

At the moment the gl backends are very naive and repaint everything
each frame, but further work can make this more reasonable.
This uses the buffer age extension to detect the "age" of the
current backbuffer, to avoid redrawing things that is already
uptodate in the backbuffer. It also adds a new green color
for the update region to show the area of the window that
was redrawn due to having to repaint old areas of the back buffer.
This allows compositors to minimize how much to repaint.
We're in full control of the paint loop (and have to be), so the
app should not be meddling with this. We'll set swap-interval if
needed (like e.g. when not running under a compositor, or when
redirected at fullscreen) to always achieve a frame-synced output.
This adds checks for alpha in the software fallback.
Note, this is still a SOURCE operation, so your alpha values
will reach the window, but not blend over other data.
The new error allows you to fall back properly if not supported.
This adds a has_alpha option to GtkGLArea, which determines of the gl
buffer in use has an alpha channel or not.

If it doesn't we use the old code using render buffers. However, render
buffers don't support alpha when blitting, so in the alpha case we use
a texture which we blend onto the backbuffer.

In order to properly blend on top of already drawn cairo content we
start by copying the area below the texture destination to the back buffer.

This also adds an alpha toggle to gdkgears
All rendering requires gl contextes sharing the paint context, so
make gdk_window_create_gl_context always share that and remove the
_shared version (can be added back later if something really needs it).

Also make gdk_window_get_paint_gl_context internal as it is no longer
needed in the public API.

Also remove gdk_gl_context_update() which is not needed any more.
@ebassi ebassi closed this Aug 11, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet