summaryrefslogtreecommitdiff
path: root/gdk/gdkinternals.h
diff options
context:
space:
mode:
authorJasper St. Pierre <jstpierre@mecheye.net>2014-11-22 09:07:51 -0800
committerJasper St. Pierre <jstpierre@mecheye.net>2014-11-22 11:46:53 -0800
commit10a7a89311ba0edf93c70470ddac23ecf2d8c3e7 (patch)
treeeb5ebbd9c718ab804e79387113f359c5558f8837 /gdk/gdkinternals.h
parentc01e37a9a5db5957d08fcb4b8f11ea86c344f6d1 (diff)
downloadgtk+-10a7a89311ba0edf93c70470ddac23ecf2d8c3e7.tar.gz
gdkinternals: Document our drawing and painting process better
Diffstat (limited to 'gdk/gdkinternals.h')
-rw-r--r--gdk/gdkinternals.h77
1 files changed, 72 insertions, 5 deletions
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 67a58da1fb..cbb87e44a2 100644
--- a/gdk/gdkinternals.h
+++ b/gdk/gdkinternals.h
@@ -216,15 +216,82 @@ struct _GdkWindow
cairo_pattern_t *background;
+ /* The paint logic here is a bit complex because of our intermingling of
+ * cairo and GL. Let's first go over the cairo-alone case:
+ *
+ * 1) gdk_window_begin_paint_region() is called with an update region. If
+ * the backend wants it, we redirect drawing to a temporary surface
+ * sized the same as the update region and set `surface_needs_composite`
+ * to TRUE. Otherwise, we paint directly onto the real server-side window.
+ *
+ * 2) Things paint with cairo using gdk_cairo_create().
+ *
+ * 3) When everything is painted, the user calls gdk_window_end_paint().
+ * If there was a temporary surface, this is composited back onto the
+ * real backing surface in the appropriate places.
+ *
+ * This is similar to double buffering, except we only have partial surfaces
+ * of undefined contents, and instead of swapping between two buffers, we
+ * create a new temporary buffer every time.
+ *
+ * When we add GL to the mix, we have this instead:
+ *
+ * 1) gdk_window_begin_paint_region() is called with an update region like
+ * before. We always redirect cairo drawing to a temporary surface when
+ * GL is enabled.
+ *
+ * 2) Things paint with cairo using gdk_cairo_create(). Whenever
+ * something paints, it calls gdk_window_mark_paint_from_clip() to mark
+ * which regions it has painted in software. We'll learn what this does
+ * soon.
+ *
+ * 3) Something paints with GL and uses gdk_cairo_draw_from_gl() to
+ * composite back into the scene. We paint this onto the backing
+ * store for the window *immediately* by using GL, rather than
+ * painting to the temporary surface, and keep track of the area that
+ * we've painted in `flushed_region`.
+ *
+ * 4) Something paints using software again. It calls
+ * gdk_window_mark_paint_from_clip(), which subtracts the region it
+ * has painted from `flushed_region` and adds the region to
+ * `needs_blended_region`.
+ *
+ * 5) Something paints using GL again, using gdk_cairo_draw_from_gl().
+ * It paints directly to the backing store, removes the region it
+ * painted from `needs_blended_region`, and adds to `flushed_region`.
+ *
+ * 6) gdk_window_end_paint() is called. It composites the temporary surface
+ * back to the window, using GL, except it doesn't bother copying
+ * `flushed_region`, and when it paints `needs_blended_region`, it also
+ * turns on GL blending.
+ *
+ * That means that at any point in time, we have three regions:
+ *
+ * * `region` - This is the original invalidated region and is never
+ * touched.
+ *
+ * * `flushed_region` - This is the portion of `region` that has GL
+ * contents that have been painted directly to the window, and
+ * doesn't have any cairo drawing painted over it.
+ *
+ * * `needs_blended_region` - This is the portion of `region` that
+ * GL contents that have part cairo drawing painted over it.
+ * gdk_window_end_paint() will draw this region using blending.
+ *
+ * `flushed_region` and `needs_blended_region` never intersect, and the
+ * rest of `region` that isn't covered by either is the "opaque region",
+ * which is any area of cairo drawing that didn't ever intersect with GL.
+ * We can paint these from GL without turning on blending.
+ **/
+
struct {
- cairo_region_t *region;
+ /* The temporary surface that we're painting to. This will be composited
+ * back into the window when we call end_paint. This is our poor-man's
+ * way of doing double buffering. */
cairo_surface_t *surface;
- /* Areas of region that have been copied to the back buffer already */
+ cairo_region_t *region;
cairo_region_t *flushed_region;
- /* Areas of region that have been copied to the back buffer but
- needs furter blending of surface data. These two regions are
- always non-intersecting. */
cairo_region_t *need_blend_region;
gboolean surface_needs_composite;