[cogl/wip/outputs: 9/11] stash: Expose api to configure outputs



commit 2abde6d7ab2c8c62aa489810ecc47fec3d09b82e
Author: Robert Bragg <robert linux intel com>
Date:   Sun Apr 21 13:05:04 2013 +0100

    stash: Expose api to configure outputs
    
    Previously it was only possible to read the state of outputs. This patch
    introduces apis for configuring outputs including setting new modes and
    setting up hardware overlays.
    
    This notably has a different style to the XRandR/KMS apis that expose
    a model of components that can be assembled into a display pipeline. For
    example the KMS api lets you make a pipeline like this:
    
      framebuffers -> crtc [+planes] -> encoder -> connector
    
    This Cogl api instead exposes an object (CoglOutput) that represents a
    full display/output pipeline and then lets you hook sources into that
    pipeline via CoglOverlay objects whereby a source may be scaled and
    positioned relative to the full output resolution and multiple overlays
    may be stacked to be composed before display.
    
    With this api all output changes are batched up until
    cogl_renderer_commit_outputs() is called and on failure we will role
    back to the previous state. This is also unlike the KMS api where errors
    can be reported while you may only be part way through configuring the
    outputs as desired and there is no role back mechanism.
    
    With this api we also hope to cover more capabilities with a portable
    api whereas the portable KMS api is very minimal and depends on device
    specific ioctls for more complete control.

 cogl/Makefile.am                  |    5 +
 cogl/cogl-bitmap.h                |    6 +-
 cogl/cogl-frame-info.h            |    6 +-
 cogl/cogl-framebuffer.h           |    1 +
 cogl/cogl-mode-private.h          |   58 ++++++++
 cogl/cogl-mode.c                  |   73 ++++++++++
 cogl/cogl-mode.h                  |   51 +++++++
 cogl/cogl-onscreen.h              |    6 +-
 cogl/cogl-output-private.h        |   46 +++++-
 cogl/cogl-output.c                |  288 ++++++++++++++++++++++++++++++++++--
 cogl/cogl-output.h                |  245 +++++++++++++++++++++++++++++++-
 cogl/cogl-overlay-private.h       |   76 ++++++++++
 cogl/cogl-overlay.c               |  249 ++++++++++++++++++++++++++++++++
 cogl/cogl-overlay.h               |  114 +++++++++++++++
 cogl/cogl-pixel-buffer.h          |    7 +-
 cogl/cogl-renderer-private.h      |    3 +
 cogl/cogl-renderer.c              |   89 +++++++++++-
 cogl/cogl-renderer.h              |   27 ++++-
 cogl/cogl-xlib-renderer.c         |  123 ++++++----------
 cogl/cogl.h                       |    1 +
 cogl/winsys/cogl-winsys-egl-kms.c |  269 +++++++++++++++++++++++++++++------
 cogl/winsys/cogl-winsys-private.h |   12 ++
 22 files changed, 1595 insertions(+), 160 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index ff0f0c6..23452ed 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -59,6 +59,8 @@ DISTCLEANFILES += $(pc_files)
 
 # public api headers
 cogl_public_h = \
+       $(srcdir)/cogl-mode.h                   \
+       $(srcdir)/cogl-overlay.h                \
        $(srcdir)/cogl-attribute-buffer.h       \
        $(srcdir)/cogl-attribute.h              \
        $(srcdir)/cogl-bitmap.h                 \
@@ -365,6 +367,9 @@ cogl_sources_c = \
        $(srcdir)/cogl-closure-list.c                   \
        $(srcdir)/cogl-fence.c                          \
        $(srcdir)/cogl-fence-private.h                  \
+       $(srcdir)/cogl-overlay-private.h                \
+       $(srcdir)/cogl-overlay.c                        \
+       $(srcdir)/cogl-mode.c                           \
        $(NULL)
 
 if USE_GLIB
diff --git a/cogl/cogl-bitmap.h b/cogl/cogl-bitmap.h
index 8a91bab..5e4772e 100644
--- a/cogl/cogl-bitmap.h
+++ b/cogl/cogl-bitmap.h
@@ -28,6 +28,10 @@
 #ifndef __COGL_BITMAP_H__
 #define __COGL_BITMAP_H__
 
+/* We forward declare the CoglBitmap type here to help deal with
+ * circular type references between headers. */
+typedef struct _CoglBitmap CoglBitmap;
+
 #include <cogl/cogl-types.h>
 #include <cogl/cogl-buffer.h>
 #include <cogl/cogl-context.h>
@@ -39,8 +43,6 @@
 
 COGL_BEGIN_DECLS
 
-typedef struct _CoglBitmap CoglBitmap;
-
 /**
  * SECTION:cogl-bitmap
  * @short_description: Functions for loading images
diff --git a/cogl/cogl-frame-info.h b/cogl/cogl-frame-info.h
index 36f8a04..f20d085 100644
--- a/cogl/cogl-frame-info.h
+++ b/cogl/cogl-frame-info.h
@@ -31,13 +31,17 @@
 #ifndef __COGL_FRAME_INFO_H
 #define __COGL_FRAME_INFO_H
 
+/* We forward declare the CoglFrameInfo type here to avoid some
+ * circular dependency issues with the following headers.
+ */
+typedef struct _CoglFrameInfo CoglFrameInfo;
+
 #include <cogl/cogl-types.h>
 #include <cogl/cogl-output.h>
 #include <glib.h>
 
 G_BEGIN_DECLS
 
-typedef struct _CoglFrameInfo CoglFrameInfo;
 #define COGL_FRAME_INFO(X) ((CoglFrameInfo *)(X))
 
 /**
diff --git a/cogl/cogl-framebuffer.h b/cogl/cogl-framebuffer.h
index fde5c35..c94eb6c 100644
--- a/cogl/cogl-framebuffer.h
+++ b/cogl/cogl-framebuffer.h
@@ -43,6 +43,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
 #include <cogl/cogl-texture.h>
 #include <cogl/cogl-quaternion.h>
 #include <cogl/cogl-euler.h>
+#include <cogl/cogl-primitive.h>
 
 COGL_BEGIN_DECLS
 
diff --git a/cogl/cogl-mode-private.h b/cogl/cogl-mode-private.h
new file mode 100644
index 0000000..fddd1ca
--- /dev/null
+++ b/cogl/cogl-mode-private.h
@@ -0,0 +1,58 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef _COGL_MODE_PRIVATE_H_
+#define _COGL_MODE_PRIVATE_H_
+
+#include "cogl-mode.h"
+#include "cogl-object-private.h"
+
+struct _CoglMode
+{
+  CoglObjectClass _parent;
+
+  char *name;
+
+  /* NB: _cogl_mode_equal() expects everything from the width member
+   * to the end of the struct to be comparable using memcmp().
+   */
+  int width;
+  int height;
+
+  float refresh_rate;
+
+#if 0
+  uint32_t clock;
+  uint16_t hdisplay, hsync_start, hsync_end, htotal, hskew;
+  uint16_t vdisplay, vsync_start, vsync_end, vtotal, vscan;
+
+  uint32_t flags;
+  uint32_t type;
+#endif
+};
+
+CoglMode *
+_cogl_mode_new (const char *name);
+
+#endif /* _COGL_MODE_PRIVATE_H_ */
diff --git a/cogl/cogl-mode.c b/cogl/cogl-mode.c
new file mode 100644
index 0000000..d742609
--- /dev/null
+++ b/cogl/cogl-mode.c
@@ -0,0 +1,73 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#include <config.h>
+
+#include "cogl-mode-private.h"
+#include "cogl-object-private.h"
+
+static void _cogl_mode_free (CoglMode *mode);
+
+COGL_OBJECT_DEFINE (Mode, mode);
+
+static void
+_cogl_mode_free (CoglMode *mode)
+{
+  g_free (mode->name);
+  g_slice_free (CoglMode, mode);
+}
+
+CoglMode *
+_cogl_mode_new (const char *name)
+{
+  CoglMode *mode = g_slice_new0 (CoglMode);
+
+  mode->name = g_strdup (name);
+
+  return _cogl_mode_object_new (mode);
+}
+
+const char *
+cogl_mode_get_name (CoglMode *mode)
+{
+  return mode->name;
+}
+
+float
+cogl_mode_get_refresh_rate (CoglMode *mode)
+{
+  return mode->refresh_rate;
+}
+
+int
+cogl_mode_get_width (CoglMode *mode)
+{
+  return mode->width;
+}
+
+int
+cogl_mode_get_height (CoglMode *mode)
+{
+  return mode->height;
+}
diff --git a/cogl/cogl-mode.h b/cogl/cogl-mode.h
new file mode 100644
index 0000000..6d25f95
--- /dev/null
+++ b/cogl/cogl-mode.h
@@ -0,0 +1,51 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef _COGL_MODE_H_
+#define _COGL_MODE_H_
+
+#include <cogl/cogl-types.h>
+
+COGL_BEGIN_DECLS
+
+typedef struct _CoglMode CoglMode;
+
+CoglBool
+cogl_is_mode (void *object);
+
+const char *
+cogl_mode_get_name (CoglMode *mode);
+
+float
+cogl_mode_get_refresh_rate (CoglMode *mode);
+
+int
+cogl_mode_get_width (CoglMode *mode);
+
+int
+cogl_mode_get_height (CoglMode *mode);
+
+COGL_END_DECLS
+
+#endif /* _COGL_MODE_H_ */
diff --git a/cogl/cogl-onscreen.h b/cogl/cogl-onscreen.h
index d9582fa..b023158 100644
--- a/cogl/cogl-onscreen.h
+++ b/cogl/cogl-onscreen.h
@@ -32,6 +32,11 @@
 #ifndef __COGL_ONSCREEN_H
 #define __COGL_ONSCREEN_H
 
