summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Bragg <robert@linux.intel.com>2011-11-14 18:33:53 +0000
committerRobert Bragg <robert@linux.intel.com>2011-11-29 12:39:42 +0000
commita32b7f1db446c687370ccca2ac84365efa71a36a (patch)
tree33c9c9db2ec94e50fca344d1952a605de6d2e28d
parent2469065904b76de2519b2709f1211fb0177fcce3 (diff)
downloadcogl-wip/virtual-framebuffer.tar.gz
stash: virtual-framebuffer work in progresswip/virtual-framebuffer
TODO: would it be worth caching the glScissor associated with a framebuffer so that when we switch between framebuffers (for virtual framebuffers) we can cheaply restore the correct glScissor so we don't need to hit the clip_stack_flush code. If we know the stencil buffer matches the current clip stack, we know any clip planes remain constant as we rotate between framebuffers, we are going to want to set a transient offset viewport but don't want that to mark the clip state as changed when drawing a primitive on multiple framebuffers we should always check what the current scissor is to see if we can trivially avoid drawing to multiple framebuffers.
-rw-r--r--cogl/Makefile.am3
-rw-r--r--cogl/cogl-framebuffer-private.h8
-rw-r--r--cogl/cogl-framebuffer.c23
-rw-r--r--cogl/cogl-virtual-framebuffer.c289
-rw-r--r--cogl/cogl-virtual-framebuffer.h118
-rw-r--r--cogl/cogl.h1
-rw-r--r--examples/Makefile.am4
-rw-r--r--examples/cogl-virtual-framebuffer.c96
8 files changed, 538 insertions, 4 deletions
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 46a1a8c8..35d02bf5 100644
--- a/cogl/Makefile.am
+++ b/cogl/Makefile.am
@@ -90,6 +90,7 @@ cogl_public_h = \
$(srcdir)/cogl-primitive.h \
$(srcdir)/cogl-clip-state.h \
$(srcdir)/cogl-framebuffer.h \
+ $(srcdir)/cogl-virtual-framebuffer.h \
$(srcdir)/cogl-onscreen.h \
$(srcdir)/cogl-clutter.h \
$(srcdir)/cogl.h \
@@ -309,6 +310,8 @@ cogl_sources_c = \
$(srcdir)/cogl-framebuffer-private.h \
$(srcdir)/cogl-framebuffer.c \
$(srcdir)/cogl-onscreen-private.h \
+ $(srcdir)/cogl-virtual-framebuffer-private.h \
+ $(srcdir)/cogl-virtual-framebuffer.c \
$(srcdir)/cogl-onscreen.c \
$(srcdir)/cogl-profile.h \
$(srcdir)/cogl-profile.c \
diff --git a/cogl/cogl-framebuffer-private.h b/cogl/cogl-framebuffer-private.h
index fce41e67..1085c66e 100644
--- a/cogl/cogl-framebuffer-private.h
+++ b/cogl/cogl-framebuffer-private.h
@@ -41,7 +41,8 @@
typedef enum _CoglFramebufferType {
COGL_FRAMEBUFFER_TYPE_ONSCREEN,
- COGL_FRAMEBUFFER_TYPE_OFFSCREEN
+ COGL_FRAMEBUFFER_TYPE_OFFSCREEN,
+ COGL_FRAMEBUFFER_TYPE_VIRTUAL
} CoglFramebufferType;
typedef struct
@@ -115,6 +116,11 @@ struct _CoglFramebuffer
CoglClipState clip_state;
+ /* The stencil buffer matches what's required for this
+ * clip stack. NULL means the stencil buffer contents
+ * are undefined. */
+ CoglClipStack *clip_stack_of_current_stencil;
+
gboolean dirty_bitmasks;
int red_bits;
int blue_bits;
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index 8e989921..28bfbda9 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -35,6 +35,8 @@
#include "cogl-util.h"
#include "cogl-texture-private.h"
#include "cogl-framebuffer-private.h"
+#include "cogl-virtual-framebuffer-private.h"
+#include "cogl-virtual-framebuffer.h"
#include "cogl-onscreen-template-private.h"
#include "cogl-clip-stack.h"
#include "cogl-journal-private.h"
@@ -137,7 +139,8 @@ _cogl_is_framebuffer (void *object)
return FALSE;
return obj->klass->type == _cogl_object_onscreen_get_type ()
- || obj->klass->type == _cogl_object_offscreen_get_type ();
+ || obj->klass->type == _cogl_object_offscreen_get_type ()
+ || obj->klass->type == _cogl_object_virtual_framebuffer_get_type ();
}
void
@@ -171,6 +174,7 @@ _cogl_framebuffer_init (CoglFramebuffer *framebuffer,
/* Initialise the clip stack */
_cogl_clip_state_init (&framebuffer->clip_state);
+ framebuffer->clip_stack_of_current_stencil = NULL;
framebuffer->journal = _cogl_journal_new ();
@@ -413,6 +417,15 @@ cogl_framebuffer_clear4f (CoglFramebuffer *framebuffer,
_cogl_framebuffer_clear_without_flush4f (framebuffer, buffers,
red, green, blue, alpha);
+ /* We are clobbering the stencil state so we can no longer assume it
+ * will match any clip_stack.
+ *
+ * Note: although NULL is a valid clip_stack value that's ok because
+ * in that case it doesn't matter what the stencil buffer contains.
+ */
+ if (buffers & COGL_BUFFER_BIT_STENCIL)
+ framebuffer->clip_stack_of_current_stencil = NULL;
+
/* This is a debugging variable used to visually display the quad
* batches from the journal. It is reset here to increase the
* chances of getting the same colours for each frame during an
@@ -532,6 +545,7 @@ cogl_framebuffer_set_viewport (CoglFramebuffer *framebuffer,
framebuffer->viewport_width = width;
framebuffer->viewport_height = height;
+#warning "XXX: I think we also need to dirty the clip state here too"
if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |=
COGL_FRAMEBUFFER_STATE_VIEWPORT;
@@ -1327,6 +1341,8 @@ bind_gl_framebuffer (CoglContext *ctx,
GLenum target,
CoglFramebuffer *framebuffer)
{
+ _COGL_RETURN_IF_FAIL (!cogl_is_virtual_framebuffer (framebuffer));
+
if (framebuffer->type == COGL_FRAMEBUFFER_TYPE_OFFSCREEN)
GE (ctx, glBindFramebuffer (target,
COGL_OFFSCREEN (framebuffer)->fbo_handle));
@@ -1513,6 +1529,8 @@ _cogl_framebuffer_flush_clip_state (CoglFramebuffer *framebuffer)
{
CoglClipStack *stack = _cogl_clip_state_get_stack (&framebuffer->clip_state);
_cogl_clip_stack_flush (stack, framebuffer);
+#warning "should we take a reference here?"
+ framebuffer->clip_stack_of_current_stencil = stack;
}
static void
@@ -1601,7 +1619,8 @@ _cogl_framebuffer_flush_state (CoglFramebuffer *draw_buffer,
unsigned long differences;
int bit;
- _COGL_RETURN_IF_FAIL (!cogl_is_virtual_framebuffer (framebuffer));
+ _COGL_RETURN_IF_FAIL (!cogl_is_virtual_framebuffer (draw_buffer));
+ _COGL_RETURN_IF_FAIL (!cogl_is_virtual_framebuffer (read_buffer));
/* We can assume that any state that has changed for the current
* framebuffer is different to the currently flushed value. */
diff --git a/cogl/cogl-virtual-framebuffer.c b/cogl/cogl-virtual-framebuffer.c
new file mode 100644
index 00000000..a4eb6bd4
--- /dev/null
+++ b/cogl/cogl-virtual-framebuffer.c
@@ -0,0 +1,289 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 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/>.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "cogl-util.h"
+#include "cogl-framebuffer-private.h"
+#include "cogl-virtual-framebuffer-private.h"
+#include "cogl-virtual-framebuffer.h"
+#include "cogl-context-private.h"
+#include "cogl-object-private.h"
+
+#include <glib.h>
+
+static void
+_cogl_virtual_framebuffer_free (CoglVirtualFramebuffer *virtual_framebuffer);
+
+COGL_OBJECT_DEFINE (VirtualFramebuffer, virtual_framebuffer);
+
+CoglVirtualFramebuffer *
+cogl_virtual_framebuffer_new (CoglContext *context,
+ int width,
+ int height)
+{
+ CoglVirtualFramebuffer *virtual_framebuffer =
+ g_new0 (CoglVirtualFramebuffer, 1);
+
+ _cogl_framebuffer_init (COGL_FRAMEBUFFER (virtual_framebuffer),
+ context,
+ COGL_FRAMEBUFFER_TYPE_VIRTUAL,
+ COGL_PIXEL_FORMAT_RGBA_8888, /* arbitrary */
+ width,
+ height);
+
+ COGL_FRAMEBUFFER (virtual_framebuffer)->allocated = TRUE;
+
+ return _cogl_virtual_framebuffer_object_new (virtual_framebuffer);
+}
+
+void
+cogl_virtual_framebuffer_add_slice (CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int sample_x,
+ int sample_y,
+ int sample_width,
+ int sample_height,
+ int virtual_x,
+ int virtual_y)
+{
+ CoglFramebufferSlice *new_slice = g_new0 (CoglFramebufferSlice, 1);
+
+ new_slice->framebuffer = cogl_object_ref (slice);
+ new_slice->sample_region[0] = sample_x;
+ new_slice->sample_region[1] = sample_y;
+ if (sample_width == -1)
+ sample_width = cogl_framebuffer_get_width (slice);
+ new_slice->sample_region[2] = sample_width;
+ if (sample_height == -1)
+ sample_height = cogl_framebuffer_get_height (slice);
+ new_slice->sample_region[3] = sample_height;
+ new_slice->virtual_x = virtual_x;
+ new_slice->virtual_y = virtual_y;
+
+ if (virtual_framebuffer->slices == NULL)
+ {
+ CoglFramebuffer *fb = COGL_FRAMEBUFFER (virtual_framebuffer);
+ fb->format = cogl_framebuffer_get_color_format (fb);
+ }
+
+ virtual_framebuffer->slices =
+ g_list_prepend (virtual_framebuffer->slices, new_slice);
+}
+
+static void
+_cogl_framebuffer_slice_free (CoglFramebufferSlice *slice)
+{
+ cogl_object_unref (slice->framebuffer);
+ g_free (slice);
+}
+
+static void
+_cogl_virtual_framebuffer_free (CoglVirtualFramebuffer *virtual_framebuffer)
+{
+ CoglFramebuffer *framebuffer = COGL_FRAMEBUFFER (virtual_framebuffer);
+ GList *l;
+
+ for (l = virtual_framebuffer->slices; l; l = l->next)
+ _cogl_framebuffer_slice_free (l->data);
+
+ g_list_free (virtual_framebuffer->slices);
+
+ /* Chain up to parent */
+ _cogl_framebuffer_free (framebuffer);
+
+ g_free (virtual_framebuffer);
+}
+
+static CoglFramebufferSlice *
+lookup_slice (CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+ GList *l;
+
+ for (l = virtual_framebuffer->slices; l; l = l->next)
+ {
+ CoglFramebufferSlice *current_slice = l->data;
+ if (current_slice->framebuffer == slice)
+ return current_slice;
+ }
+
+ return NULL;
+}
+
+void
+cogl_virtual_framebuffer_remove_slice (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+ GList *l;
+
+ for (l = virtual_framebuffer->slices; l; l = l->next)
+ {
+ CoglFramebufferSlice *current_slice = l->data;
+ if (current_slice->framebuffer == slice)
+ {
+ _cogl_framebuffer_slice_free (current_slice);
+ virtual_framebuffer->slices =
+ g_list_remove_list (virtual_framebuffer->slices, l);
+ return;
+ }
+ }
+
+ g_warn_if_reached ();
+}
+
+void
+cogl_virtual_framebuffer_move_slice (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int virtual_x,
+ int virtual_y)
+{
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_IF_FAIL (match);
+
+ /* XXX: do we need to flush anything here? */
+
+ match->virtual_x = virtual_x;
+ match->virtual_y = virtual_y;
+}
+
+void
+cogl_virtual_framebuffer_set_slice_sample_region (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_IF_FAIL (match);
+
+ /* XXX: do we need to flush anything here? */
+
+ match->sample_region[0] = x;
+ match->sample_region[1] = y;
+
+ if (width == -1)
+ width = cogl_framebuffer_get_width (slice);
+ match->sample_region[2] = width;
+ if (height == -1)
+ height = cogl_framebuffer_get_height (slice);
+ match->sample_region[3] = height;
+}
+
+int
+cogl_virtual_framebuffer_get_slice_sample_x (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_VAL_IF_FAIL (match, 0);
+
+ /* XXX: do we need to flush anything here? */
+
+ return match->sample_region[0];
+}
+
+int
+cogl_virtual_framebuffer_get_slice_sample_y (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_VAL_IF_FAIL (match, 0);
+
+ /* XXX: do we need to flush anything here? */
+
+ return match->sample_region[1];
+}
+
+int
+cogl_virtual_framebuffer_get_slice_sample_width (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_VAL_IF_FAIL (match, 0);
+
+ /* XXX: do we need to flush anything here? */
+
+ return match->sample_region[2];
+}
+
+int
+cogl_virtual_framebuffer_get_slice_sample_height (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice)
+{
+ CoglFramebufferSlice *match = lookup_slice (virtual_framebuffer, slice);
+
+ _COGL_RETURN_VAL_IF_FAIL (match, 0);
+
+ /* XXX: do we need to flush anything here? */
+
+ return match->sample_region[3];
+}
+
+void
+cogl_virtual_framebuffer_set_size (CoglVirtualFramebuffer *virtual_framebuffer,
+ int width,
+ int height)
+{
+ CoglFramebuffer *fb = COGL_FRAMEBUFFER (virtual_framebuffer);
+
+ /* XXX: do we need to flush anything here? */
+
+ fb->width = width;
+ fb->height = height;
+}
+
+void
+_cogl_virtual_framebuffer_foreach (CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglVirtialFramebufferCallback callback,
+ void *user_data)
+{
+ GList *l;
+ gboolean cont = TRUE;
+
+ for (l = virtual_framebuffer->slices; l && cont; l = l->next)
+ {
+ CoglFramebufferSlice *slice = l->data;
+ cont = callback (virtual_framebuffer,
+ slice->framebuffer,
+ slice->sample_region,
+ slice->virtual_x,
+ slice->virtual_y,
+ user_data);
+ }
+}
diff --git a/cogl/cogl-virtual-framebuffer.h b/cogl/cogl-virtual-framebuffer.h
new file mode 100644
index 00000000..69aa77e4
--- /dev/null
+++ b/cogl/cogl-virtual-framebuffer.h
@@ -0,0 +1,118 @@
+/*
+ * Cogl
+ *
+ * An object oriented GL/GLES Abstraction/Utility Layer
+ *
+ * Copyright (C) 2011 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/>.
+ *
+ *
+ * Authors:
+ * Robert Bragg <robert@linux.intel.com>
+ */
+
+#if !defined(__COGL_H_INSIDE__) && !defined(CLUTTER_COMPILATION)
+#error "Only <cogl/cogl.h> can be included directly."
+#endif
+
+#ifndef _COGL_VIRTUAL_FRAMEBUFFER_H_
+#define _COGL_VIRTUAL_FRAMEBUFFER_H_
+
+#include <cogl/cogl-context.h>
+#include <cogl/cogl-framebuffer.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _CoglVirtualFramebuffer CoglVirtualFramebuffer;
+#define COGL_VIRTUAL_FRAMEBUFFER(X) ((CoglVirtualFramebuffer *)(X))
+
+#define cogl_is_virtual_framebuffer cogl_is_virtual_framebuffer_EXP
+/**
+ * cogl_is_virtual_framebuffer:
+ * @object: A pointer to a #CoglObject
+ *
+ * Gets whether the given object implements the virtual framebuffer
+ * interface.
+ *
+ * Return value: %TRUE if object implements the
+ * #CoglVirtualFramebuffer interface %FALSE otherwise.
+ *
+ * Since: 1.10
+ * Stability: Unstable
+ */
+gboolean
+cogl_is_virtual_framebuffer (void *object);
+
+CoglVirtualFramebuffer *
+cogl_virtual_framebuffer_new (CoglContext *context,
+ int width,
+ int height);
+
+void
+cogl_virtual_framebuffer_add_slice (CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int sample_x,
+ int sample_y,
+ int sample_width,
+ int sample_height,
+ int virtual_x,
+ int virtual_y);
+void
+cogl_virtual_framebuffer_remove_slice (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice);
+void
+cogl_virtual_framebuffer_move_slice (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int virtual_x,
+ int virtual_y);
+void
+cogl_virtual_framebuffer_set_slice_sample_region (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice,
+ int x,
+ int y,
+ int width,
+ int height);
+int
+cogl_virtual_framebuffer_get_slice_sample_x (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice);
+int
+cogl_virtual_framebuffer_get_slice_sample_y (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice);
+
+int
+cogl_virtual_framebuffer_get_slice_sample_width (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice);
+
+int
+cogl_virtual_framebuffer_get_slice_sample_height (
+ CoglVirtualFramebuffer *virtual_framebuffer,
+ CoglFramebuffer *slice);
+
+void
+cogl_virtual_framebuffer_set_size (CoglVirtualFramebuffer *virtual_framebuffer,
+ int width,
+ int height);
+
+G_END_DECLS
+
+#endif /* _COGL_VIRTUAL_FRAMEBUFFER_H_ */
diff --git a/cogl/cogl.h b/cogl/cogl.h
index 772886b8..51644fb6 100644
--- a/cogl/cogl.h
+++ b/cogl/cogl.h
@@ -95,6 +95,7 @@ typedef struct _CoglFramebuffer CoglFramebuffer;
#include <cogl/cogl-pipeline-state.h>
#include <cogl/cogl-pipeline-layer-state.h>
#include <cogl/cogl-framebuffer.h>
+#include <cogl/cogl-virtual-framebuffer.h>
#include <cogl/cogl-onscreen.h>
#if defined (COGL_HAS_EGL_PLATFORM_WAYLAND_SUPPORT)
#include <cogl/cogl-wayland-renderer.h>
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 8403a460..69229224 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -18,7 +18,7 @@ common_ldadd = \
$(COGL_DEP_LIBS) \
$(top_builddir)/cogl/libcogl.la
-programs = cogl-hello cogl-info cogl-msaa
+programs = cogl-hello cogl-info cogl-msaa cogl-virtual-framebuffer
examples_datadir = $(pkgdatadir)/examples-data
examples_data_DATA =
@@ -28,6 +28,8 @@ cogl_info_SOURCES = cogl-info.c
cogl_info_LDADD = $(common_ldadd)
cogl_msaa_SOURCES = cogl-msaa.c
cogl_msaa_LDADD = $(common_ldadd)
+cogl_virtual_framebuffer_SOURCES = cogl-virtual-framebuffer.c
+cogl_virtual_framebuffer_LDADD = $(common_ldadd)
if BUILD_COGL_PANGO
programs += cogl-crate
diff --git a/examples/cogl-virtual-framebuffer.c b/examples/cogl-virtual-framebuffer.c
new file mode 100644
index 00000000..54eae3c5
--- /dev/null
+++ b/examples/cogl-virtual-framebuffer.c
@@ -0,0 +1,96 @@
+#include <cogl/cogl.h>
+#include <glib.h>
+#include <stdio.h>
+
+CoglColor black;
+
+#define TEX_WIDTH 300
+#define TEX_HEIGHT 220
+
+int
+main (int argc, char **argv)
+{
+ CoglContext *ctx;
+ CoglOnscreen *onscreen;
+ CoglTexture2D *textures[4];
+ CoglHandle offscreens[4];
+ CoglVirtualFramebuffer *vfb;
+ CoglFramebuffer *fb;
+ GError *error = NULL;
+ CoglVertexP2C4 triangle_vertices[] = {
+ {0, 0.7, 0xff, 0x00, 0x00, 0x80},
+ {-0.7, -0.7, 0x00, 0xff, 0x00, 0xff},
+ {0.7, -0.7, 0x00, 0x00, 0xff, 0xff}
+ };
+ CoglPrimitive *triangle;
+ int i;
+
+ ctx = cogl_context_new (NULL, &error);
+ if (!ctx) {
+ fprintf (stderr, "Failed to create context: %s\n", error->message);
+ return 1;
+ }
+
+ for (i = 0; i < 4; i++)
+ {
+ textures[i] = cogl_texture_2d_new_with_size (ctx,
+ 300, 220,
+ COGL_PIXEL_FORMAT_RGBA_8888,
+ &error);
+ if (!textures[i])
+ {
+ fprintf (stderr, "Failed to allocated texture: %s\n", error->message);
+ return 1;
+ }
+ offscreens[i] =
+ cogl_offscreen_new_to_texture (COGL_TEXTURE (textures[i]));
+ }
+
+ vfb = cogl_virtual_framebuffer_new (ctx, 640, 480);
+ cogl_virtual_framebuffer_add_slice (vfb, offscreens[0],
+ 0, 0, -1, -1,
+ 10, 10);
+ cogl_virtual_framebuffer_add_slice (vfb, offscreens[1],
+ 0, 0, -1, -1,
+ 330, 10);
+ cogl_virtual_framebuffer_add_slice (vfb, offscreens[2],
+ 0, 0, -1, -1,
+ 10, 250);
+ cogl_virtual_framebuffer_add_slice (vfb, offscreens[3],
+ 0, 0, -1, -1,
+ 330, 250);
+
+ onscreen = cogl_onscreen_new (ctx, 640, 480);
+ /* Eventually there will be an implicit allocate on first use so this
+ * will become optional... */
+ fb = COGL_FRAMEBUFFER (onscreen);
+ if (!cogl_framebuffer_allocate (fb, &error)) {
+ fprintf (stderr, "Failed to allocate framebuffer: %s\n", error->message);
+ return 1;
+ }
+
+ cogl_onscreen_show (onscreen);
+
+ cogl_push_framebuffer (COGL_FRAMEBUFFER (vfb));
+
+ triangle = cogl_primitive_new_p2c4 (COGL_VERTICES_MODE_TRIANGLES,
+ 3, triangle_vertices);
+ for (;;) {
+ cogl_clear (&black, COGL_BUFFER_BIT_COLOR);
+ cogl_primitive_draw (triangle);
+
+ /* Now draw the slices of the virtual framebuffer onscreen */
+ cogl_set_source_texture (COGL_TEXTURE (textures[0]));
+ cogl_rectangle (10, 10, 10 + TEX_WIDTH, 10 + TEX_HEIGHT);
+ cogl_set_source_texture (COGL_TEXTURE (textures[1]));
+ cogl_rectangle (330, 10, 330 + TEX_WIDTH, 10 + TEX_HEIGHT);
+ cogl_set_source_texture (COGL_TEXTURE (textures[2]));
+ cogl_rectangle (10, 250, 10 + TEX_WIDTH, 250 + TEX_HEIGHT);
+ cogl_set_source_texture (COGL_TEXTURE (textures[3]));
+ cogl_rectangle (330, 250, 330 + TEX_WIDTH, 250 + TEX_HEIGHT);
+
+ cogl_framebuffer_swap_buffers (fb);
+ }
+
+ return 0;
+}