summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference/gdk/gdk4-sections.txt1
-rw-r--r--gdk/gdkglcontext.c36
-rw-r--r--gdk/gdkglcontext.h3
-rw-r--r--gdk/gdkglcontextprivate.h2
-rw-r--r--gdk/mir/gdkmirglcontext.c59
-rw-r--r--gdk/wayland/gdkglcontext-wayland.c67
-rw-r--r--gdk/x11/gdkglcontext-x11.c111
-rw-r--r--gsk/gskglrenderer.c94
8 files changed, 236 insertions, 137 deletions
diff --git a/docs/reference/gdk/gdk4-sections.txt b/docs/reference/gdk/gdk4-sections.txt
index ecebef2bdd..7d3bd5fc38 100644
--- a/docs/reference/gdk/gdk4-sections.txt
+++ b/docs/reference/gdk/gdk4-sections.txt
@@ -1313,6 +1313,7 @@ gdk_gl_context_is_legacy
<SUBSECTION>
GdkGLError
gdk_gl_context_realize
+gdk_gl_context_get_damage
gdk_gl_context_make_current
gdk_gl_context_get_current
gdk_gl_context_clear_current
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index c12af91ea8..b8df697dbe 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -255,6 +255,18 @@ gdk_gl_context_real_realize (GdkGLContext *self,
return FALSE;
}
+static cairo_region_t *
+gdk_gl_context_real_get_damage (GdkGLContext *context)
+{
+ GdkWindow *window = gdk_draw_context_get_window (GDK_DRAW_CONTEXT (context));
+
+ return cairo_region_create_rectangle (&(GdkRectangle) {
+ 0, 0,
+ gdk_window_get_width (window),
+ gdk_window_get_height (window)
+ });
+}
+
static void
gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
cairo_region_t *region)
@@ -262,6 +274,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
GdkWindow *window;
GdkGLContext *shared;
+ cairo_region_t *damage;
int ww, wh;
shared = gdk_gl_context_get_shared_context (context);
@@ -271,6 +284,10 @@ gdk_gl_context_real_begin_frame (GdkDrawContext *draw_context,
return;
}
+ damage = gdk_gl_context_get_damage (context);
+ cairo_region_union (region, damage);
+ cairo_region_destroy (damage);
+
window = gdk_draw_context_get_window (draw_context);
ww = gdk_window_get_width (window) * gdk_window_get_scale_factor (window);
wh = gdk_window_get_height (window) * gdk_window_get_scale_factor (window);
@@ -309,6 +326,7 @@ gdk_gl_context_class_init (GdkGLContextClass *klass)
GdkDrawContextClass *draw_context_class = GDK_DRAW_CONTEXT_CLASS (klass);
klass->realize = gdk_gl_context_real_realize;
+ klass->get_damage = gdk_gl_context_real_get_damage;
draw_context_class->begin_frame = gdk_gl_context_real_begin_frame;
draw_context_class->end_frame = gdk_gl_context_real_end_frame;
@@ -345,6 +363,24 @@ gdk_gl_context_init (GdkGLContext *self)
priv->use_es = -1;
}
+/**
+ * gdk_gl_context_get_damage:
+ * @context: a #GdkGLContext
+ *
+ * Returns the part of the backbuffer that is known to be damaged and would
+ * need to be redrawn. This is the area that needs to be respected in addition
+ * to areas invalidated by GTK or the windowing system itself.
+ *
+ * Returns: The damage to the backbuffer
+ **/
+cairo_region_t *
+gdk_gl_context_get_damage (GdkGLContext *context)
+{
+ g_return_val_if_fail (GDK_IS_GL_CONTEXT (context), cairo_region_create ());
+
+ return GDK_GL_CONTEXT_GET_CLASS (context)->get_damage (context);
+}
+
GdkGLContextPaintData *
gdk_gl_context_get_paint_data (GdkGLContext *context)
{
diff --git a/gdk/gdkglcontext.h b/gdk/gdkglcontext.h
index eb380c2f25..2c22fb7341 100644
--- a/gdk/gdkglcontext.h
+++ b/gdk/gdkglcontext.h
@@ -82,6 +82,9 @@ gboolean gdk_gl_context_get_use_es (GdkGLContext *
GDK_AVAILABLE_IN_3_16
gboolean gdk_gl_context_realize (GdkGLContext *context,
GError **error);
+GDK_AVAILABLE_IN_3_90
+cairo_region_t * gdk_gl_context_get_damage (GdkGLContext *context);
+
GDK_AVAILABLE_IN_3_16
void gdk_gl_context_make_current (GdkGLContext *context);
GDK_AVAILABLE_IN_3_16
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index 7fc15ca9b4..cf834da3a7 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -44,6 +44,8 @@ struct _GdkGLContextClass
gboolean (* realize) (GdkGLContext *context,
GError **error);
+ cairo_region_t * (* get_damage) (GdkGLContext *context);
+
gboolean (* texture_from_surface) (GdkGLContext *context,
cairo_surface_t *surface,
cairo_region_t *region);
diff --git a/gdk/mir/gdkmirglcontext.c b/gdk/mir/gdkmirglcontext.c
index ae98c5282c..4d358a66da 100644
--- a/gdk/mir/gdkmirglcontext.c
+++ b/gdk/mir/gdkmirglcontext.c
@@ -97,28 +97,47 @@ gdk_mir_gl_context_realize (GdkGLContext *context,
return TRUE;
}
-static void
-gdk_mir_gl_context_begin_frame (GdkDrawContext *draw_context,
- cairo_region_t *update_area)
+static cairo_region_t *
+gdk_mir_gl_context_get_damage (GdkGLContext *context)
{
- GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
- GdkDisplay *display = gdk_draw_context_get_display (draw_context);
- GdkWindow *window;
-
- GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->begin_frame (draw_context, update_area);
- if (gdk_gl_context_get_shared_context (context))
- return;
+ GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
+ EGLSurface egl_surface;
+ GdkWindow *window = gdk_draw_context_get_window (GDK_DRAW_CONTEXT (context));
+ unsigned int buffer_age = 0;
- if (_gdk_mir_display_have_egl_swap_buffers_with_damage (display))
- return;
+ if (_gdk_mir_display_have_egl_buffer_age (display))
+ {
+ GdkGLContext *shared;
+ GdkMirGLContext *shared_mir;
+
+ shared = gdk_gl_context_get_shared_context (context);
+ if (shared == NULL)
+ shared = context;
+ shared_mir = GDK_MIR_GL_CONTEXT (shared);
+
+ egl_surface = _gdk_mir_window_get_egl_surface (window, shared_mir->egl_config);
+ gdk_gl_context_make_current (shared);
+ eglQuerySurface (_gdk_mir_display_get_egl_display (display), egl_surface,
+ EGL_BUFFER_AGE_EXT, &buffer_age);
+
+ if (buffer_age >= 2)
+ {
+ if (window->old_updated_area[0])
+ return cairo_region_copy (window->old_updated_area[0]);
+ }
+ else if (buffer_age >= 3)
+ {
+ if (window->old_updated_area[0] &&
+ window->old_updated_area[1])
+ {
+ cairo_region_t *damage = cairo_region_copy (window->old_updated_area[0]);
+ cairo_region_union (damage, window->old_updated_area[1]);
+ return damage;
+ }
+ }
+ }
- /* If nothing else is known, repaint everything so that the back
- buffer is fully up-to-date for the swapbuffer */
- window = gdk_gl_context_get_window (context);
- cairo_region_union_rectangle (update_area, &(GdkRectangle) {
- 0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window) });
+ return GDK_GL_CONTEXT_CLASS (gdk_mir_gl_context_parent_class)->get_damage (context);
}
static void
@@ -197,7 +216,7 @@ gdk_mir_gl_context_class_init (GdkMirGLContextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
context_class->realize = gdk_mir_gl_context_realize;
- context_class->begin_frame = gdk_mir_gl_context_begin_frame;
+ context_class->get_damage = gdk_mir_gl_context_get_damage;
context_class->end_frame = gdk_mir_gl_context_end_frame;
gobject_class->dispose = gdk_mir_gl_context_dispose;
}
diff --git a/gdk/wayland/gdkglcontext-wayland.c b/gdk/wayland/gdkglcontext-wayland.c
index 42ba97c9e0..991273c19c 100644
--- a/gdk/wayland/gdkglcontext-wayland.c
+++ b/gdk/wayland/gdkglcontext-wayland.c
@@ -37,26 +37,6 @@ G_DEFINE_TYPE (GdkWaylandGLContext, gdk_wayland_gl_context, GDK_TYPE_GL_CONTEXT)
static void gdk_wayland_gl_context_dispose (GObject *gobject);
-static void
-gdk_wayland_gl_context_begin_frame (GdkDrawContext *draw_context,
- cairo_region_t *update_area)
-{
- GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
- GdkWindow *window;
-
- GDK_DRAW_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->begin_frame (draw_context, update_area);
- if (gdk_gl_context_get_shared_context (context))
- return;
-
- /* If nothing else is known, repaint everything so that the back
- buffer is fully up-to-date for the swapbuffer */
- window = gdk_gl_context_get_window (context);
- cairo_region_union_rectangle (update_area, &(GdkRectangle) {
- 0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window) });
-}
-
#define N_EGL_ATTRS 16
static gboolean
@@ -175,6 +155,51 @@ gdk_wayland_gl_context_realize (GdkGLContext *context,
return TRUE;
}
+static cairo_region_t *
+gdk_wayland_gl_context_get_damage (GdkGLContext *context)
+{
+ GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
+ GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display);
+ EGLSurface egl_surface;
+ GdkWindow *window = gdk_draw_context_get_window (GDK_DRAW_CONTEXT (context));
+ int buffer_age = 0;
+
+ if (display_wayland->have_egl_buffer_age)
+ {
+ GdkGLContext *shared;
+ GdkWaylandGLContext *shared_wayland;
+
+ shared = gdk_gl_context_get_shared_context (context);
+ if (shared == NULL)
+ shared = context;
+ shared_wayland = GDK_WAYLAND_GL_CONTEXT (shared);
+
+ egl_surface = gdk_wayland_window_get_egl_surface (window->impl_window,
+ shared_wayland->egl_config);
+ gdk_gl_context_make_current (shared);
+ eglQuerySurface (display_wayland->egl_display, egl_surface,
+ EGL_BUFFER_AGE_EXT, &buffer_age);
+
+ if (buffer_age >= 2)
+ {
+ if (window->old_updated_area[0])
+ return cairo_region_copy (window->old_updated_area[0]);
+ }
+ else if (buffer_age >= 3)
+ {
+ if (window->old_updated_area[0] &&
+ window->old_updated_area[1])
+ {
+ cairo_region_t *damage = cairo_region_copy (window->old_updated_area[0]);
+ cairo_region_union (damage, window->old_updated_area[1]);
+ return damage;
+ }
+ }
+ }
+
+ return GDK_GL_CONTEXT_CLASS (gdk_wayland_gl_context_parent_class)->get_damage (context);
+}
+
static void
gdk_wayland_gl_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted,
@@ -227,10 +252,10 @@ gdk_wayland_gl_context_class_init (GdkWaylandGLContextClass *klass)
gobject_class->dispose = gdk_wayland_gl_context_dispose;
- draw_context_class->begin_frame = gdk_wayland_gl_context_begin_frame;
draw_context_class->end_frame = gdk_wayland_gl_context_end_frame;
context_class->realize = gdk_wayland_gl_context_realize;
+ context_class->get_damage = gdk_wayland_gl_context_get_damage;
}
static void
diff --git a/gdk/x11/gdkglcontext-x11.c b/gdk/x11/gdkglcontext-x11.c
index 5662bc544b..8eb2cab1c0 100644
--- a/gdk/x11/gdkglcontext-x11.c
+++ b/gdk/x11/gdkglcontext-x11.c
@@ -120,48 +120,6 @@ maybe_wait_for_vblank (GdkDisplay *display,
}
static void
-gdk_x11_gl_context_begin_frame (GdkDrawContext *draw_context,
- cairo_region_t *update_area)
-{
- GdkGLContext *context = GDK_GL_CONTEXT (draw_context);
- GdkWindow *window;
-
- GDK_DRAW_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->begin_frame (draw_context, update_area);
- if (gdk_gl_context_get_shared_context (context))
- return;
-
- if (gdk_gl_context_has_framebuffer_blit (context))
- return;
-
- window = gdk_gl_context_get_window (context);
- /* If nothing else is known, repaint everything so that the back
- buffer is fully up-to-date for the swapbuffer */
- cairo_region_union_rectangle (update_area, &(GdkRectangle) {
- 0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window) });
-}
-
-static void
-gdk_gl_blit_region (GdkWindow *window, cairo_region_t *region)
-{
- int n_rects, i;
- int scale = gdk_window_get_scale_factor (window);
- int wh = gdk_window_get_height (window);
- cairo_rectangle_int_t rect;
-
- n_rects = cairo_region_num_rectangles (region);
- for (i = 0; i < n_rects; i++)
- {
- cairo_region_get_rectangle (region, i, &rect);
- glScissor (rect.x * scale, (wh - rect.y - rect.height) * scale, rect.width * scale, rect.height * scale);
- glBlitFramebuffer (rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale,
- rect.x * scale, (wh - rect.y - rect.height) * scale, (rect.x + rect.width) * scale, (wh - rect.y) * scale,
- GL_COLOR_BUFFER_BIT, GL_NEAREST);
- }
-}
-
-static void
gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
cairo_region_t *painted,
cairo_region_t *damage)
@@ -172,7 +130,7 @@ gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
GdkDisplay *display = gdk_gl_context_get_display (context);
Display *dpy = gdk_x11_display_get_xdisplay (display);
GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
- GdkRectangle whole_window;
+ //GdkRectangle whole_window;
DrawableInfo *info;
GLXDrawable drawable;
@@ -225,32 +183,55 @@ gdk_x11_gl_context_end_frame (GdkDrawContext *draw_context,
}
}
- whole_window = (GdkRectangle) { 0, 0, gdk_window_get_width (window), gdk_window_get_height (window) };
- if (cairo_region_contains_rectangle (painted, &whole_window) == CAIRO_REGION_OVERLAP_IN)
- {
- glXSwapBuffers (dpy, drawable);
- }
- else if (gdk_gl_context_has_framebuffer_blit (context))
- {
- glDrawBuffer(GL_FRONT);
- glReadBuffer(GL_BACK);
- gdk_gl_blit_region (window, painted);
- glDrawBuffer(GL_BACK);
- glFlush();
-
- if (gdk_gl_context_has_frame_terminator (context))
- glFrameTerminatorGREMEDY ();
- }
- else
- {
- g_warning ("Need to swap whole buffer even thouigh not everything was redrawn. Expect artifacts.");
- glXSwapBuffers (dpy, drawable);
- }
+ glXSwapBuffers (dpy, drawable);
if (context_x11->do_frame_sync && info != NULL && display_x11->has_glx_video_sync)
glXGetVideoSyncSGI (&info->last_frame_counter);
}
+static cairo_region_t *
+gdk_x11_gl_context_get_damage (GdkGLContext *context)
+{
+ GdkDisplay *display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
+ GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+ Display *dpy = gdk_x11_display_get_xdisplay (display);
+ GdkWindow *window = gdk_draw_context_get_window (GDK_DRAW_CONTEXT (context));
+ unsigned int buffer_age = 0;
+
+ if (display_x11->has_glx_buffer_age)
+ {
+ GdkGLContext *shared;
+ GdkX11GLContext *shared_x11;
+
+ shared = gdk_gl_context_get_shared_context (context);
+ if (shared == NULL)
+ shared = context;
+ shared_x11 = GDK_X11_GL_CONTEXT (shared);
+
+ gdk_gl_context_make_current (shared);
+ glXQueryDrawable(dpy, shared_x11->attached_drawable,
+ GLX_BACK_BUFFER_AGE_EXT, &buffer_age);
+
+ if (buffer_age >= 2)
+ {
+ if (window->old_updated_area[0])
+ return cairo_region_copy (window->old_updated_area[0]);
+ }
+ else if (buffer_age >= 3)
+ {
+ if (window->old_updated_area[0] &&
+ window->old_updated_area[1])
+ {
+ cairo_region_t *damage = cairo_region_copy (window->old_updated_area[0]);
+ cairo_region_union (damage, window->old_updated_area[1]);
+ return damage;
+ }
+ }
+ }
+
+ return GDK_GL_CONTEXT_CLASS (gdk_x11_gl_context_parent_class)->get_damage (context);
+}
+
typedef struct {
Display *display;
GLXDrawable drawable;
@@ -787,9 +768,9 @@ gdk_x11_gl_context_class_init (GdkX11GLContextClass *klass)
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
context_class->realize = gdk_x11_gl_context_realize;
+ context_class->get_damage = gdk_x11_gl_context_get_damage;
context_class->texture_from_surface = gdk_x11_gl_context_texture_from_surface;
- draw_context_class->begin_frame = gdk_x11_gl_context_begin_frame;
draw_context_class->end_frame = gdk_x11_gl_context_end_frame;
gobject_class->dispose = gdk_x11_gl_context_dispose;
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 3ec9327f7e..c0d528871c 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -90,6 +90,11 @@ typedef struct {
} ProfileTimers;
#endif
+typedef enum {
+ RENDER_FULL,
+ RENDER_SCISSOR
+} RenderMode;
+
struct _GskGLRenderer
{
GskRenderer parent_instance;
@@ -118,6 +123,8 @@ struct _GskGLRenderer
ProfileTimers profile_timers;
#endif
+ RenderMode render_mode;
+
gboolean has_buffers : 1;
};
@@ -322,48 +329,45 @@ gsk_gl_renderer_unrealize (GskRenderer *renderer)
static GdkDrawingContext *
gsk_gl_renderer_begin_draw_frame (GskRenderer *renderer,
- const cairo_region_t *region)
+ const cairo_region_t *update_area)
{
GskGLRenderer *self = GSK_GL_RENDERER (renderer);
- cairo_region_t *whole_window;
+ cairo_region_t *damage;
GdkDrawingContext *result;
+ GdkRectangle whole_window;
GdkWindow *window;
window = gsk_renderer_get_window (renderer);
+ whole_window = (GdkRectangle) {
+ 0, 0,
+ gdk_window_get_width (window),
+ gdk_window_get_height (window)
+ };
+ damage = gdk_gl_context_get_damage (self->gl_context);
+ cairo_region_union (damage, update_area);
- whole_window = cairo_region_create_rectangle (&(GdkRectangle) {
- 0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window)
- });
-
- return gdk_window_begin_draw_frame (window,
- GDK_DRAW_CONTEXT (self->gl_context),
- region);
-
- cairo_region_destroy (whole_window);
-
- return result;
-}
+ if (cairo_region_contains_rectangle (damage, &whole_window) == CAIRO_REGION_OVERLAP_IN)
+ {
+ self->render_mode = RENDER_FULL;
+ }
+ else
+ {
+ GdkRectangle extents;
-static GdkDrawingContext *
-gsk_gl_renderer_begin_draw_frame (GskRenderer *renderer,
- const cairo_region_t *region)
-{
- cairo_region_t *whole_window;
- GdkDrawingContext *result;
- GdkWindow *window;
+ cairo_region_get_extents (damage, &extents);
+ cairo_region_union_rectangle (damage, &extents);
- window = gsk_renderer_get_window (renderer);
-
- whole_window = cairo_region_create_rectangle (&(GdkRectangle) {
- 0, 0,
- gdk_window_get_width (window),
- gdk_window_get_height (window) });
+ if (gdk_rectangle_equal (&extents, &whole_window))
+ self->render_mode = RENDER_FULL;
+ else
+ self->render_mode = RENDER_SCISSOR;
+ }
- result = GSK_RENDERER_CLASS (gsk_gl_renderer_parent_class)->begin_draw_frame (renderer, whole_window);
+ result = gdk_window_begin_draw_frame (window,
+ GDK_DRAW_CONTEXT (self->gl_context),
+ damage);
- cairo_region_destroy (whole_window);
+ cairo_region_destroy (damage);
return result;
}
@@ -859,6 +863,32 @@ gsk_gl_renderer_clear (GskGLRenderer *self)
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
}
+static void
+gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
+{
+ switch (self->render_mode)
+ {
+ case RENDER_FULL:
+ glDisable (GL_SCISSOR_TEST);
+ break;
+
+ case RENDER_SCISSOR:
+ {
+ GdkDrawingContext *context = gsk_renderer_get_drawing_context (GSK_RENDERER (self));
+ GdkWindow *window = gsk_renderer_get_window (GSK_RENDERER (self));
+ GdkRectangle extents;
+ cairo_region_get_extents (gdk_drawing_context_get_clip (context), &extents);
+ glScissor (extents.x, gdk_window_get_height (window) - extents.height - extents.y, extents.width, extents.height);
+ glEnable (GL_SCISSOR_TEST);
+ break;
+ }
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
#define ORTHO_NEAR_PLANE -10000
#define ORTHO_FAR_PLANE 10000
@@ -916,6 +946,8 @@ gsk_gl_renderer_render (GskRenderer *renderer,
if (gsk_gl_driver_bind_render_target (self->gl_driver, 0))
gsk_gl_renderer_resize_viewport (self, &viewport, scale_factor);
+ gsk_gl_renderer_setup_render_mode (self);
+
gsk_gl_renderer_clear (self);
glEnable (GL_DEPTH_TEST);