+/* We forward declare the CoglOnscreen type here to avoid some
+ * circular dependency issues with the following headers.
+ */
+typedef struct _CoglOnscreen CoglOnscreen;
+
 #include <cogl/cogl-context.h>
 #include <cogl/cogl-framebuffer.h>
 #include <cogl/cogl-frame-info.h>
@@ -39,7 +44,6 @@
 
 COGL_BEGIN_DECLS
 
-typedef struct _CoglOnscreen CoglOnscreen;
 #define COGL_ONSCREEN(X) ((CoglOnscreen *)(X))
 
 /**
diff --git a/cogl/cogl-output-private.h b/cogl/cogl-output-private.h
index f0e8d57..82bb491 100644
--- a/cogl/cogl-output-private.h
+++ b/cogl/cogl-output-private.h
@@ -24,24 +24,51 @@
 #ifndef __COGL_OUTPUT_PRIVATE_H
 #define __COGL_OUTPUT_PRIVATE_H
 
+#include <glib.h>
+
 #include "cogl-output.h"
 #include "cogl-object-private.h"
 
-struct _CoglOutput
+#warning "TODO: remove if not used in the end"
+typedef enum _CoglOutputChange
 {
-  CoglObject _parent;
+  COGL_OUTPUT_CHANGE_OVERLAYS = 1<<0,
+  COGL_OUTPUT_CHANGE_MODE = 1<<1,
+} CoglOutputChange;
 
+typedef struct _CoglOutputState
+{
   char *name;
 
-  int x; /* Must be first field for _cogl_output_values_equal() */
+  GList *overlays;
+
+  CoglMode *mode;
+
+  /* x must be first field for _cogl_output_state_equal()
+   * and all following members should be comparable using
+   * memcmp() */
+  int x;
   int y;
-  int width;
-  int height;
   int mm_width;
   int mm_height;
-  float refresh_rate;
   CoglSubpixelOrder subpixel_order;
 
+  CoglDpmsMode dpms_mode;
+
+#warning "TODO: remove if not used in the end"
+  CoglOutputChange changes;
+
+} CoglOutputState;
+
+struct _CoglOutput
+{
+  CoglObject _parent;
+
+  GList *modes;
+
+  CoglOutputState *pending;
+  CoglOutputState *state;
+
   void *winsys;
   CoglUserDataDestroyCallback winsys_destroy_callback;
 };
@@ -54,8 +81,11 @@ _cogl_output_set_winsys_data (CoglOutput *output,
                               void *winsys,
                               CoglUserDataDestroyCallback destroy_callback);
 
+void
+_cogl_output_update_state (CoglOutput *output);
+
 CoglBool
-_cogl_output_values_equal (CoglOutput *output,
-                           CoglOutput *other);
+_cogl_output_equal (CoglOutput *output,
+                    CoglOutput *other);
 
 #endif /* __COGL_OUTPUT_PRIVATE_H */
diff --git a/cogl/cogl-output.c b/cogl/cogl-output.c
index bf2ba21..cd79f5a 100644
--- a/cogl/cogl-output.c
+++ b/cogl/cogl-output.c
@@ -24,6 +24,8 @@
 #include <config.h>
 
 #include "cogl-output-private.h"
+#include "cogl-overlay-private.h"
+#include "cogl-mode-private.h"
 
 #include <string.h>
 
@@ -37,18 +39,40 @@ _cogl_output_new (const char *name)
   CoglOutput *output;
 
   output = g_slice_new0 (CoglOutput);
-  output->name = g_strdup (name);
+
+  output->state = g_slice_new0 (CoglOutputState);
+  output->state->name = g_strdup (name);
+
+  output->pending = output->state;
 
   return _cogl_output_object_new (output);
 }
 
 static void
+free_output_state (CoglOutputState *state)
+{
+  GList *l;
+
+  for (l = state->overlays; l; l = l->next)
+    cogl_object_unref (l->data);
+  g_list_free (state->overlays);
+
+  g_free (state->name);
+
+  g_slice_free (CoglOutputState, state);
+}
+
+static void
 _cogl_output_free (CoglOutput *output)
 {
   if (output->winsys_destroy_callback)
     output->winsys_destroy_callback (output->winsys);
 
-  g_free (output->name);
+  if (output->pending != output->state)
+    free_output_state (output->pending);
+
+  free_output_state (output->state);
+
   g_slice_free (CoglOutput, output);
 }
 
@@ -61,59 +85,291 @@ _cogl_output_set_winsys_data (CoglOutput *output,
   output->winsys_destroy_callback = destroy_callback;
 }
 
