diff options
-rw-r--r-- | cogl/Makefile.am | 3 | ||||
-rw-r--r-- | cogl/cogl-framebuffer-private.h | 8 | ||||
-rw-r--r-- | cogl/cogl-framebuffer.c | 23 | ||||
-rw-r--r-- | cogl/cogl-virtual-framebuffer.c | 289 | ||||
-rw-r--r-- | cogl/cogl-virtual-framebuffer.h | 118 | ||||
-rw-r--r-- | cogl/cogl.h | 1 | ||||
-rw-r--r-- | examples/Makefile.am | 4 | ||||
-rw-r--r-- | examples/cogl-virtual-framebuffer.c | 96 |
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; +} |