[gtk+] gdkinternals: Document our drawing and painting process better



commit 10a7a89311ba0edf93c70470ddac23ecf2d8c3e7
Author: Jasper St. Pierre <jstpierre mecheye net>
Date:   Sat Nov 22 09:07:51 2014 -0800

    gdkinternals: Document our drawing and painting process better

 gdk/gdkinternals.h |   77 ++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 72 insertions(+), 5 deletions(-)
---
diff --git a/gdk/gdkinternals.h b/gdk/gdkinternals.h
index 67a58da..cbb87e4 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;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]