-gboolean
-_cogl_output_values_equal (CoglOutput *output,
-                           CoglOutput *other)
+static CoglBool
+_cogl_mode_equal (CoglMode *mode0, CoglMode *mode1)
+{
+  if (memcmp ((const char *)mode0 + G_STRUCT_OFFSET (CoglMode, width),
+              (const char *)mode1 + G_STRUCT_OFFSET (CoglMode, width),
+              sizeof (CoglMode) - G_STRUCT_OFFSET (CoglMode, width)) != 0)
+    return FALSE;
+
+  return TRUE;
+}
+
+static CoglBool
+_cogl_mode_lists_equal (GList *modes0, GList *modes1)
 {
-  return memcmp ((const char *)output + G_STRUCT_OFFSET (CoglOutput, x),
-                 (const char *)other + G_STRUCT_OFFSET (CoglOutput, x),
-                 sizeof (CoglOutput) - G_STRUCT_OFFSET (CoglOutput, x)) == 0;
+  GList *l, *m;
+
+  for (l = modes0, m = modes1;
+       l && m;
+       l = l->next, m = m->next)
+    {
+      if (!_cogl_mode_equal (l->data, m->data))
+        return FALSE;
+    }
+
+  if (l || m)
+    return FALSE;
+
+  return TRUE;
+}
+
+CoglBool
+_cogl_output_equal (CoglOutput *output,
+                    CoglOutput *other)
+{
+  GList *l, *l2;
+
+  if (output == other)
+    return TRUE;
+
+  if (!_cogl_mode_lists_equal (output->modes, other->modes))
+    return FALSE;
+
+  if (!_cogl_mode_equal (output->pending->mode, other->pending->mode))
+    return FALSE;
+
+  if (memcmp ((const char *)output->pending +
+              G_STRUCT_OFFSET (CoglOutputState, x),
+              (const char *)other->pending +
+              G_STRUCT_OFFSET (CoglOutputState, x),
+              sizeof (CoglOutputState) -
+              G_STRUCT_OFFSET (CoglOutputState, x)) != 0)
+    return FALSE;
+
+  for (l = output->pending->overlays, l2 = other->pending->overlays;
+       l && l2;
+       l = l->next, l2 = l2->next)
+    {
+      if (!_cogl_overlay_equal (l->data, l2->data))
+        return FALSE;
+    }
+
+  if (l || l2)
+    return FALSE;
+
+  return TRUE;
 }
 
 int
 cogl_output_get_x (CoglOutput *output)
 {
-  return output->x;
+  return output->pending->x;
 }
 
 int
 cogl_output_get_y (CoglOutput *output)
 {
-  return output->y;
+  return output->pending->y;
 }
 
 int
 cogl_output_get_width (CoglOutput *output)
 {
-  return output->width;
+  return output->pending->mode->width;
 }
 
 int
 cogl_output_get_height (CoglOutput *output)
 {
-  return output->height;
+  return output->pending->mode->height;
 }
 
 int
 cogl_output_get_mm_width (CoglOutput *output)
 {
-  return output->mm_width;
+  return output->pending->mm_width;
 }
 
 int
 cogl_output_get_mm_height (CoglOutput *output)
 {
-  return output->mm_height;
+  return output->pending->mm_height;
 }
 
 CoglSubpixelOrder
 cogl_output_get_subpixel_order (CoglOutput *output)
 {
-  return output->subpixel_order;
+  return output->pending->subpixel_order;
 }
 
 float
 cogl_output_get_refresh_rate (CoglOutput *output)
 {
-  return output->refresh_rate;
+  return output->pending->mode->refresh_rate;
+}
+
+CoglOverlay *
+cogl_output_get_overlay0 (CoglOutput *output)
+{
+  return output->pending->overlays->data;
+}
+
+static void
+ensure_pending_state (CoglOutput *output)
+{
+  CoglOutputState *state = output->state;
+  CoglOutputState *pending;
+
+  if (output->pending != state)
+    return;
+
+  pending = g_slice_dup (CoglOutputState, state);
+  pending->name = g_strdup (state->name);
+  pending->overlays = g_list_copy (state->overlays);
+
+  output->pending = state;
+}
+
+void
+_cogl_output_update_state (CoglOutput *output)
+{
+  if (output->pending == output->state)
+    return;
+
+  free_output_state (output->state);
+
+  output->state = output->pending;
+}
+
+void
+cogl_output_append_overlay (CoglOutput *output,
+                            CoglOverlay *overlay)
+{
+  ensure_pending_state (output);
+
+  output->pending->overlays =
+    g_list_append (output->pending->overlays, overlay);
+}
+
+void
+cogl_output_put_overlay_above (CoglOutput *output,
+                               CoglOverlay *overlay,
+                               CoglOverlay *sibling)
+{
+  GList *l;
+
+  ensure_pending_state (output);
+
+  if (sibling)
+    {
+      l = g_list_find (output->pending->overlays, sibling);
+
+      _COGL_RETURN_IF_FAIL (l != NULL);
+
+      l = l->next;
+    }
+  else
+    l = NULL;
+
+  output->pending->overlays =
+    g_list_insert_before (output->pending->overlays,
+                          l,
+                          overlay);
+}
+
+void
+cogl_output_put_overlay_below (CoglOutput *output,
+                               CoglOverlay *overlay,
+                               CoglOverlay *sibling)
+{
+  GList *l;
+
+  ensure_pending_state (output);
+
+  if (sibling)
+    {
+      l = g_list_find (output->pending->overlays, sibling);
+
+      _COGL_RETURN_IF_FAIL (l != NULL);
+    }
+  else
+    l = NULL;
+
+  output->pending->overlays =
+    g_list_insert_before (output->pending->overlays,
+                          l,
+                          overlay);
+}
+
+void
+cogl_output_remove_overlay (CoglOutput *output,
+                            CoglOverlay *overlay)
+{
+  GList *l;
+
+  ensure_pending_state (output);
+
+  l = g_list_find (output->pending->overlays, overlay);
+
+  _COGL_RETURN_IF_FAIL (l != NULL);
+
+  cogl_object_unref (l->data);
+
+  output->pending->overlays =
+    g_list_delete_link (output->pending->overlays, l);
+}
+
+void
+cogl_output_foreach_mode (CoglOutput *output,
+                          CoglOutputModeCallback callback,
+                          void *user_data)
+{
+  GList *l;
+  for (l = output->modes; l; l = l->next)
+    callback (l->data, user_data);
+}
+
+void
+cogl_output_set_mode (CoglOutput *output,
+                      CoglMode *mode)
+{
+  _COGL_RETURN_IF_FAIL (mode);
+
+  if (_cogl_mode_equal (output->pending->mode, mode))
+    return;
+
+  ensure_pending_state (output);
+
+  if (output->pending->mode)
+    cogl_object_unref (output->pending->mode);
+
+  output->pending->mode = cogl_object_ref (mode);
+}
+
+CoglMode *
+cogl_output_get_mode (CoglOutput *output)
+{
+  _COGL_RETURN_VAL_IF_FAIL (output->pending->mode, NULL);
+
+  return output->pending->mode;
+}
+
+void
+cogl_output_set_dpms_mode (CoglOutput *output,
+                           CoglDpmsMode dpms_mode)
+{
+  if (output->pending->dpms_mode == dpms_mode)
+    return;
+
+  ensure_pending_state (output);
+
+  output->pending->dpms_mode = dpms_mode;
+}
+
+CoglDpmsMode
+cogl_output_get_dpms_mode (CoglOutput *output)
+{
+  return output->pending->dpms_mode;
+}
+
+void
+cogl_output_foreach_overlay (CoglOutput *output,
+                             CoglOutputOverlayCallback callback,
+                             void *user_data)
+{
+  GList *l;
+  for (l = output->pending->overlays; l; l = l->next)
+    callback (l->data, user_data);
 }
diff --git a/cogl/cogl-output.h b/cogl/cogl-output.h
index 473a5cc..7966fd8 100644
--- a/cogl/cogl-output.h
+++ b/cogl/cogl-output.h
@@ -31,7 +31,14 @@
 #ifndef __COGL_OUTPUT_H
 #define __COGL_OUTPUT_H
 
+/* We forward declare the CoglOutput type here to avoid some circular
+ * dependency issues with the following headers.
+ */
+typedef struct _CoglOutput CoglOutput;
+
 #include <cogl/cogl-types.h>
+#include <cogl/cogl-overlay.h>
+#include <cogl/cogl-mode.h>
 
 COGL_BEGIN_DECLS
 
@@ -57,7 +64,6 @@ COGL_BEGIN_DECLS
  * to the #CoglOnscreen.
  */
 
