summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cogl/Makefile.am5
-rw-r--r--cogl/cogl-frame-info.h6
-rw-r--r--cogl/cogl-framebuffer.h1
-rw-r--r--cogl/cogl-mode-private.h58
-rw-r--r--cogl/cogl-mode.c73
-rw-r--r--cogl/cogl-mode.h51
-rw-r--r--cogl/cogl-onscreen.h6
-rw-r--r--cogl/cogl-output-private.h46
-rw-r--r--cogl/cogl-output.c288
-rw-r--r--cogl/cogl-output.h245
-rw-r--r--cogl/cogl-overlay-private.h76
-rw-r--r--cogl/cogl-overlay.c249
-rw-r--r--cogl/cogl-overlay.h114
-rw-r--r--cogl/cogl-renderer-private.h3
-rw-r--r--cogl/cogl-renderer.c89
-rw-r--r--cogl/cogl-renderer.h27
-rw-r--r--cogl/cogl-xlib-renderer.c123
-rw-r--r--cogl/cogl.h1
-rw-r--r--cogl/winsys/cogl-winsys-egl-kms.c523
-rw-r--r--cogl/winsys/cogl-winsys-private.h12
20 files changed, 1840 insertions, 156 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 642e9c94..512b3c1c 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-frame-info.h b/cogl/cogl-frame-info.h
index 36f8a046..f20d0853 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 2ad41f8f..8106095d 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 00000000..fddd1cad
--- /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 00000000..d742609f
--- /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 00000000..6d25f95b
--- /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 d9582fa4..b0231584 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 f0e8d57b..82bb4919 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 bf2ba217..cd79f5a2 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 c0cc7cce..1f275a3f 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 00000000..1943a9a6
--- /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 00000000..0abe6218
--- /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 00000000..1a3c793e
--- /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-renderer-private.h b/cogl/cogl-renderer-private.h
index 8b8d2bfe..7bca274f 100644
--- a/cogl/cogl-renderer-private.h
+++ b/cogl/cogl-renderer-private.h
@@ -117,4 +117,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 2564c9d2..ab9b37b9 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 */
@@ -843,3 +845,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 c7e6a5ab..1f81faa3 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 4d332fa8..99f1f895 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 c5ad6619..5ec316bc 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 a81237de..260342ff 100644
--- a/cogl/winsys/cogl-winsys-egl-kms.c
+++ b/cogl/winsys/cogl-winsys-egl-kms.c
@@ -334,7 +334,6 @@ update_outputs (CoglRenderer *renderer)
{
CoglOutput *output = NULL;
CoglOutputKMS *kms_output;
- const char *type_name;
GList *l;
drmModeConnector *connector =
@@ -356,7 +355,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;
@@ -366,53 +365,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);
+ output = _cogl_output_new (type_name);
- kms_output = g_slice_new0 (CoglOutputKMS);
- kms_output->connector_id = connector->connector_id;
- kms_output->connector = connector;
+ 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);
+ }
+
+ for (j = 0; j < connector->count_modes; j++)
+ {
+ drmModeModeInfo *info = &connector->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);
+ }
+
+ 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;
}
@@ -439,29 +467,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);
}
@@ -476,6 +494,8 @@ update_outputs (CoglRenderer *renderer)
renderer->outputs = new_outputs;
drmModeFreeResources (resources);
+
+ _cogl_renderer_notify_outputs_changed (renderer);
}
static void
@@ -1242,6 +1262,419 @@ _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;
+}
+
+/* XXX: NB: Don't assume that the output->state is a reliable cache
+ * of the real hardware state such that state changes can be avoided
+ * by looking for NOP changes between ->state and ->pending since we
+ * sometimes have to deal with the display being changed behind our
+ * back.
+ *
+ * TODO: Support incremental updates in certain cases
+ *
+ * XXX: The corner cases to consider...
+ *
+ * Q: How do we _commit an overlay configuration?
+ * A: During a _commit we always check that each overlay has
+ * an associated framebuffer source that has a valid
+ * ->next_bo or ->current_bo (otherwise we report an error)
+ * since we can't set a mode without a framebuffer and we
+ * don't want to be automatically allocating place holder
+ * framebuffers in corner cases or displaying undefined
+ * buffer contents.
+ *
+ * If we need to call drmModeSetCrtc() we will pass ->next_bo
+ * if available, otherwise ->current_bo.
+ *
+ * We always assume there could be outstanding rendering
+ * associated with a bo when calling drmModeSetCrtc() and so
+ * we explicitly synchronize with the GPU to make sure all
+ * rendering to the buffer is complete first.
+ *
+ * If we are using ->next_bo that implies there is currently
+ * a pending flip that hasn't completed. We should mark the
+ * pending flip as a "stale" flip by incrementing
+ * ->stale_flips++. Later when we reach page_flip_handler()
+ * we will check the ->stale_flips counter before
+ * decrementing it and whenever it is set we should only make
+ * sure to issue any necessary _FRAME_SYNC events but we
+ * should avoid making any updates to ->current_bo/->next_bo
+ * pointers.
+ *
+ *XXX: why does stale_flips need to be a counter instead of just
+ * a boolean
+ *
+ * After successfully calling drmModeSetCrtc() we insert a
+ * reference to the overlay in kms_onscreen->overlays.
+ *
+ * Q: what if there is an error when calling drmModeSetCrtc?
+ * A: We roll-back the whole configuration
+ *
+ * Q: What are the semantics for calling drmModeSetCrtc while
+ * there are pending page flips?
+ * A: Looking at the intel drm driver it looks like setting
+ * a mode starts by disabling the crtc, which involves
+ * waiting for pending flips so I think we can assume
+ * page flip events will *always* be delivered by drm.
+ *
+ * Q: How do we deal with roll-back when this is the first
+ * configuration to be committed?
+ * A: We should be assuming that update_outputs has been
+ * called before any configuration so we should know the
+ * previous state. XXX: what about previous framebuffer
+ * state? It seems likely that we'll need to special case
+ * restoring a saved state where the saved drmModeFB doesn't
+ * correspond to a CoglFramebuffer.
+ *
+ * Q: What if we disassociate a framebuffer from an overlay
+ * while it still has a pending flip? (considering what
+ * might go wrong if we then immediately tried to associate
+ * the framebuffer with a different overlay)
+ * A: XXX
+ *
+ * Q: When do we remove references from the
+ * kms_onscreen->overlays list?
+ * A: XXX
+ *
+ * Q: How do we handle _swap_buffers
+ * A: We iterate through each output that is associated with
+ * the onscreen framebuffer and for the first output
+ * we use drmModePageFlip (passing DRM_MODE_PAGE_FLIP_EVENT)
+ * to post the framebuffer for overlay0 and use
+ * drmModeSetPlane() for any additional overlays. For
+ * all other outputs we use drmModeSetCrtc to post the
+ * framebuffer for overlay0 while also using
+ * drmModeSetPlane() for additional overlays.
+ *
+ * Note: until we have the atomic page flipping api we
+ * don't have a very sane way of synchronizing changes
+ * to overlay planes.
+ *
+ * Note: we are intentionally only trying to synchronize
+ * with one output but we will probably want to provide
+ * api for controlling which output is synchronized.
+ *
+ * Q: Would it be better when handling multiple outputs to
+ * call drmModeSetCrtc() after being notified of the flip
+ * for the first output?
+ * A: Since using drmModeSetCrtc() implies needing to
+ * synchronize with the GPU to make sure rendering is
+ * complete, then waiting until the flip should minimize
+ * blocking on the CPU, especially in the case where the same
+ * buffer is being posted to multiple outputs since the flip
+ * should end up waiting for the GPU to finish for us so we
+ * won't have to.
+ *
+ * We should create a queue_swap_outputs utility for us to
+ * queue the swapping of all unsynchronized outputs.
+ *
+ *
+ * Q: What if we call _swap_buffers() before we have committed
+ * an output configuration associating the framebuffer with
+ * a hardware overlay?
+ * A: In this case we'll see that kms_output->overlays is NULL.
+ * We lock the front buffer, set it on ->next_bo and directly
+ * call page_flip_handler() to behave as if the flip
+ * completed immediately. This will make sure we issue a
+ * _FRAME_SYNC event for the swap and move the bo to
+ * ->current_bo.
+ *
+ *
+ * Q: How do we deal with an error in drmModePageFlip() also
+ * considering that after the error we might commit a
+ * new display configuration which will want to find
+ * a next/current_bo to reference.
+ * A: We can pretend there was no error and that the page
+ * flip completed immediately by calling page_flip_handler()
+ * directly in this case. This will make sure cogl
+ * dispatches a _FRAME_SYNC event for the frame otherwise
+ * applications may freeze. The main problem here is that
+ * we don't have meaningful timestamp data to pass to
+ * page_flip_handler(). XXX: wont this potentially break the
+ * invariable that we should be able to assume ->current_bo
+ * has no outstanding rendering?
+ *
+ * Q: How do we handle an onscreen framebuffer resize?
+ * A: We don't, you just have to create a new framebuffer
+ */
+static void
+_cogl_winsys_commit_outputs (CoglRenderer *renderer,
+ CoglError **error)
+{
+ CoglRendererEGL *egl_renderer = renderer->winsys;
+ CoglRendererKMS *kms_renderer = egl_renderer->platform;
+ GList *l;
+ CoglBool roll_back = FALSE;
+
+
+ /* If we hit an error at any point while committing the new
+ * configuration then we revert back to here with roll_back
+ * set to TRUE and instead re-commit the previous
+ * configuration */
+ROLL_BACK:
+
+
+ for (l = renderer->outputs; l; l = l->next)
+ {
+ CoglOutput *output = l->data;
+ CoglOutputKMS *kms_output = output->winsys;
+ CoglOutputState *state = roll_back ? output->state : output->pending;
+ CoglOverlay *overlay0;
+ drmModeConnector *connector;
+ drmModeProperty *property;
+ int i;
+
+ connector = drmModeGetConnector (kms_renderer->fd,
+ kms_output->connector_id);
+ if (!connector)
+ {
+ g_warn_if_reached ();
+ continue;
+ }
+
+ if (state->overlays)
+ overlay0 = state->overlays->data;
+ else
+ overlay0 = NULL;
+
+ /* 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)
+ {
+ int status = drmModeConnectorSetProperty (kms_renderer->fd,
+ connector->connector_id,
+ property->prop_id,
+ dpms_mode);
+ drmModeFreeProperty (property);
+
+ if (status < 0)
+ {
+ const char *dpms_mode_names[] = {
+ "ON",
+ "STANDBY",
+ "SUSPEND",
+ "OFF"
+ };
+
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("Failed to set DPMS state for "
+ "connector %d to %s",
+ kms_output->connector_id,
+ dpms_mode_names[dpms_mode]);
+ goto ROLL_BACK;
+ }
+ }
+
+ if (!overlay0)
+ {
+ drmModeFreeConnector (connector);
+ continue;
+ }
+
+ if (!overlay0->onscreen_source)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("An overlay must be associated with an "
+ "onscreen framebuffer as a color source");
+ goto ROLL_BACK;
+ }
+
+ for (i = 0; i < connector->count_modes; i++)
+ {
+ drmModeInfo *mode_info = &connector->modes[i];
+ int n_planes;
+
+ if (strcmp (mode_info->name, state->mode->name) == 0)
+ {
+ CoglOnscreen *onscreen = overlay0->onscreen_source;
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
+ uint32_t fb_id;
+ int status;
+
+ if (overlay0->src_x != 0 ||
+ overlay0->src_y != 0 ||
+ overlay0->src_width != mode_info->width ||
+ overlay0->src_height != mode_info->height)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("On KMS the first overlay's source can "
+ "not be offset and its size must match "
+ "the mode resolution");
+ goto ROLL_BACK;
+ }
+
+ if (kms_onscreen->next_fb_id)
+ fb_id = kms_onscreen->next_fb_id;
+ else if (kms_onscreen->current_fb_id)
+ fb_id = kms_onscreen->current_fb_id;
+ else
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("Can't commit output changes involving "
+ "an uninitialized (un-swapped) onscreen "
+ "framebuffer since it has no actual "
+ "data to scan out yet");
+ goto ROLL_BACK;
+ }
+
+ /* drmModeSetCrtc isn't synchronized with the GPU
+ * pipeline so we explicitly wait for any out standing
+ * rendering to complete before setting the new
+ * mode... */
+ cogl_framebuffer_finish (overlay0->onscreen_source);
+
+ status = drmModeSetCrtc (kms_renderer->fd,
+ kms_output->encoder->crtc_id,
+ fb_id, 0, 0,
+ &kms_output->connector_id, 1,
+ &kms_mode_info);
+ if (status < 0)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("KMS was unable to set the requested "
+ "mode (%s) on connector %d, possibly "
+ "due to a hardware limitation",
+ dpms_mode_names[dpms_mode],
+ kms_output->connector_id);
+ goto ROLL_BACK;
+ }
+ }
+
+ /*
+ * The remaining overlays should be setup via drmModeSetPlane()
+ */
+
+ for (n_planes = 0, l = state->overlays->next;
+ l;
+ n_planes++, l = l->next)
+ ;
+
+ if (n_planes)
+ {
+ drmModePlaneRes *planes =
+ drmModeGetPlaneResources (kms_renderer->fd);
+
+ if (!planes)
+ g_warn_if_reached ();
+
+ if (planes == NULL || planes->count_planes < n_planes)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("Hardware doesn't support enough "
+ "overlays to support configuration.");
+ goto ROLL_BACK;
+ }
+
+ for (n = 0, l = state->overlays->next; l; n++, l = l->next)
+ {
+ CoglOverlay *overlay = l->data;
+ CoglOnscreen *onscreen = overlay0->onscreen_source;
+ CoglOnscreenEGL *egl_onscreen = onscreen->winsys;
+ CoglOnscreenKMS *kms_onscreen = egl_onscreen->platform;
+ uint32_t fb_id;
+
+ if (!overlay->onscreen_source)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("An overlay must be associated with an "
+ "onscreen framebuffer as a color source");
+ goto ROLL_BACK;
+ }
+
+ if (kms_onscreen->next_fb_id)
+ fb_id = kms_onscreen->next_fb_id;
+ else if (kms_onscreen->current_fb_id)
+ fb_id = kms_onscreen->current_fb_id;
+ else
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("Can't commit output changes involving "
+ "an uninitialized (un-swapped) onscreen "
+ "framebuffer since it has no actual "
+ "data to scan out yet");
+ goto ROLL_BACK;
+ }
+
+ if (drmModeSetPlane (kms_renderer->fd,
+ planes->planes[n],
+ kms_output->encoder->crtc_id,
+ fb_id,
+ /* FIXME: flags? */,
+ /* FIXME: ctc_x/y/w/h,
+ * src_x/y/w/h */) < 0)
+ {
+ g_return_if_fail (roll_back == FALSE);
+
+ roll_back = TRUE;
+ roll_back_error =
+ g_strdup_printf ("KMS was unable to setup the "
+ "overlays as requested, possibly "
+ "due to a hardware limitation.");
+ goto ROLL_BACK;
+ }
+ }
+
+ drmModeFreePlaneResources (planes);
+ }
+ }
+
+ drmModeFreeConnector (connector);
+
+ _cogl_output_update_state (output);
+ }
+}
+
static const CoglWinsysEGLVtable
_cogl_winsys_egl_vtable =
{
@@ -1282,6 +1715,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 123419e1..43f34638 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