[cogl/wip/virtual-framebuffer: 22/22] stash: virtual-framebuffer work in progress



commit a32b7f1db446c687370ccca2ac84365efa71a36a
Author: Robert Bragg <robert linux intel com>
Date:   Mon Nov 14 18:33:53 2011 +0000

    stash: virtual-framebuffer work in progress
    
    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.

 cogl/Makefile.am                    |    3 +
 cogl/cogl-framebuffer-private.h     |    8 +-
 cogl/cogl-framebuffer.c             |   23 +++-
 cogl/cogl-virtual-framebuffer.c     |  289 +++++++++++++++++++++++++++++++++++
 cogl/cogl-virtual-framebuffer.h     |  118 ++++++++++++++
 cogl/cogl.h                         |    1 +
 examples/Makefile.am                |    4 +-
 examples/cogl-virtual-framebuffer.c |   96 ++++++++++++
 8 files changed, 538 insertions(+), 4 deletions(-)
---
diff --git a/cogl/Makefile.am b/cogl/Makefile.am
index 46a1a8c..35d02bf 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 fce41e6..1085c66 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 8e98992..28bfbda 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 0000000..a4eb6bd
--- /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 0000000..69aa77e
--- /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 772886b..51644fb 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 8403a46..6922922 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 0000000..54eae3c
--- /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;
+}



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