-typedef struct _CoglOutput CoglOutput;
 #define COGL_OUTPUT(X) ((CoglOutput *)(X))
 
 /**
@@ -234,6 +240,243 @@ cogl_output_get_subpixel_order (CoglOutput *output);
 float
 cogl_output_get_refresh_rate (CoglOutput *output);
 
+/**
+ * cogl_output_get_overlay0:
+ * @output: a #CoglOutput
+ *
+ * Queries the first, base overlay associated with the given @output.
+ *
+ * Return value: A pointer to the first #CoglOverlay associated with
+ *               @output.
+ * Since: 1.16
+ * Stability: unstable
+ */
+CoglOverlay *
+cogl_output_get_overlay0 (CoglOutput *output);
+
+/**
+ * cogl_output_append_overlay:
+ * @output: a #CoglOutput
+ * @overlay: A #CoglOverlay to add
+ *
+ * Stacks @overlay above all the other overlays currently associated
+ * with the given @output.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_append_overlay (CoglOutput *output,
+                            CoglOverlay *overlay);
+
+/**
+ * cogl_output_put_overlay_above:
+ * @output: a #CoglOutput
+ * @overlay: A #CoglOverlay to position
+ * @sibling: A #CoglOverlay to position @overlay above or %NULL
+ *
+ * Stacks @overlay above @sibling. If @sibling is %NULL then @overlay
+ * is stacked at the lowest position.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_put_overlay_above (CoglOutput *output,
+                               CoglOverlay *overlay,
+                               CoglOverlay *sibling);
+
+/**
+ * cogl_output_put_overlay_below:
+ * @output: a #CoglOutput
+ * @overlay: A #CoglOverlay to position
+ * @sibling: A #CoglOverlay to position @overlay below or %NULL
+ *
+ * Stacks @overlay below @sibling. If @sibling is %NULL then @overlay
+ * is stacked at the highest position.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_put_overlay_below (CoglOutput *output,
+                               CoglOverlay *overlay,
+                               CoglOverlay *sibling);
+
+/**
+ * cogl_output_remove_overlay:
+ * @output: a #CoglOutput
+ * @overlay: A #CoglOverlay to remove
+ *
+ * Removes @overlay from the given @output.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_remove_overlay (CoglOutput *output,
+                            CoglOverlay *overlay);
+
+/**
+ * CoglOutputModeCallback:
+ * @overlay: The current overlay being iterated
+ * @user_data: The private data passed to
+ *             cogl_output_foreach_mode()
+ *
+ * A callback type for use with cogl_output_foreach_mode()
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef void (*CoglOutputModeCallback) (CoglMode *mode,
+                                        void *user_data);
+
+/**
+ * cogl_output_foreach_mode:
+ * @output: a #CoglOutput
+ * @callback: A #CoglOutputModeCallback to call for each mode.
+ * @user_data: A private pointer to pass to @callback
+ *
+ * Iterates through the possible #CoglMode<!-- -->'s usable with @output.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_foreach_mode (CoglOutput *output,
+                          CoglOutputModeCallback callback,
+                          void *user_data);
+
+/**
+ * cogl_output_set_mode:
+ * @output: a #CoglOutput
+ * @mode: A #CoglMode
+ *
+ * Requests to set the given @mode on the given @output the next
+ * time output configurations are comitted via
+ * cogl_renderer_commit_outputs().
+ *
+ * <note>@mode should be a mode that was found via
+ * cogl_output_foreach_mode()</note>
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_set_mode (CoglOutput *output,
+                      CoglMode *mode);
+
+/**
+ * cogl_output_get_mode:
+ * @output: a #CoglOutput
+ *
+ * Queries the mode that's currently set on the given @output.
+ *
+ * <note>If the mode is set via cogl_output_set_mode() but
+ * cogl_renderer_commit_outputs() hasn't since been called then this
+ * will return the last set mode, which might not correspond to the
+ * outputs actual mode.</note>
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+CoglMode *
+cogl_output_get_mode (CoglOutput *output);
+
+/**
+ * CoglDpmsMode:
+ * @COGL_DPMS_MODE_ON: Set when the display is use
+ * @COGL_DPMS_MODE_STANDBY: Uses less than 80% of the power compared
+ *                          to @COGL_DPMS_MODE_ON. Recovery time about
+ *                          1 second.
+ * @COGL_DPMS_MODE_SUSPEND: Uses less the 30W. Recovery time may be
+ *                          about 5 seconds.
+ * @COGL_DPMS_MODE_OFF: Uses less than 8W. Recovery time may be about
+ *                      20 seconds.
+ *
+ * Standard VESA Display Power Management modes that can be controlled
+ * for each #CoglOutput via cogl_output_set_dpms_mode().
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef enum _CoglDpmsMode
+{
+  COGL_DPMS_MODE_ON,
+  COGL_DPMS_MODE_STANDBY,
+  COGL_DPMS_MODE_SUSPEND,
+  COGL_DPMS_MODE_OFF,
+} CoglDpmsMode;
+
+/**
+ * cogl_output_set_dpms_mode:
+ * @output: a #CoglOutput
+ * @dpms_mode: A #CoglDpmsMode
+ *
+ * Requests to set the given @dpms_mode on the given @output the next
+ * time that cogl_renderer_commit_outputs() is called.
+ *
+ * This can be used to save power when a display is not in active
+ * use.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_set_dpms_mode (CoglOutput *output,
+                           CoglDpmsMode dpms_mode);
+
+/**
+ * cogl_output_get_dpms_mode:
+ * @output: a #CoglOutput
+ *
+ * Queries the dpms mode last set on @output.
+ *
+ * <note>If the dpms mode has been set with
+ * cogl_output_set_dpms_mode() but cogl_renderer_commit_outputs()
+ * hasn't since been called then this will return the last set
+ * dpms mode that might not correspond to the actual state of
+ * @output.<note.
+ *
+ * Return value: The dpms mode set on @output.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+CoglDpmsMode
+cogl_output_get_dpms_mode (CoglOutput *output);
+
+/**
+ * CoglOutputOverlayCallback:
+ * @overlay: The current overlay being iterated
+ * @user_data: The private data passed to
+ *             cogl_output_foreach_overlay()
+ *
+ * A callback type for use with cogl_output_foreach_overlay()
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+typedef void (*CoglOutputOverlayCallback) (CoglOverlay *overlay,
+                                           void *user_data);
+
+/**
+ * cogl_output_foreach_overlay:
+ * @output: a #CoglOutput
+ * @callback: A #CoglOutputOverlayCallback to call for each overlay.
+ * @user_data: A private pointer to pass to @callback
+ *
+ * Iterates through the current @output overlays, starting from
+ * overlay 0.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+void
+cogl_output_foreach_overlay (CoglOutput *output,
+                             CoglOutputOverlayCallback callback,
+                             void *user_data);
+
 COGL_END_DECLS
 
 #endif /* __COGL_OUTPUT_H */
diff --git a/cogl/cogl-overlay-private.h b/cogl/cogl-overlay-private.h
new file mode 100644
index 0000000..1943a9a
--- /dev/null
+++ b/cogl/cogl-overlay-private.h
@@ -0,0 +1,76 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef _COGL_OVERLAY_PRIVATE_H_
+#define _COGL_OVERLAY_PRIVATE_H_
+
+#include <cogl/cogl-overlay.h>
+
+typedef enum _CoglOverlayChange
+{
+  COGL_OVERLAY_CHANGE_SOURCE = 1<<0,
+  COGL_OVERLAY_CHANGE_TRANSFORM = 1<<1,
+} CoglOverlayChange;
+
+typedef struct _CoglOverlayState
+{
+  /* NB: to avoid a circular reference we don't keep a reference
+   * here... */
+  CoglOutput *output;
+
+  /* Note: In the future we might support other sources, such as for
+   * video */
+  CoglOnscreen *onscreen_source;
+
+  /* XXX: src_x must be the first member for _cogl_overlay_equal() to
+   * work and all remaining members should be comparable via
+   * memcpy() */
+
+  /* What region of the source should be overlayed? */
+  int src_x;
+  int src_y;
+  int src_width;
+  int src_height;
+
+  int dst_x;
+  int dst_y;
+
+} CoglOverlayState;
+
+struct _CoglOverlay
+{
+  CoglObjectClass _parent;
+
+  CoglOverlayState *state;
+  CoglOverlayState *pending;
+};
+
+void
+_cogl_overlay_update_state (CoglOverlay *overlay);
+
+CoglBool
+_cogl_overlay_equal (CoglOverlay *overlay0,
+                     CoglOverlay *overlay1);
+
+#endif /* _COGL_OVERLAY_PRIVATE_H_ */
diff --git a/cogl/cogl-overlay.c b/cogl/cogl-overlay.c
new file mode 100644
index 0000000..0abe621
--- /dev/null
+++ b/cogl/cogl-overlay.c
@@ -0,0 +1,249 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include "cogl-object-private.h"
+#include "cogl-overlay-private.h"
+#include "cogl-onscreen.h"
+
+static void _cogl_overlay_free (CoglOverlay *overlay);
+
+COGL_OBJECT_DEFINE (Overlay, overlay);
+
+static void
+free_overlay_state (CoglOverlayState *state)
+{
+  if (state->onscreen_source)
+    cogl_object_unref (state->onscreen_source);
+
+  g_slice_free (CoglOverlayState, state);
+}
+
+static void
+ensure_pending_state (CoglOverlay *overlay)
+{
+  CoglOverlayState *state = overlay->state;
+  CoglOverlayState *pending;
+
+  if (state != overlay->pending)
+    return;
+
+  pending = g_slice_dup (CoglOverlayState, state);
+
+  pending->onscreen_source = state->onscreen_source;
+  if (pending->onscreen_source)
+    cogl_object_ref (pending->onscreen_source);
+
+  overlay->pending = pending;
+}
+
+static void
+_cogl_overlay_free (CoglOverlay *overlay)
+{
+  if (overlay->pending != overlay->state)
+    free_overlay_state (overlay->pending);
+
+  free_overlay_state (overlay->state);
+
+  g_slice_free (CoglOverlay, overlay);
+}
+
+CoglOverlay *
+cogl_overlay_new (CoglOutput *output)
+{
+  CoglOverlay *overlay = g_slice_new0 (CoglOverlay);
+
+  overlay->state = g_slice_new0 (CoglOverlayState);
+
+  /* Note: to avoid a circular reference we don't reference
+   * the output here. */
+  overlay->state->output = output;
+
+  overlay->pending = overlay->state;
+
+  overlay = _cogl_overlay_object_new (overlay);
+
+  cogl_output_append_overlay (output, overlay);
+
+  return overlay;
+}
+
+void
+_cogl_overlay_update_state (CoglOverlay *overlay)
+{
+  if (overlay->pending == overlay->state)
+    return;
+
+  free_overlay_state (overlay->state);
+
+  overlay->state = overlay->pending;
+}
+
+void
+cogl_overlay_set_onscreen_source (CoglOverlay *overlay,
+                                  CoglOnscreen *onscreen_source)
+{
+  if (overlay->pending->onscreen_source == onscreen_source)
+    return;
+
+  ensure_pending_state (overlay);
+
+  if (overlay->pending->onscreen_source)
+    cogl_object_unref (overlay->pending->onscreen_source);
+
+  overlay->pending->onscreen_source = cogl_object_ref (onscreen_source);
+}
+
+CoglOnscreen *
+cogl_overlay_get_onscreen_source (CoglOverlay *overlay)
+{
+  return overlay->pending->onscreen_source;
+}
+
+int
+cogl_overlay_get_source_x (CoglOverlay *overlay)
+{
+  return overlay->pending->src_x;
+}
+
+void
+cogl_overlay_set_source_x (CoglOverlay *overlay, int src_x)
+{
+  if (overlay->pending->src_x == src_x)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->src_x = src_x;
+}
+
+int
+cogl_overlay_get_source_y (CoglOverlay *overlay)
+{
+  return overlay->pending->src_y;
+}
+
+void
+cogl_overlay_set_source_y (CoglOverlay *overlay, int src_y)
+{
+  if (overlay->pending->src_y == src_y)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->src_y = src_y;
+}
+
+int
+cogl_overlay_get_source_width (CoglOverlay *overlay)
+{
+  return overlay->pending->src_width;
+}
+
+void
+cogl_overlay_set_source_width (CoglOverlay *overlay, int src_width)
+{
+  if (overlay->pending->src_width == src_width)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->src_width = src_width;
+}
+
+int
+cogl_overlay_get_source_height (CoglOverlay *overlay)
+{
+  return overlay->pending->src_height;
+}
+
+void
+cogl_overlay_set_source_height (CoglOverlay *overlay, int src_height)
+{
+  if (overlay->pending->src_height == src_height)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->src_height = src_height;
+}
+
+int
+cogl_overlay_get_x (CoglOverlay *overlay)
+{
+  return overlay->pending->dst_x;
+}
+
+void
+cogl_overlay_set_x (CoglOverlay *overlay, int dst_x)
+{
+  if (overlay->pending->dst_x == dst_x)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->dst_x = dst_x;
+}
+
+int
+cogl_overlay_get_y (CoglOverlay *overlay)
+{
+  return overlay->pending->dst_y;
+}
+
+void
+cogl_overlay_set_y (CoglOverlay *overlay, int dst_y)
+{
+  if (overlay->pending->dst_y == dst_y)
+    return;
+
+  ensure_pending_state (overlay);
+
+  overlay->pending->dst_y = dst_y;
+}
+
+CoglBool
+_cogl_overlay_equal (CoglOverlay *overlay0,
+                     CoglOverlay *overlay1)
+{
+  if (overlay0 == overlay1)
+    return TRUE;
+
+  if (memcmp ((const char *)overlay0->pending +
+              G_STRUCT_OFFSET (CoglOverlayState, src_x),
+              (const char *)overlay1->pending +
+              G_STRUCT_OFFSET (CoglOverlayState, src_x),
+              sizeof (CoglOverlayState) -
+              G_STRUCT_OFFSET (CoglOverlayState, src_x)) != 0)
+    return FALSE;
+
+  if (overlay0->pending->onscreen_source !=
+      overlay1->pending->onscreen_source)
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/cogl/cogl-overlay.h b/cogl/cogl-overlay.h
new file mode 100644
index 0000000..1a3c793
--- /dev/null
+++ b/cogl/cogl-overlay.h
@@ -0,0 +1,114 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ *
+ */
+
+#ifndef _COGL_OVERLAY_H_
+#define _COGL_OVERLAY_H_
+
+/* We forward declare the CoglOverlay type here to avoid some
+ * circular dependency issues with the following headers.
+ */
+typedef struct _CoglOverlay CoglOverlay;
+
+#include <cogl/cogl-onscreen.h>
+#include <cogl/cogl-output.h>
+
+COGL_BEGIN_DECLS
+
+/**
+ * SECTION:cogl-overlay
+ * @short_description: A single overlay to composite on a #CoglOutput
+ *
+ * A #CoglOverlay represents a single image source to composite on a
+ * given #CoglOutput. Depending on the capabilities of the output an
+ * overlay can - for example - be offset and scaled within that
+ * output.
+ *
+ * If an output can be composited with overlyas using dedicated,
+ * fixed-function hardware then it can be more power effecient than
+ * compositing with the more general purpose GPU pipeline.
+ */
+
+CoglBool cogl_is_overlay (void *object);
+
+/**
+ * cogl_overlay_new:
+ * @output: A #CoglOutput pointer
+ *
+ * Creates a new #CoglOverlay that is associated with the given @output,
+ * positioned on top of any existing overlays.
+ *
+ * Return value: A newly allocated #CoglOverlay.
+ *
+ * Since: 1.16
+ * Stability: unstable
+ */
+CoglOverlay *
+cogl_overlay_new (CoglOutput *output);
+
+void
+cogl_overlay_set_onscreen_source (CoglOverlay *overlay,
+                                  CoglOnscreen *onscreen_source);
+
+CoglOnscreen *
+cogl_overlay_get_onscreen_source (CoglOverlay *overlay);
+
+int
+cogl_overlay_get_source_x (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_source_x (CoglOverlay *overlay, int src_x);
+
+int
+cogl_overlay_get_source_y (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_source_y (CoglOverlay *overlay, int src_y);
+
+int
+cogl_overlay_get_source_width (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_source_width (CoglOverlay *overlay, int src_width);
+
+int
+cogl_overlay_get_source_height (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_source_height (CoglOverlay *overlay, int src_height);
+
+int
+cogl_overlay_get_x (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_x (CoglOverlay *overlay, int dst_x);
+
+int
+cogl_overlay_get_y (CoglOverlay *overlay);
+
+void
+cogl_overlay_set_y (CoglOverlay *overlay, int dst_y);
+
+COGL_END_DECLS
+
+#endif /* _COGL_OVERLAY_H_ */
diff --git a/cogl/cogl-pixel-buffer.h b/cogl/cogl-pixel-buffer.h
index 0e5ea38..a8fc97b 100644
--- a/cogl/cogl-pixel-buffer.h
+++ b/cogl/cogl-pixel-buffer.h
@@ -32,6 +32,11 @@
 #ifndef __COGL_PIXEL_BUFFER_H__
 #define __COGL_PIXEL_BUFFER_H__
 
+/* We forward declare the CoglPixelBuffer type here to avoid some
+ * circular dependency issues with the following headers.
+ */
+typedef struct _CoglPixelBuffer CoglPixelBuffer;
+
 #include <cogl/cogl-types.h>
 #include <cogl/cogl-context.h>
 
@@ -39,8 +44,6 @@ COGL_BEGIN_DECLS
 
 #define COGL_PIXEL_BUFFER(buffer) ((CoglPixelBuffer *)(buffer))
 
-typedef struct _CoglPixelBuffer CoglPixelBuffer;
-
 /**
  * cogl_pixel_buffer_new:
  * @context: A #CoglContext
diff --git a/cogl/cogl-renderer-private.h b/cogl/cogl-renderer-private.h
index 1816588..731f997 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -113,4 +113,7 @@ _cogl_renderer_get_proc_address (CoglRenderer *renderer,
                                  const char *name,
                                  CoglBool in_core);
 
+void
+_cogl_renderer_notify_outputs_changed (CoglRenderer *renderer);
+
 #endif /* __COGL_RENDERER_PRIVATE_H */
diff --git a/cogl/cogl-renderer.c b/cogl/cogl-renderer.c
index c5a2940..64215ca 100644
--- a/cogl/cogl-renderer.c
+++ b/cogl/cogl-renderer.c
@@ -44,6 +44,7 @@
 #include "cogl-winsys-stub-private.h"
 #include "cogl-config-private.h"
 #include "cogl-error-private.h"
+#include "cogl-output-private.h"
 
 #ifdef COGL_HAS_EGL_PLATFORM_XLIB_SUPPORT
 #include "cogl-winsys-egl-x11-private.h"
@@ -111,7 +112,7 @@ static CoglDriverDescription _cogl_drivers[] =
   {
     COGL_DRIVER_GL3,
     "gl3",
-    0,
+    COGL_RENDERER_CONSTRAINT_USES_KMS,
     COGL_PRIVATE_FEATURE_ANY_GL |
       COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE,
     &_cogl_driver_gl,
@@ -121,7 +122,7 @@ static CoglDriverDescription _cogl_drivers[] =
   {
     COGL_DRIVER_GL,
     "gl",
-    0,
+    COGL_RENDERER_CONSTRAINT_USES_KMS,
     COGL_PRIVATE_FEATURE_ANY_GL |
       COGL_PRIVATE_FEATURE_GL_FIXED |
       COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE,
@@ -134,7 +135,8 @@ static CoglDriverDescription _cogl_drivers[] =
   {
     COGL_DRIVER_GLES2,
     "gles2",
-    COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2,
+    COGL_RENDERER_CONSTRAINT_SUPPORTS_COGL_GLES2 |
+      COGL_RENDERER_CONSTRAINT_USES_KMS,
     COGL_PRIVATE_FEATURE_ANY_GL |
       COGL_PRIVATE_FEATURE_GL_EMBEDDED |
       COGL_PRIVATE_FEATURE_GL_PROGRAMMABLE,
@@ -147,7 +149,7 @@ static CoglDriverDescription _cogl_drivers[] =
   {
     COGL_DRIVER_GLES1,
     "gles1",
-    0,
+    COGL_RENDERER_CONSTRAINT_USES_KMS,
     COGL_PRIVATE_FEATURE_ANY_GL |
       COGL_PRIVATE_FEATURE_GL_EMBEDDED |
       COGL_PRIVATE_FEATURE_GL_FIXED,
@@ -173,7 +175,7 @@ static CoglDriverDescription _cogl_drivers[] =
   {
     COGL_DRIVER_NOP,
     "nop",
-    0, /* constraints satisfied */
+    COGL_RENDERER_CONSTRAINT_USES_KMS, /* constraints satisfied */
     0, /* flags */
     &_cogl_driver_nop,
     NULL, /* texture driver */
@@ -820,3 +822,80 @@ cogl_renderer_foreach_output (CoglRenderer *renderer,
   for (l = renderer->outputs; l; l = l->next)
     callback (l->data, user_data);
 }
+
+CoglBool
+cogl_renderer_commit_outputs (CoglRenderer *renderer,
+                              CoglError **error)
+{
+  CoglWinsysVtable *winsys;
+
+  _COGL_RETURN_IF_FAIL (!renderer->connected);
+
+  winsys = renderer->winsys;
+
+  if (winsys->commit_outputs)
+    return winsys->commit_outputs (renderer, error);
+  else
+    {
+      _cogl_set_error (error,
+                       COGL_SYSTEM_ERROR,
+                       COGL_SYSTEM_ERROR_UNSUPPORTED,
+                       "The current Cogl window system doesn't support "
+                       "display configuration");
+      return FALSE;
+    }
+}
+
+void
+_cogl_renderer_notify_outputs_changed (CoglRenderer *renderer)
+{
+  const CoglWinsysVtable *winsys = renderer->winsys_vtable;
+  GList *l;
+
+  COGL_NOTE (WINSYS, "Outputs changed:");
+
+  for (l = renderer->outputs; l; l = l->next)
+    {
+      CoglOutput *output = l->data;
+      const char *subpixel_string;
+
+      switch (output->state->subpixel_order)
+        {
+        case COGL_SUBPIXEL_ORDER_UNKNOWN:
+        default:
+          subpixel_string = "unknown";
+          break;
+        case COGL_SUBPIXEL_ORDER_NONE:
+          subpixel_string = "none";
+          break;
+        case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB:
+          subpixel_string = "horizontal_rgb";
+          break;
+        case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR:
+          subpixel_string = "horizontal_bgr";
+          break;
+        case COGL_SUBPIXEL_ORDER_VERTICAL_RGB:
+          subpixel_string = "vertical_rgb";
+          break;
+        case COGL_SUBPIXEL_ORDER_VERTICAL_BGR:
+          subpixel_string = "vertical_bgr";
+          break;
+        }
+
+      COGL_NOTE (WINSYS,
+                 " %10s: +%d+%dx%dx%d mm=%dx%d dpi=%.1fx%.1f "
+                 "subpixel_order=%s refresh_rate=%.3f",
+                 output->state->name,
+                 output->state->x, output->state->y,
+                 cogl_output_get_width (output),
+                 cogl_output_get_height (output),
+                 output->state->mm_width, output->state->mm_height,
+                 cogl_output_get_width (output) / (output->state->mm_width / 25.4),
+                 cogl_output_get_height (output) / (output->state->mm_height / 25.4),
+                 subpixel_string,
+                 cogl_output_get_refresh_rate (output));
+    }
+
+  if (winsys->renderer_outputs_changed)
+    winsys->renderer_outputs_changed (renderer);
+}
diff --git a/cogl/cogl-renderer.h b/cogl/cogl-renderer.h
index c7e6a5a..1f81faa 100644
--- a/cogl/cogl-renderer.h
+++ b/cogl/cogl-renderer.h
@@ -28,6 +28,11 @@
 #ifndef __COGL_RENDERER_H__
 #define __COGL_RENDERER_H__
 
+/* We forward declare the CoglRenderer type here to avoid some
+ * circular dependency issues with the following headers.
+ */
+typedef struct _CoglRenderer CoglRenderer;
+
 #include <cogl/cogl-types.h>
 #include <cogl/cogl-onscreen-template.h>
 #include <cogl/cogl-error.h>
@@ -78,8 +83,6 @@ COGL_BEGIN_DECLS
 uint32_t
 cogl_renderer_error_domain (void);
 
-typedef struct _CoglRenderer CoglRenderer;
-
 /**
  * cogl_is_renderer:
  * @object: A #CoglObject pointer
@@ -421,6 +424,26 @@ cogl_renderer_foreach_output (CoglRenderer *renderer,
                               CoglOutputCallback callback,
                               void *user_data);
 
+/**
+ * cogl_renderer_commit_outputs:
+ * @renderer: A connected #CoglRenderer
+ *
+ * Attempts to apply all outstanding #CoglOutput changes to the
+ * underlying hardware. If for some reason it is not possible to
+ * support the whole configuration then all outstanding changes
+ * will be reverted and a #CoglError will be returned.
+ *
+ * XXX: Instead of reverting the outstanding changes should we
+ * instead have a separate api for manually reverting outstanding
+ * changes?
+ *
+ * Since: 1.16
+ * Stability: Unstable
+ */
+CoglBool
+cogl_renderer_commit_outputs (CoglRenderer *renderer,
+                              CoglError **error);
+
 COGL_END_DECLS
 
 #endif /* __COGL_RENDERER_H__ */
diff --git a/cogl/cogl-xlib-renderer.c b/cogl/cogl-xlib-renderer.c
index 4d332fa..99f1f89 100644
--- a/cogl/cogl-xlib-renderer.c
+++ b/cogl/cogl-xlib-renderer.c
@@ -39,6 +39,7 @@
 #include "cogl-winsys-private.h"
 #include "cogl-error-private.h"
 #include "cogl-poll-private.h"
+#include "cogl-mode-private.h"
 
 #include <X11/Xlib.h>
 #include <X11/extensions/Xdamage.h>
@@ -198,7 +199,7 @@ static int
 compare_outputs (CoglOutput *a,
                  CoglOutput *b)
 {
-  return strcmp (a->name, b->name);
+  return strcmp (a->pending->name, b->pending->name);
 }
 
 #define CSO(X) COGL_SUBPIXEL_ORDER_ ## X
@@ -243,8 +244,9 @@ update_outputs (CoglRenderer *renderer,
     {
       XRRCrtcInfo *crtc_info = NULL;
       XRROutputInfo *output_info = NULL;
+      GList *new_modes = NULL;
+      CoglMode *current_mode = NULL;
       CoglOutput *output;
-      float refresh_rate = 0;
       int j;
 
       crtc_info = XRRGetCrtcInfo (xlib_renderer->xdpy,
@@ -260,10 +262,17 @@ update_outputs (CoglRenderer *renderer,
 
       for (j = 0; j < resources->nmode; j++)
         {
-          if (resources->modes[j].id == crtc_info->mode)
-            refresh_rate = (resources->modes[j].dotClock /
-                            ((float)resources->modes[j].hTotal *
-                             resources->modes[j].vTotal));
+          XRRModeInfo *info = &resources->modes[j];
+
+          CoglMode *mode = _cogl_mode_new (info->name);
+          mode->width = info->width;
+          mode->height = info->height;
+          mode->refresh_rate =
+            (info->dotClock / ((float)info->hTotal * info->vTotal));
+          new_modes = g_list_prepend (new_modes, mode);
+
+          if (info->id == crtc_info->mode)
+            current_mode = mode;
         }
 
       output_info = XRRGetOutputInfo (xlib_renderer->xdpy,
@@ -276,53 +285,51 @@ update_outputs (CoglRenderer *renderer,
         }
 
       output = _cogl_output_new (output_info->name);
-      output->x = crtc_info->x;
-      output->y = crtc_info->y;
-      output->width = crtc_info->width;
-      output->height = crtc_info->height;
+      output->modes = g_list_reverse (new_modes);
+      output->state->mode = cogl_object_ref (current_mode);
+      output->state->x = crtc_info->x;
+      output->state->y = crtc_info->y;
       if ((crtc_info->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0)
         {
-          output->mm_width = output_info->mm_height;
-          output->mm_height = output_info->mm_width;
+          output->state->mm_width = output_info->mm_height;
+          output->state->mm_height = output_info->mm_width;
         }
       else
         {
-          output->mm_width = output_info->mm_width;
-          output->mm_height = output_info->mm_height;
+          output->state->mm_width = output_info->mm_width;
+          output->state->mm_height = output_info->mm_height;
         }
 
-      output->refresh_rate = refresh_rate;
-
       switch (output_info->subpixel_order)
         {
         case SubPixelUnknown:
         default:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
           break;
         case SubPixelNone:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
           break;
         case SubPixelHorizontalRGB:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
           break;
         case SubPixelHorizontalBGR:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
           break;
         case SubPixelVerticalRGB:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
           break;
         case SubPixelVerticalBGR:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
           break;
         }
 
-      output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+      output->state->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
 
       /* Handle the effect of rotation and reflection on subpixel order (ugh) */
       for (j = 0; j < 6; j++)
         {
           if ((crtc_info->rotation & (1 << j)) != 0)
-            output->subpixel_order = subpixel_map[j][output->subpixel_order];
+            output->state->subpixel_order = subpixel_map[j][output->state->subpixel_order];
         }
 
       new_outputs = g_list_prepend (new_outputs, output);
@@ -350,6 +357,14 @@ update_outputs (CoglRenderer *renderer,
           CoglOutput *output_l = l ? (CoglOutput *)l->data : NULL;
           CoglOutput *output_m = m ? (CoglOutput *)m->data : NULL;
 
+          if (output_m && output_m->pending != output_m->state)
+            {
+              g_warning ("Unexpected pending state associated with CoglOutput "
+                         "%s while processing events. Pending output state "
+                         "shouldn't be maintained between mainloop "
+                         "iterations\n", output_m->state->name);
+            }
+
           if (l && m)
             cmp = compare_outputs (output_l, output_m);
           else if (l)
@@ -361,7 +376,7 @@ update_outputs (CoglRenderer *renderer,
             {
               GList *m_next = m->next;
 
-              if (!_cogl_output_values_equal (output_l, output_m))
+              if (!_cogl_output_equal (output_l, output_m))
                 {
                   renderer->outputs = g_list_remove_link (renderer->outputs, m);
                   renderer->outputs = g_list_insert_before (renderer->outputs,
@@ -396,57 +411,7 @@ update_outputs (CoglRenderer *renderer,
   _cogl_xlib_renderer_untrap_errors (renderer, &state);
 
   if (changed)
-    {
-      const CoglWinsysVtable *winsys = renderer->winsys_vtable;
-
-      if (notify)
-        COGL_NOTE (WINSYS, "Outputs changed:");
-      else
-        COGL_NOTE (WINSYS, "Outputs:");
-
-      for (l = renderer->outputs; l; l = l->next)
-        {
-          CoglOutput *output = l->data;
-          const char *subpixel_string;
-
-          switch (output->subpixel_order)
-            {
-            case COGL_SUBPIXEL_ORDER_UNKNOWN:
-            default:
-              subpixel_string = "unknown";
-              break;
-            case COGL_SUBPIXEL_ORDER_NONE:
-              subpixel_string = "none";
-              break;
-            case COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB:
-              subpixel_string = "horizontal_rgb";
-              break;
-            case COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR:
-              subpixel_string = "horizontal_bgr";
-              break;
-            case COGL_SUBPIXEL_ORDER_VERTICAL_RGB:
-              subpixel_string = "vertical_rgb";
-              break;
-            case COGL_SUBPIXEL_ORDER_VERTICAL_BGR:
-              subpixel_string = "vertical_bgr";
-              break;
-            }
-
-          COGL_NOTE (WINSYS,
-                     " %10s: +%d+%dx%dx%d mm=%dx%d dpi=%.1fx%.1f "
-                     "subpixel_order=%s refresh_rate=%.3f",
-                     output->name,
-                     output->x, output->y, output->width, output->height,
-                     output->mm_width, output->mm_height,
-                     output->width / (output->mm_width / 25.4),
-                     output->height / (output->mm_height / 25.4),
-                     subpixel_string,
-                     output->refresh_rate);
-        }
-
-      if (notify && winsys->renderer_outputs_changed != NULL)
-        winsys->renderer_outputs_changed (renderer);
-    }
+    _cogl_renderer_notify_outputs_changed (renderer);
 }
 
 static CoglFilterReturn
@@ -634,8 +599,10 @@ _cogl_xlib_renderer_output_for_rectangle (CoglRenderer *renderer,
   for (l = renderer->outputs; l; l = l->next)
     {
       CoglOutput *output = l->data;
-      int xb1 = output->x, xb2 = output->x + output->width;
-      int yb1 = output->y, yb2 = output->y + output->height;
+      int xb1 = output->state->x;
+      int xb2 = output->state->x + cogl_output_get_width (output);
+      int yb1 = output->state->y;
+      int yb2 = output->state->y + cogl_output_get_height (output);
 
       int overlap_x = MIN(xa2, xb2) - MAX(xa1, xb1);
       int overlap_y = MIN(ya2, yb2) - MAX(ya1, yb1);
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 304beed..371f23b 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -46,6 +46,7 @@
 #endif
 
 #include <cogl/cogl-renderer.h>
+#include <cogl/cogl-overlay.h>
 #include <cogl/cogl-output.h>
 #include <cogl/cogl-display.h>
 #include <cogl/cogl-context.h>
diff --git a/cogl/winsys/cogl-winsys-egl-kms.c b/cogl/winsys/cogl-winsys-egl-kms.c
index 02d3f8a..107a815 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -330,7 +330,6 @@ update_outputs (CoglRenderer *renderer)
     {
       CoglOutput *output = NULL;
       CoglOutputKMS *kms_output;
-      const char *type_name;
       GList *l;
 
       drmModeConnector *connector =
@@ -352,7 +351,7 @@ update_outputs (CoglRenderer *renderer)
         }
 
       /* If we already have a CoglOutput corresponding to this
-       * connector id then we can simply keep it and move on... */
+       * connector id then we keep it... */
       for (l = renderer->outputs; l; l = l->next)
         {
           CoglOutput *existing_output = l->data;
@@ -362,53 +361,82 @@ update_outputs (CoglRenderer *renderer)
             {
               renderer->outputs = g_list_delete_link (renderer->outputs, l);
               output = existing_output;
+              kms_output = output->winsys;
+
+              if (output->pending != output->state)
+                {
+                  g_warning ("Unexpected pending state associated with CoglOutput "
+                             "%s while processing events. Pending output state "
+                             "shouldn't be maintained between mainloop "
+                             "iterations\n", output->state->name);
+                }
+
+              break;
             }
         }
 
-      if (output)
+      if (!output)
         {
-          new_outputs = g_list_prepend (new_outputs, output);
-          drmModeFreeConnector (connector);
-          continue;
-        }
+          const char *type_name;
 
-      if (connector->connector_type < G_N_ELEMENTS (kms_connector_types))
-        type_name = kms_connector_types[connector->connector_type];
-      else
-        type_name = kms_connector_types[0];
+          if (connector->connector_type < G_N_ELEMENTS (kms_connector_types))
+            type_name = kms_connector_types[connector->connector_type];
+          else
+            type_name = kms_connector_types[0];
+
+          output = _cogl_output_new (type_name);
+
+          kms_output = g_slice_new0 (CoglOutputKMS);
+          kms_output->connector_id = connector->connector_id;
+          kms_output->connector = connector;
+
+          _cogl_output_set_winsys_data (output,
+                                        kms_output,
+                                        kms_output_destroy_cb);
+        }
 
-      output = _cogl_output_new (type_name);
+      for (j = 0; j < resources->count_modes; j++)
+        {
+          drmModeModeInfo *info = &resources->modes[j];
+
+          CoglMode *mode = _cogl_mode_new (info->name);
+          mode->width = info->hdisplay;
+          mode->height = info->vdisplay;
+          mode->refresh_rate =
+            (info->clock / ((float)info->htotal * info->vtotal));
+          new_modes = g_list_prepend (new_modes, mode);
+        }
 
-      kms_output = g_slice_new0 (CoglOutputKMS);
-      kms_output->connector_id = connector->connector_id;
-      kms_output->connector = connector;
+      if (output->modes)
+        g_list_free_full (output->modes, cogl_object_unref);
+      output->modes = g_list_reverse (new_modes);
 
       /* We can't determinine anything about the relative position
        * of the outputs... */
-      output->x = output->y = 0;
+      output->state->x = output->state->y = 0;
 
-      output->mm_width = connector->mmWidth;
-      output->mm_height = connector->mmHeight;
+      output->state->mm_width = connector->mmWidth;
+      output->state->mm_height = connector->mmHeight;
 
       switch (connector->subpixel)
         {
         case DRM_MODE_SUBPIXEL_UNKNOWN:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_UNKNOWN;
           break;
         case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_RGB;
           break;
         case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_HORIZONTAL_BGR;
           break;
         case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_RGB;
           break;
         case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_VERTICAL_BGR;
           break;
         case DRM_MODE_SUBPIXEL_NONE:
-          output->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
+          output->state->subpixel_order = COGL_SUBPIXEL_ORDER_NONE;
           break;
         }
 
@@ -435,29 +463,19 @@ update_outputs (CoglRenderer *renderer)
             }
         }
 
-      if (kms_output->saved_crtc)
-        {
-          output->width = kms_output->saved_crtc->width;
-          output->height = kms_output->saved_crtc->height;
+      if (output->state->mode)
+        cogl_object_unref (output->state->mode);
+      output->state->mode = NULL;
 
-          if (kms_output->saved_crtc->mode_valid)
-            {
-              drmModeModeInfo *mode = &kms_output->saved_crtc->mode;
-              output->refresh_rate = mode->vrefresh;
-            }
-        }
-      else
+      if (kms_output->saved_crtc &&
+          kms_output->saved_crtc->mode_valid)
         {
-          /* If there is no encoder associated with the connector then
-           * there is no crtc mode and so there's currently no basis
-           * to specify a width/height */
-          output->width = 0;
-          output->height = 0;
-        }
+          output->state->mode =
+            find_mode (output->modes, kms_output->saved_crtc->mode.name);
+          cogl_object_ref (output->state->mode);
 
-      _cogl_output_set_winsys_data (output,
-                                    kms_output,
-                                    kms_output_destroy_cb);
+          g_warn_if_fail (output->state->mode);
+        }
 
       new_outputs = g_list_prepend (new_outputs, output);
     }
@@ -472,6 +490,8 @@ update_outputs (CoglRenderer *renderer)
   renderer->outputs = new_outputs;
 
   drmModeFreeResources (resources);
+
+  _cogl_renderer_notify_outputs_changed (renderer);
 }
 
 static void
@@ -1152,6 +1172,165 @@ _cogl_winsys_onscreen_deinit (CoglOnscreen *onscreen)
   onscreen->winsys = NULL;
 }
 
+static drmModeProperty *
+get_connector_property (int fd,
+                        drmModeConnector *connector,
+                        const char *name)
+{
+  drmModeProperty *property;
+  int i;
+
+  for (i = 0; i < connector->count_props; i++)
+    {
+      property = drmModeGetProperty (fd, connector->props[i]);
+      if (!property)
+        continue;
+
+      if (strcmp (property->name, name) == 0)
+        return props;
+
+      drmModeFreeProperty (property);
+    }
+
+  return NULL;
+}
+
+static void
+_cogl_winsys_commit_outputs (CoglRenderer *renderer,
+                             CoglError **error)
+{
+  CoglRendererEGL *egl_renderer = renderer->winsys;
+  CoglRendererKMS *kms_renderer = egl_renderer->platform;
+  GList *l;
+
+  /*
+   * Ideally we never want to mode-switch to un-initialized
+   * memory or even a temporary buffer since that could introduce
+   * flashes if trying to seamlessly transition from a previous
+   * state.
+   *
+   * If we don't actually make the mode-switchess during the commit
+   * though there's a chance that we'll fail later during
+   * _swap_buffers where we don't have a way of reporting runtime
+   * errors.
+   *
+   * Considering both of of these issues we always mode-switch during
+   * the _commit() and if no source buffer is yet available then we
+   * will setup a source buffer ourselves first. Although this could
+   * cause flashes, those artifacts can be avoided by applications if
+   * they always ensure they have rendered overlay source buffers
+   * before attempting a mode-switch.
+   */
+
+  for (l = renderer->outputs; l; l = l->next)
+    {
+      CoglOutput *output = l->data;
+      CoglOutputKMS *kms_output = output->winsys;
+      CoglOutputState *state_old = output->state;
+      CoglOutputState *state_new = output->pending;
+      GList *old_overlay0_link, *new_overlay0_link;
+      drmModeProperty *property;
+
+      if (state_old == state_new)
+        continue;
+
+      connector = drmModeGetConnector (kms_renderer->fd,
+                                       kms_output->connector_id);
+      if (!connector)
+        {
+          g_warn_if_reached ();
+          continue;
+        }
+
+      if (b->output->pending->overlays)
+        overlay0_new = state_new->output->pending->overlays->data;
+      else
+        overlay0_new = NULL;
+
+      if (!overlay0_new ||
+          state_old->dpms_mode != state_new->dpms_mode)
+        {
+          /* If the output has no associated overlays then we assume
+           * it's ok to try and put it into DPMS_MODE_OFF */
+          dpms_mode = overlay0_new ? state_new->dpms_mode : DRM_MODE_DPMS_OFF;
+
+          property = get_connector_property (kms_renderer->fd,
+                                             connector,
+                                             "DPMS");
+          if (property)
+            {
+              drmModeConnectorSetProperty (kms_renderer->fd,
+                                           connector->connector_id,
+                                           property->prop_id, dpms_mode);
+              drmModeFreeProperty (property);
+            }
+        }
+
+      drmModeFreeConnector (connector);
+
+      if (!state_new->output->pending->overlays)
+        {
+
+        }
+
+      /* We always assume there is always at least one overlay
+       * associated with each output */
+      g_warn_if_fail (b->output->pending->overlays &&
+                      b->output->pending->overlays->data);
+      overlay0_b = b->output->pending->overlays->data;
+
+      /* We also assume there is always source associated with
+       * each overlay */
+      g_warn_if_fail (overlay0_b->onscreen_source);
+
+      b_overlay0_link = b->output->pending->overlays;
+      if (!
+
+#error FIXME
+      /* First setup the crtc mode, using the source from the
+       * lowest overlay associated with the output. */
+
+      /* Now setup planes for all remaining overlays */
+      for (m = a->overlays, n = b->overlays;
+           ;
+           m = m->next, n = n->next)
+        {
+          CoglOverlay *overlay_m, *overlay_n;
+
+          if (m && n && _cogl_overlay_equal (m->data, n->data))
+            continue;
+
+          overlay_m = m->data;
+
+          if (!m || overlay_m->onscreen_source != overlay_n->onscreen_source)
+            {
+
+            }
+#error FIXME
+        }
+
+  /* Note: In the future we might support other sources, such as for
+   * video */
+  CoglOnscreen *onscreen_source;
+
+  /* XXX: src_x must be the first member for _cogl_overlay_equal() to
+   * work and all remaining members should be comparable via
+   * memcpy() */
+
+  /* What region of the source should be overlayed? */
+  int src_x;
+  int src_y;
+  int src_width;
+  int src_height;
+
+  int dst_x;
+  int dst_y;
+
+
+      _cogl_output_update_state (output);
+    }
+}
+
 static const CoglWinsysEGLVtable
 _cogl_winsys_egl_vtable =
   {
@@ -1192,6 +1371,8 @@ _cogl_winsys_egl_kms_get_vtable (void)
       vtable.onscreen_swap_buffers_with_damage =
         _cogl_winsys_onscreen_swap_buffers_with_damage;
 
+      vtable.commit_outputs = _cogl_winsys_commit_outputs;
+
       vtable_inited = TRUE;
     }
 
diff --git a/cogl/winsys/cogl-winsys-private.h b/cogl/winsys/cogl-winsys-private.h
index 123419e..43f3463 100644
--- a/cogl/winsys/cogl-winsys-private.h
+++ b/cogl/winsys/cogl-winsys-private.h
@@ -194,6 +194,18 @@ typedef struct _CoglWinsysVtable
   void
   (*fence_destroy) (CoglContext *ctx, void *fence);
 
+  /* optional
+   *
+   * This iterates the current renderer->outputs and for each output
+   * with pending changes they should be applied to the window system
+   * or hardware.
+   *
+   * If it's not possible to apply the pending changes then the
+   * previous state should be restored and an error returned.
+   */
+  CoglBool
+  (*commit_outputs) (CoglRenderer *renderer, CoglError **error);
+
 } CoglWinsysVtable;
 
 CoglBool


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