From bb3a008318c97f573d98b09d7e8fe911548947fa Mon Sep 17 00:00:00 2001 From: Robert Bragg Date: Fri, 25 Sep 2009 14:34:34 +0100 Subject: [PATCH] [draw-buffers] First pass at overhauling Cogl's framebuffer management Cogl's support for offscreen rendering was originally written just to support the clutter_texture_new_from_actor API and due to lack of documentation and several confusing - non orthogonal - side effects of using the API it wasn't really possible to use directly. This commit does a number of things: - It removes {gl,gles}/cogl-fbo.{c,h} and adds shared cogl-draw-buffer.{c,h} files instead which should be easier to maintain. - internally CoglFbo objects are now called CoglDrawBuffers. A CoglDrawBuffer is an abstract base class that is inherited from to implement CoglOnscreen and CoglOffscreen draw buffers. CoglOffscreen draw buffers will initially be used to support the cogl_offscreen_new_to_texture API, and CoglOnscreen draw buffers will start to be used internally to represent windows as we aim to migrate some of Clutter's backend code to Cogl. - It makes draw buffer objects the owners of the following state: - viewport - projection matrix stack - modelview matrix stack - clip state (This means when you switch between draw buffers you will automatically be switching to their associated viewport, matrix and clip state) Aside from hopefully making cogl_offscreen_new_to_texture be more useful short term by having simpler and well defined semantics for cogl_set_draw_buffer, as mentioned above this is the first step for a couple of other things: - Its a step toward moving ownership for windows down from Clutter backends into Cogl, by (internally at least) introducing the CoglOnscreen draw buffer. Note: the plan is that cogl_set_draw_buffer will accept on or offscreen draw buffer handles, and the "target" argument will become redundant since we will instead query the type of the given draw buffer handle. - Because we have a common type for on and offscreen framebuffers we can provide a unified API for framebuffer management. Things like: - blitting between buffers - managing ancillary buffers (e.g. attaching depth and stencil buffers) - size requisition - clearing --- cogl/Makefile.am | 2 + cogl/cogl-clip-stack.c | 211 +++++++--- cogl/cogl-clip-stack.h | 9 +- cogl/cogl-context.c | 34 +- cogl/cogl-context.h | 20 +- cogl/cogl-draw-buffer-private.h | 126 ++++++ cogl/cogl-draw-buffer.c | 555 +++++++++++++++++++++++++ cogl/cogl-journal.c | 33 +- cogl/cogl-primitives.c | 19 +- cogl/cogl-texture.c | 19 +- cogl/cogl-vertex-buffer.c | 14 +- cogl/cogl.c | 222 ++++++---- cogl/cogl.h.in | 1 + cogl/driver/gl/Makefile.am | 2 - cogl/driver/gl/cogl-context-driver.c | 19 +- cogl/driver/gl/cogl-context-driver.h | 23 +- cogl/driver/gl/cogl-defines.h.in | 28 +- cogl/driver/gl/cogl-fbo.c | 315 -------------- cogl/driver/gl/cogl-fbo.h | 39 -- cogl/driver/gl/cogl-primitives.c | 99 +++-- cogl/driver/gl/cogl-texture-driver.c | 2 +- cogl/driver/gl/cogl.c | 110 ++--- cogl/driver/gles/Makefile.am | 2 - cogl/driver/gles/cogl-context-driver.c | 10 + cogl/driver/gles/cogl-context-driver.h | 17 +- cogl/driver/gles/cogl-defines.h.in | 70 ++++ cogl/driver/gles/cogl-fbo.c | 328 --------------- cogl/driver/gles/cogl-fbo.h | 39 -- cogl/driver/gles/cogl-primitives.c | 121 ++++-- cogl/driver/gles/cogl.c | 75 ++++ 30 files changed, 1474 insertions(+), 1090 deletions(-) create mode 100644 cogl/cogl-draw-buffer-private.h create mode 100644 cogl/cogl-draw-buffer.c delete mode 100644 cogl/driver/gl/cogl-fbo.c delete mode 100644 cogl/driver/gl/cogl-fbo.h delete mode 100644 cogl/driver/gles/cogl-fbo.c delete mode 100644 cogl/driver/gles/cogl-fbo.h diff --git a/cogl/Makefile.am b/cogl/Makefile.am index 81c5186d2..8988f8d35 100644 --- a/cogl/Makefile.am +++ b/cogl/Makefile.am @@ -120,6 +120,8 @@ libclutter_cogl_la_SOURCES = \ $(srcdir)/cogl-spans.c \ $(srcdir)/cogl-journal-private.h \ $(srcdir)/cogl-journal.c \ + $(srcdir)/cogl-draw-buffer-private.h \ + $(srcdir)/cogl-draw-buffer.c \ $(BUILT_SOURCES) \ $(NULL) diff --git a/cogl/cogl-clip-stack.c b/cogl/cogl-clip-stack.c index a0dc3bc49..8cf59d197 100644 --- a/cogl/cogl-clip-stack.c +++ b/cogl/cogl-clip-stack.c @@ -34,6 +34,7 @@ #include "cogl-primitives.h" #include "cogl-context.h" #include "cogl-internal.h" +#include "cogl-draw-buffer-private.h" /* These are defined in the particular backend (float in GL vs fixed in GL ES) */ @@ -119,15 +120,24 @@ cogl_clip_push_window_rect (float x_offset, float width, float height) { - CoglClipStackEntryWindowRect *entry; + CoglHandle draw_buffer; + CoglClipStackState *clip_state; CoglClipStack *stack; - float v[4]; + CoglClipStackEntryWindowRect *entry; + float viewport_height; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - stack = (CoglClipStack *) ctx->clip.stacks->data; + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); - cogl_get_viewport (v); + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + + stack = clip_state->stacks->data; + + viewport_height = _cogl_draw_buffer_get_viewport_height (draw_buffer); entry = g_slice_new (CoglClipStackEntryWindowRect); @@ -135,14 +145,14 @@ cogl_clip_push_window_rect (float x_offset, * with (0,0) at bottom left. */ entry->type = COGL_CLIP_STACK_WINDOW_RECT; entry->x0 = x_offset; - entry->y0 = v[3] - y_offset - height; + entry->y0 = viewport_height - y_offset - height; entry->x1 = x_offset + width; - entry->y1 = v[3] - y_offset; + entry->y1 = viewport_height - y_offset; /* Store it in the stack */ stack->stack_top = g_list_prepend (stack->stack_top, entry); - ctx->clip.stack_dirty = TRUE; + clip_state->stack_dirty = TRUE; } /* Scale from OpenGL <-1,1> coordinates system to window coordinates @@ -214,17 +224,26 @@ cogl_clip_push (float x_offset, float width, float height) { - CoglClipStackEntryRect *entry; + CoglHandle draw_buffer; + CoglClipStackState *clip_state; CoglClipStack *stack; + CoglClipStackEntryRect *entry; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + /* Try and catch window space rectangles so we can redirect to * cogl_clip_push_window_rect which will use scissoring. */ if (try_pushing_rect_as_window_rect (x_offset, y_offset, width, height)) return; - stack = (CoglClipStack *) ctx->clip.stacks->data; + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + + stack = clip_state->stacks->data; entry = g_slice_new (CoglClipStackEntryRect); @@ -240,18 +259,27 @@ cogl_clip_push (float x_offset, /* Store it in the stack */ stack->stack_top = g_list_prepend (stack->stack_top, entry); - ctx->clip.stack_dirty = TRUE; + clip_state->stack_dirty = TRUE; } void cogl_clip_push_from_path_preserve (void) { - CoglClipStackEntryPath *entry; + CoglHandle draw_buffer; + CoglClipStackState *clip_state; CoglClipStack *stack; + CoglClipStackEntryPath *entry; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - stack = (CoglClipStack *) ctx->clip.stacks->data; + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + + stack = clip_state->stacks->data; entry = g_malloc (sizeof (CoglClipStackEntryPath) + sizeof (CoglPathNode) * (ctx->path_nodes->len - 1)); @@ -268,7 +296,7 @@ cogl_clip_push_from_path_preserve (void) /* Store it in the stack */ stack->stack_top = g_list_prepend (stack->stack_top, entry); - ctx->clip.stack_dirty = TRUE; + clip_state->stack_dirty = TRUE; } void @@ -279,16 +307,18 @@ cogl_clip_push_from_path (void) cogl_path_new (); } -void -cogl_clip_pop (void) +static void +_cogl_clip_pop_real (CoglClipStackState *clip_state) { - gpointer entry; CoglClipStack *stack; + gpointer entry; CoglClipStackEntryType type; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); - stack = (CoglClipStack *) ctx->clip.stacks->data; + stack = clip_state->stacks->data; g_return_if_fail (stack->stack_top != NULL); @@ -306,35 +336,57 @@ cogl_clip_pop (void) stack->stack_top = g_list_delete_link (stack->stack_top, stack->stack_top); - ctx->clip.stack_dirty = TRUE; + clip_state->stack_dirty = TRUE; } void -_cogl_clip_stack_rebuild (void) +cogl_clip_pop (void) { - int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES); + CoglHandle draw_buffer; + CoglClipStackState *clip_state; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + + _cogl_clip_pop_real (clip_state); +} + +void +_cogl_flush_clip_state (CoglClipStackState *clip_state) +{ + CoglClipStack *stack; + int has_clip_planes; gboolean using_clip_planes = FALSE; gboolean using_stencil_buffer = FALSE; GList *node; - CoglClipStack *stack; gint scissor_x0 = 0; gint scissor_y0 = 0; gint scissor_x1 = G_MAXINT; gint scissor_y1 = G_MAXINT; - CoglMatrixStack *modelview_stack; + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - modelview_stack = ctx->modelview_stack; + if (!clip_state->stack_dirty) + return; /* The current primitive journal does not support tracking changes to the * clip stack... */ _cogl_journal_flush (); - stack = (CoglClipStack *) ctx->clip.stacks->data; + /* XXX: the handling of clipping is quite complex. It may involve use of + * the Cogl Journal or other Cogl APIs which may end up recursively + * wanting to ensure the clip state is flushed. We need to ensure we + * don't recurse infinitely... + */ + clip_state->stack_dirty = FALSE; - ctx->clip.stack_dirty = FALSE; - ctx->clip.stencil_used = FALSE; + has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES); + + stack = clip_state->stacks->data; + + clip_state->stencil_used = FALSE; _cogl_disable_clip_planes (); _cogl_disable_stencil_buffer (); @@ -433,74 +485,111 @@ _cogl_clip_stack_rebuild (void) scissor_y1 - scissor_y0)); } - ctx->clip.stencil_used = using_stencil_buffer; + clip_state->stencil_used = using_stencil_buffer; } +/* XXX: This should never have been made public API! */ void cogl_clip_ensure (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); + CoglClipStackState *clip_state; - if (ctx->clip.stack_dirty) - _cogl_clip_stack_rebuild (); + clip_state = _cogl_draw_buffer_get_clip_state (_cogl_get_draw_buffer ()); + _cogl_flush_clip_state (clip_state); +} + +static void +_cogl_clip_stack_save_real (CoglClipStackState *clip_state) +{ + CoglClipStack *stack; + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + stack = g_slice_new (CoglClipStack); + stack->stack_top = NULL; + + clip_state->stacks = g_slist_prepend (clip_state->stacks, stack); + clip_state->stack_dirty = TRUE; } void cogl_clip_stack_save (void) { - CoglClipStack *stack; + CoglHandle draw_buffer; + CoglClipStackState *clip_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - stack = g_slice_new (CoglClipStack); - stack->stack_top = NULL; + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); - ctx->clip.stacks = g_slist_prepend (ctx->clip.stacks, stack); + _cogl_clip_stack_save_real (clip_state); +} - ctx->clip.stack_dirty = TRUE; +static void +_cogl_clip_stack_restore_real (CoglClipStackState *clip_state) +{ + CoglClipStack *stack; + + g_return_if_fail (clip_state->stacks != NULL); + + /* We don't log clip stack changes in the journal so we must flush + * it before making modifications */ + _cogl_journal_flush (); + + stack = clip_state->stacks->data; + + /* Empty the current stack */ + while (stack->stack_top) + _cogl_clip_pop_real (clip_state); + + /* Revert to an old stack */ + g_slice_free (CoglClipStack, stack); + clip_state->stacks = g_slist_delete_link (clip_state->stacks, + clip_state->stacks); + + clip_state->stack_dirty = TRUE; } void cogl_clip_stack_restore (void) { - CoglClipStack *stack; + CoglHandle draw_buffer; + CoglClipStackState *clip_state; _COGL_GET_CONTEXT (ctx, NO_RETVAL); - g_return_if_fail (ctx->clip.stacks != NULL); + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); - stack = (CoglClipStack *) ctx->clip.stacks->data; - - /* Empty the current stack */ - while (stack->stack_top) - cogl_clip_pop (); - - /* Revert to an old stack */ - g_slice_free (CoglClipStack, stack); - ctx->clip.stacks = g_slist_delete_link (ctx->clip.stacks, - ctx->clip.stacks); - - ctx->clip.stack_dirty = TRUE; + _cogl_clip_stack_restore_real (clip_state); } void -_cogl_clip_stack_state_init (void) +_cogl_clip_stack_state_init (CoglClipStackState *clip_state) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - ctx->clip.stacks = NULL; - ctx->clip.stack_dirty = TRUE; + clip_state->stacks = NULL; + clip_state->stack_dirty = TRUE; /* Add an intial stack */ - cogl_clip_stack_save (); + _cogl_clip_stack_save_real (clip_state); } void -_cogl_clip_stack_state_destroy (void) +_cogl_clip_stack_state_destroy (CoglClipStackState *clip_state) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - /* Destroy all of the stacks */ - while (ctx->clip.stacks) - cogl_clip_stack_restore (); + while (clip_state->stacks) + _cogl_clip_stack_restore_real (clip_state); } + +void +_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state) +{ + clip_state->stack_dirty = TRUE; +} + diff --git a/cogl/cogl-clip-stack.h b/cogl/cogl-clip-stack.h index 324097b17..0ca041ec4 100644 --- a/cogl/cogl-clip-stack.h +++ b/cogl/cogl-clip-stack.h @@ -35,9 +35,10 @@ struct _CoglClipStackState gboolean stencil_used; }; -void _cogl_clip_stack_state_init (void); -void _cogl_clip_stack_state_destroy (void); -void _cogl_clip_stack_rebuild (void); -void _cogl_clip_stack_merge (void); +void _cogl_clip_stack_state_init (CoglClipStackState *state); +void _cogl_clip_stack_state_destroy (CoglClipStackState *state); +void _cogl_clip_stack_state_dirty (CoglClipStackState *state); + +void _cogl_flush_clip_state (CoglClipStackState *clip_state); #endif /* __COGL_CLIP_STACK_H */ diff --git a/cogl/cogl-context.c b/cogl/cogl-context.c index 6cbc7b7c2..8005aaf23 100644 --- a/cogl/cogl-context.c +++ b/cogl/cogl-context.c @@ -32,6 +32,7 @@ #include "cogl-journal-private.h" #include "cogl-texture-private.h" #include "cogl-material-private.h" +#include "cogl-draw-buffer-private.h" #include @@ -46,7 +47,7 @@ cogl_create_context (void) { GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; gulong enable_flags = 0; - CoglDrawBufferState *draw_buffer; + CoglHandle window_buffer; if (_context != NULL) return FALSE; @@ -66,8 +67,6 @@ cogl_create_context (void) _context->indirect = gl_is_indirect; _context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; - _context->modelview_stack = _cogl_matrix_stack_new (); - _context->projection_stack = _cogl_matrix_stack_new (); _context->texture_units = NULL; _context->default_material = cogl_material_new (); @@ -87,11 +86,14 @@ cogl_create_context (void) sizeof (CoglLayerInfo)); _context->n_texcoord_arrays_enabled = 0; - draw_buffer = g_slice_new0 (CoglDrawBufferState); - draw_buffer->target = COGL_WINDOW_BUFFER; - draw_buffer->offscreen = COGL_INVALID_HANDLE; - _context->draw_buffer_stack = - g_slist_prepend (NULL, draw_buffer); + _context->draw_buffer_stack = _cogl_create_draw_buffer_stack (); + window_buffer = _cogl_onscreen_new (); + /* XXX: When setting up the window buffer, cogl_set_draw_buffer + * assumes that the handle can be found in ctx->window_buffer */ + _context->window_buffer = window_buffer; + cogl_set_draw_buffer (COGL_WINDOW_BUFFER, 0/* ignored */); + _context->dirty_bound_framebuffer = TRUE; + _context->dirty_viewport = TRUE; _context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode)); _context->last_path = 0; @@ -99,20 +101,16 @@ cogl_create_context (void) _context->in_begin_gl_block = FALSE; - _context->viewport_width = 0; - _context->viewport_height = 0; - _context->quad_indices_byte = COGL_INVALID_HANDLE; _context->quad_indices_short = COGL_INVALID_HANDLE; _context->quad_indices_short_len = 0; _context->texture_download_material = COGL_INVALID_HANDLE; - /* Initialise the clip stack */ - _cogl_clip_stack_state_init (); - /* Initialise the driver specific state */ + /* TODO: combine these two into one function */ _cogl_create_context_driver (_context); + _cogl_features_init (); /* Create default textures used for fall backs */ _context->default_gl_texture_2d_tex = @@ -146,16 +144,14 @@ cogl_create_context (void) void _cogl_destroy_context () { + if (_context == NULL) return; - _cogl_clip_stack_state_destroy (); - - _cogl_matrix_stack_destroy (_context->modelview_stack); - _cogl_matrix_stack_destroy (_context->projection_stack); - _cogl_destroy_texture_units (); + _cogl_free_draw_buffer_stack (_context->draw_buffer_stack); + if (_context->path_nodes) g_array_free (_context->path_nodes, TRUE); diff --git a/cogl/cogl-context.h b/cogl/cogl-context.h index cf8e3ad84..67e33cc68 100644 --- a/cogl/cogl-context.h +++ b/cogl/cogl-context.h @@ -38,12 +38,6 @@ typedef struct GLubyte c[4]; } CoglTextureGLVertex; -typedef struct -{ - CoglBufferTarget target; - CoglHandle offscreen; -} CoglDrawBufferState; - typedef struct { /* Features cache */ @@ -60,9 +54,6 @@ typedef struct /* Client-side matrix stack or NULL if none */ CoglMatrixMode flushed_matrix_mode; - CoglMatrixStack *projection_stack; - CoglMatrixStack *modelview_stack; - GList *texture_units; /* Cache of inverse projection matrix */ @@ -91,11 +82,11 @@ typedef struct GArray *current_layers; guint n_texcoord_arrays_enabled; - /* Framebuffer objects */ + /* Draw Buffers */ GSList *draw_buffer_stack; - - /* Clip stack */ - CoglClipStackState clip; + CoglHandle window_buffer; + gboolean dirty_bound_framebuffer; + gboolean dirty_viewport; /* Primitives */ floatVec2 path_start; @@ -114,9 +105,6 @@ typedef struct gboolean in_begin_gl_block; - guint viewport_width; - guint viewport_height; - CoglHandle texture_download_material; CoglContextDriver drv; diff --git a/cogl/cogl-draw-buffer-private.h b/cogl/cogl-draw-buffer-private.h new file mode 100644 index 000000000..d5bdf0b11 --- /dev/null +++ b/cogl/cogl-draw-buffer-private.h @@ -0,0 +1,126 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __COGL_DRAW_BUFFER_PRIVATE_H +#define __COGL_DRAW_BUFFER_PRIVATE_H + +#include "cogl-handle.h" +#include "cogl-matrix-stack.h" +#include "cogl-clip-stack.h" + +typedef enum _CoglDrawBufferType { + COGL_DRAW_BUFFER_TYPE_ONSCREEN, + COGL_DRAW_BUFFER_TYPE_OFFSCREEN +} CoglDrawBufferType; + +typedef struct +{ + CoglHandleObject _parent; + CoglDrawBufferType type; + int width; + int height; + + CoglMatrixStack *modelview_stack; + CoglMatrixStack *projection_stack; + int viewport_x; + int viewport_y; + int viewport_width; + int viewport_height; + + CoglClipStackState clip_state; +} CoglDrawBuffer; + +#define COGL_DRAW_BUFFER(X) ((CoglDrawBuffer *)(X)) + +typedef struct _CoglDrawBufferStackEntry +{ + CoglBufferTarget target; + CoglHandle draw_buffer; +} CoglDrawBufferStackEntry; + +typedef struct _CoglOffscreen +{ + CoglDrawBuffer _parent; + GLuint fbo_handle; + GLuint gl_stencil_handle; +} CoglOffscreen; + +#define COGL_OFFSCREEN(X) ((CoglOffscreen *)(X)) + +typedef struct _CoglOnscreen +{ + CoglDrawBuffer _parent; +} CoglOnscreen; + +#define COGL_ONSCREEN(X) ((CoglOnscreen *)(X)) + +void +_cogl_draw_buffer_state_init (void); +CoglClipStackState * +_cogl_draw_buffer_get_clip_state (CoglHandle handle); +void +_cogl_draw_buffer_set_viewport (CoglHandle handle, + int x, + int y, + int width, + int height); +int +_cogl_draw_buffer_get_viewport_x (CoglHandle handle); +int +_cogl_draw_buffer_get_viewport_y (CoglHandle handle); +int +_cogl_draw_buffer_get_viewport_width (CoglHandle handle); +int +_cogl_draw_buffer_get_viewport_height (CoglHandle handle); +void +_cogl_draw_buffer_get_viewport4fv (CoglHandle handle, int *viewport); +CoglMatrixStack * +_cogl_draw_buffer_get_modelview_stack (CoglHandle handle); +CoglMatrixStack * +_cogl_draw_buffer_get_projection_stack (CoglHandle handle); + +typedef enum _CoglDrawBufferFlushFlags +{ + /* XXX: When using this, that imples you are going to manually load the + * modelview matrix (via glLoadMatrix). _cogl_matrix_stack_flush_to_gl wont + * be called for draw_buffer->modelview_stack, and the modelview_stack will + * also be marked as dirty. */ + COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW = 1L<<0, +} CoglDrawBufferFlushFlags; + +void +_cogl_draw_buffer_flush_state (CoglHandle handle, + CoglDrawBufferFlushFlags flags); + +CoglHandle +_cogl_onscreen_new (void); + +CoglHandle +_cogl_get_draw_buffer (void); +GSList * +_cogl_create_draw_buffer_stack (void); +void +_cogl_free_draw_buffer_stack (GSList *stack); + +#endif /* __COGL_DRAW_BUFFER_PRIVATE_H */ + diff --git a/cogl/cogl-draw-buffer.c b/cogl/cogl-draw-buffer.c new file mode 100644 index 000000000..41f0a5f91 --- /dev/null +++ b/cogl/cogl-draw-buffer.c @@ -0,0 +1,555 @@ +/* + * Cogl + * + * An object oriented GL/GLES Abstraction/Utility Layer + * + * Copyright (C) 2007,2008,2009 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "cogl.h" +#include "cogl-internal.h" +#include "cogl-context.h" +#include "cogl-handle.h" +#include "cogl-util.h" +#include "cogl-texture-private.h" +#include "cogl-draw-buffer-private.h" +#include "cogl-clip-stack.h" + +#ifdef HAVE_COGL_GLES2 + +#include "../gles/cogl-gles2-wrapper.h" + +#else + +#define glGenRenderbuffers ctx->drv.pf_glGenRenderbuffers +#define glDeleteRenderbuffers ctx->drv.pf_glDeleteRenderbuffers +#define glBindRenderbuffer ctx->drv.pf_glBindRenderbuffer +#define glRenderbufferStorage ctx->drv.pf_glRenderbufferStorage +#define glGenFramebuffers ctx->drv.pf_glGenFramebuffers +#define glBindFramebuffer ctx->drv.pf_glBindFramebuffer +#define glFramebufferTexture2D ctx->drv.pf_glFramebufferTexture2D +#define glFramebufferRenderbuffer ctx->drv.pf_glFramebufferRenderbuffer +#define glCheckFramebufferStatus ctx->drv.pf_glCheckFramebufferStatus +#define glDeleteFramebuffers ctx->drv.pf_glDeleteFramebuffers + +#endif + +#ifndef GL_FRAMEBUFFER +#define GL_FRAMEBUFFER 0x8D40 +#endif +#ifndef GL_RENDERBUFFER +#define GL_RENDERBUFFER 0x8D41 +#endif +#ifndef GL_STENCIL_ATTACHMENT +#define GL_STENCIL_ATTACHMENT 0x8D00 +#endif +#ifndef GL_COLOR_ATTACHMENT0 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#endif +#ifndef GL_FRAMEBUFFER_COMPLETE +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#endif +#ifndef GL_STENCIL_INDEX8 +#define GL_STENCIL_INDEX8 0x8D48 +#endif + +static void _cogl_draw_buffer_free (CoglDrawBuffer *draw_buffer); +static void _cogl_onscreen_free (CoglOnscreen *onscreen); +static void _cogl_offscreen_free (CoglOffscreen *offscreen); + +COGL_HANDLE_DEFINE (Onscreen, onscreen); +COGL_HANDLE_DEFINE (Offscreen, offscreen); + +/* XXX: + * The CoglHandle macros don't support any form of inheritance, so for + * now we implement the CoglHandle support for the CoglDrawBuffer + * abstract class manually. + */ + +gboolean +cogl_is_draw_buffer (CoglHandle handle) +{ + CoglHandleObject *obj = (CoglHandleObject *)handle; + + if (handle == COGL_INVALID_HANDLE) + return FALSE; + + return obj->klass->type == _cogl_handle_onscreen_get_type () + || obj->klass->type == _cogl_handle_offscreen_get_type (); +} + +static void +_cogl_draw_buffer_init (CoglDrawBuffer *draw_buffer, + CoglDrawBufferType type, + int width, + int height) +{ + draw_buffer->type = type; + draw_buffer->width = width; + draw_buffer->height = height; + draw_buffer->viewport_x = 0; + draw_buffer->viewport_y = 0; + draw_buffer->viewport_width = width; + draw_buffer->viewport_height = height; + + draw_buffer->modelview_stack = _cogl_matrix_stack_new (); + draw_buffer->projection_stack = _cogl_matrix_stack_new (); + + /* Initialise the clip stack */ + _cogl_clip_stack_state_init (&draw_buffer->clip_state); +} + +void +_cogl_draw_buffer_free (CoglDrawBuffer *draw_buffer) +{ + _cogl_clip_stack_state_destroy (&draw_buffer->clip_state); + + _cogl_matrix_stack_destroy (draw_buffer->modelview_stack); + draw_buffer->modelview_stack = NULL; + + _cogl_matrix_stack_destroy (draw_buffer->projection_stack); + draw_buffer->projection_stack = NULL; +} + +CoglClipStackState * +_cogl_draw_buffer_get_clip_state (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + + return &draw_buffer->clip_state; +} + +void +_cogl_draw_buffer_set_viewport (CoglHandle handle, + int x, + int y, + int width, + int height) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + if (draw_buffer->viewport_x == x && + draw_buffer->viewport_y == y && + draw_buffer->viewport_width == width && + draw_buffer->viewport_height == height) + return; + + _cogl_journal_flush (); + + draw_buffer->viewport_x = x; + draw_buffer->viewport_y = y; + draw_buffer->viewport_width = width; + draw_buffer->viewport_height = height; + + if (_cogl_get_draw_buffer () == draw_buffer) + ctx->dirty_viewport = TRUE; +} + +int +_cogl_draw_buffer_get_viewport_x (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->viewport_x; +} + +int +_cogl_draw_buffer_get_viewport_y (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->viewport_y; +} + +int +_cogl_draw_buffer_get_viewport_width (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->viewport_width; +} + +int +_cogl_draw_buffer_get_viewport_height (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->viewport_height; +} + +void +_cogl_draw_buffer_get_viewport4fv (CoglHandle handle, int *viewport) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + viewport[0] = draw_buffer->viewport_x; + viewport[1] = draw_buffer->viewport_y; + viewport[2] = draw_buffer->viewport_width; + viewport[3] = draw_buffer->viewport_height; +} + +CoglMatrixStack * +_cogl_draw_buffer_get_modelview_stack (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->modelview_stack; +} + +CoglMatrixStack * +_cogl_draw_buffer_get_projection_stack (CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle); + return draw_buffer->projection_stack; +} + +CoglHandle +cogl_offscreen_new_to_texture (CoglHandle texhandle) +{ + CoglOffscreen *offscreen; + int width; + int height; + GLuint tex_gl_handle; + GLenum tex_gl_target; + GLuint fbo_gl_handle; + GLuint gl_stencil_handle; + GLenum status; + + _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); + + if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) + return COGL_INVALID_HANDLE; + + /* Make texhandle is a valid texture object */ + if (!cogl_is_texture (texhandle)) + return COGL_INVALID_HANDLE; + + /* The texture must not be sliced */ + if (cogl_texture_is_sliced (texhandle)) + return COGL_INVALID_HANDLE; + + /* Pick the single texture slice width, height and GL id */ + + width = cogl_texture_get_width (texhandle); + height = cogl_texture_get_height (texhandle); + + if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) + return COGL_INVALID_HANDLE; + + if (tex_gl_target != GL_TEXTURE_2D) + return COGL_INVALID_HANDLE; + + /* Create a renderbuffer for stenciling */ + GE (glGenRenderbuffers (1, &gl_stencil_handle)); + GE (glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle)); + GE (glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, + cogl_texture_get_width (texhandle), + cogl_texture_get_height (texhandle))); + GE (glBindRenderbuffer (GL_RENDERBUFFER, 0)); + + /* We are about to generate and bind a new fbo, so when next flushing the + * journal, we will need to rebind the current draw buffer... */ + ctx->dirty_bound_framebuffer = 1; + + /* Generate framebuffer */ + glGenFramebuffers (1, &fbo_gl_handle); + GE (glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle)); + GE (glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + tex_gl_target, tex_gl_handle, 0)); + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, gl_stencil_handle)); + + /* XXX: The framebuffer_object spec isn't clear in defining whether attaching + * a texture as a renderbuffer with mipmap filtering enabled while the + * mipmaps have not been uploaded should result in an incomplete framebuffer + * object. (different drivers make different decisions) + * + * To avoid an error with drivers that do consider this a problem we + * explicitly set non mipmapped filters here. These will later be reset when + * the texture is actually used for rendering according to the filters set on + * the corresponding CoglMaterial. + */ + _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST); + + /* Make sure it's complete */ + status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + /* Stencil renderbuffers aren't always supported. Try again + without the stencil buffer */ + GE (glFramebufferRenderbuffer (GL_FRAMEBUFFER, + GL_STENCIL_ATTACHMENT, + GL_RENDERBUFFER, + 0)); + GE (glDeleteRenderbuffers (1, &gl_stencil_handle)); + gl_stencil_handle = 0; + + status = glCheckFramebufferStatus (GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) + { + /* Still failing, so give up */ + GE (glDeleteFramebuffers (1, &fbo_gl_handle)); + GE (glBindFramebuffer (GL_FRAMEBUFFER, 0)); + return COGL_INVALID_HANDLE; + } + } + + offscreen = g_new0 (CoglOffscreen, 1); + + _cogl_draw_buffer_init (COGL_DRAW_BUFFER (offscreen), + COGL_DRAW_BUFFER_TYPE_OFFSCREEN, + width, + height); + + offscreen->fbo_handle = fbo_gl_handle; + offscreen->gl_stencil_handle = gl_stencil_handle; + + /* XXX: Can we get a away with removing this? It wasn't documented, and most + * users of the API are hopefully setting up the modelview from scratch + * anyway */ +#if 0 + cogl_matrix_translate (&draw_buffer->modelview, -1.0f, -1.0f, 0.0f); + cogl_matrix_scale (&draw_buffer->modelview, + 2.0f / draw_buffer->width, 2.0f / draw_buffer->height, 1.0f); +#endif + + return _cogl_offscreen_handle_new (offscreen); +} + +static void +_cogl_offscreen_free (CoglOffscreen *offscreen) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* Chain up to parent */ + _cogl_draw_buffer_free (COGL_DRAW_BUFFER (offscreen)); + + if (offscreen->gl_stencil_handle) + GE (glDeleteRenderbuffers (1, &offscreen->gl_stencil_handle)); + GE (glDeleteFramebuffers (1, &offscreen->fbo_handle)); + g_free (offscreen); +} + +CoglHandle +_cogl_onscreen_new (void) +{ + CoglOnscreen *onscreen; + + /* XXX: Until we have full winsys support in Cogl then we can't fully + * implement CoglOnscreen draw buffers, since we can't, e.g. keep track of + * the window size. */ + + onscreen = g_new0 (CoglOnscreen, 1); + _cogl_draw_buffer_init (COGL_DRAW_BUFFER (onscreen), + COGL_DRAW_BUFFER_TYPE_ONSCREEN, + 0xdeadbeef, /* width */ + 0xdeadbeef); /* height */ + + return _cogl_onscreen_handle_new (onscreen); +} + +static void +_cogl_onscreen_free (CoglOnscreen *onscreen) +{ + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + /* Chain up to parent */ + _cogl_draw_buffer_free (COGL_DRAW_BUFFER (onscreen)); + + g_free (onscreen); +} + +GSList * +_cogl_create_draw_buffer_stack (void) +{ + GSList *stack = NULL; + CoglDrawBufferStackEntry *entry; + + entry = g_slice_new0 (CoglDrawBufferStackEntry); + entry->target = COGL_WINDOW_BUFFER; + entry->draw_buffer = COGL_INVALID_HANDLE; + + return g_slist_prepend (stack, entry); +} + +void +_cogl_free_draw_buffer_stack (GSList *stack) +{ + GSList *l; + + for (l = stack; l != NULL; l = l->next) + { + CoglDrawBufferStackEntry *entry = l->data; + CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (entry->draw_buffer); + if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN) + _cogl_offscreen_free (COGL_OFFSCREEN (draw_buffer)); + else + _cogl_onscreen_free (COGL_ONSCREEN (draw_buffer)); + } + g_slist_free (stack); +} + +/* XXX: The target argument is redundant; when we break API, we should + * remove it! */ +void +cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle handle) +{ + CoglDrawBuffer *draw_buffer = NULL; + CoglDrawBufferStackEntry *entry; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + _cogl_journal_flush (); + + g_assert (ctx->draw_buffer_stack != NULL); + entry = ctx->draw_buffer_stack->data; + + if (target == COGL_WINDOW_BUFFER) + handle = ctx->window_buffer; + else if (!cogl_is_draw_buffer (handle)) + return; + + draw_buffer = COGL_DRAW_BUFFER (handle); + + if (entry->draw_buffer != draw_buffer) + { + entry->target = target; + + ctx->dirty_bound_framebuffer = 1; + ctx->dirty_viewport = 1; + + if (draw_buffer != COGL_INVALID_HANDLE) + cogl_handle_ref (draw_buffer); + if (entry->draw_buffer != COGL_INVALID_HANDLE) + cogl_handle_unref (entry->draw_buffer); + entry->draw_buffer = draw_buffer; + + /* We've effectively just switched the current modelview and + * projection matrix stacks and clip state so we need to dirty + * them to ensure they get flushed for the next batch of geometry + * we flush */ + _cogl_matrix_stack_dirty (draw_buffer->modelview_stack); + _cogl_matrix_stack_dirty (draw_buffer->projection_stack); + _cogl_clip_stack_state_dirty (&draw_buffer->clip_state); + } +} + +CoglHandle +_cogl_get_draw_buffer (void) +{ + CoglDrawBufferStackEntry *entry; + + _COGL_GET_CONTEXT (ctx, NULL); + + g_assert (ctx->draw_buffer_stack); + entry = ctx->draw_buffer_stack->data; + + return entry->draw_buffer; +} + +void +cogl_push_draw_buffer (void) +{ + CoglDrawBufferStackEntry *old; + CoglDrawBufferStackEntry *entry; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + entry = g_slice_new0 (CoglDrawBufferStackEntry); + + g_assert (ctx->draw_buffer_stack); + + old = ctx->draw_buffer_stack->data; + *entry = *old; + + cogl_handle_ref (entry->draw_buffer); + + ctx->draw_buffer_stack = + g_slist_prepend (ctx->draw_buffer_stack, entry); +} + +void +cogl_pop_draw_buffer (void) +{ + CoglDrawBufferStackEntry *to_pop; + CoglDrawBufferStackEntry *to_restore; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + g_assert (ctx->draw_buffer_stack != NULL); + + to_pop = ctx->draw_buffer_stack->data; + to_restore = ctx->draw_buffer_stack->next->data; + + cogl_set_draw_buffer (to_restore->target, to_restore->draw_buffer); + + cogl_handle_unref (to_pop->draw_buffer); + ctx->draw_buffer_stack = + g_slist_remove_link (ctx->draw_buffer_stack, + ctx->draw_buffer_stack); + g_slice_free (CoglDrawBufferStackEntry, to_pop); +} + +void +_cogl_draw_buffer_flush_state (CoglHandle handle, + CoglDrawBufferFlushFlags flags) +{ + CoglDrawBuffer *draw_buffer; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + draw_buffer = COGL_DRAW_BUFFER (handle); + + if (cogl_features_available (COGL_FEATURE_OFFSCREEN) && + ctx->dirty_bound_framebuffer) + { + if (draw_buffer->type == COGL_DRAW_BUFFER_TYPE_OFFSCREEN) + { + GE (glBindFramebuffer (GL_FRAMEBUFFER, + COGL_OFFSCREEN (draw_buffer)->fbo_handle)); + } + else + GE (glBindFramebuffer (GL_FRAMEBUFFER, 0)); + ctx->dirty_bound_framebuffer = FALSE; + } + + if (ctx->dirty_viewport) + { + GE (glViewport (draw_buffer->viewport_x, + draw_buffer->viewport_y, + draw_buffer->viewport_width, + draw_buffer->viewport_height)); + ctx->dirty_viewport = FALSE; + } + + /* XXX: Flushing clip state may trash the modelview and projection + * matrices so we must do it before flushing the matrices... + */ + _cogl_flush_clip_state (&draw_buffer->clip_state); + + if (!(flags & COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW)) + _cogl_matrix_stack_flush_to_gl (draw_buffer->modelview_stack, + COGL_MATRIX_MODELVIEW); + + _cogl_matrix_stack_flush_to_gl (draw_buffer->projection_stack, + COGL_MATRIX_PROJECTION); +} + diff --git a/cogl/cogl-journal.c b/cogl/cogl-journal.c index aa0d5892e..a50bf8e42 100644 --- a/cogl/cogl-journal.c +++ b/cogl/cogl-journal.c @@ -32,6 +32,7 @@ #include "cogl-texture-private.h" #include "cogl-material-private.h" #include "cogl-vertex-buffer-private.h" +#include "cogl-draw-buffer-private.h" #include #include @@ -531,6 +532,8 @@ _cogl_journal_flush (void) GLuint journal_vbo; gboolean vbo_fallback = (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; + CoglHandle draw_buffer; + CoglMatrixStack *modelview_stack; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -547,20 +550,19 @@ _cogl_journal_flush (void) else state.vbo_offset = (char *)ctx->logged_vertices->data; - _cogl_matrix_stack_flush_to_gl (ctx->projection_stack, - COGL_MATRIX_PROJECTION); + draw_buffer = _cogl_get_draw_buffer (); + modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer); + state.modelview_stack = modelview_stack; - state.modelview_stack = ctx->modelview_stack; - _cogl_matrix_stack_push (ctx->modelview_stack); + _cogl_matrix_stack_push (modelview_stack); /* If we have transformed all our quads at log time then we ensure no * further model transform is applied by loading the identity matrix * here... */ if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) { - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, - COGL_MATRIX_MODELVIEW); + _cogl_matrix_stack_load_identity (modelview_stack); + _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW); } /* batch_and_call() batches a list of journal entries according to some @@ -591,7 +593,7 @@ _cogl_journal_flush (void) _cogl_journal_flush_vbo_offsets_and_entries, /* callback */ &state); /* data */ - _cogl_matrix_stack_pop (ctx->modelview_stack); + _cogl_matrix_stack_pop (modelview_stack); for (i = 0; i < ctx->journal->len; i++) { @@ -607,6 +609,18 @@ _cogl_journal_flush (void) g_array_set_size (ctx->logged_vertices, 0); } +static void +_cogl_journal_init (void) +{ + /* Here we flush anything that we know must remain constant until the + * next the the journal is flushed. Note: This lets up flush things + * that themselves depend on the journal, such as clip state. */ + + /* NB: the journal deals with flushing the modelview stack manually */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), + COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW); +} + void _cogl_journal_log_quad (float x_1, float y_1, @@ -632,6 +646,9 @@ _cogl_journal_log_quad (float x_1, _COGL_GET_CONTEXT (ctx, NO_RETVAL); + if (ctx->logged_vertices->len == 0) + _cogl_journal_init (); + /* The vertex data is logged into a separate array in a layout that can be * directly passed to OpenGL */ diff --git a/cogl/cogl-primitives.c b/cogl/cogl-primitives.c index 016833ad3..45ec90ce6 100644 --- a/cogl/cogl-primitives.c +++ b/cogl/cogl-primitives.c @@ -32,6 +32,7 @@ #include "cogl-texture-private.h" #include "cogl-material-private.h" #include "cogl-vertex-buffer-private.h" +#include "cogl-draw-buffer-private.h" #include #include @@ -396,8 +397,6 @@ _cogl_rectangles_with_multitexture_coords ( _COGL_GET_CONTEXT (ctx, NO_RETVAL); - cogl_clip_ensure (); - material = ctx->source_material; layers = cogl_material_get_layers (material); @@ -706,7 +705,6 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle, options.layer0_override_texture = gl_handle; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_flush_matrix_stacks (); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices)); } @@ -840,7 +838,6 @@ _cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices, options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR; options.fallback_layers = fallback_layers; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_flush_matrix_stacks (); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); } @@ -866,7 +863,11 @@ cogl_polygon (CoglTextureVertex *vertices, _COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_journal_flush (); - cogl_clip_ensure (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); material = ctx->source_material; layers = cogl_material_get_layers (ctx->source_material); @@ -1030,9 +1031,6 @@ cogl_path_fill_preserve (void) { _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_journal_flush (); - cogl_clip_ensure (); - if (ctx->path_nodes->len == 0) return; @@ -1055,10 +1053,7 @@ cogl_path_stroke_preserve (void) if (ctx->path_nodes->len == 0) return; - _cogl_journal_flush (); - cogl_clip_ensure (); - - _cogl_path_stroke_nodes(); + _cogl_path_stroke_nodes (); } void diff --git a/cogl/cogl-texture.c b/cogl/cogl-texture.c index fa33f047d..763edbc2e 100644 --- a/cogl/cogl-texture.c +++ b/cogl/cogl-texture.c @@ -42,6 +42,7 @@ #include "cogl-context.h" #include "cogl-handle.h" #include "cogl-primitives.h" +#include "cogl-draw-buffer-private.h" #include #include @@ -667,7 +668,8 @@ _cogl_texture_draw_and_read (CoglTexture *tex, GLuint target_gl_type) { gint bpp; - GLint viewport[4]; + CoglHandle draw_buffer; + int viewport[4]; CoglBitmap alpha_bmp; CoglHandle prev_source; CoglMatrixStack *projection_stack; @@ -677,8 +679,9 @@ _cogl_texture_draw_and_read (CoglTexture *tex, bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); + draw_buffer = _cogl_get_draw_buffer (); /* Viewport needs to have some size and be inside the window for this */ - GE( glGetIntegerv (GL_VIEWPORT, viewport)); + _cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport); if (viewport[0] < 0 || viewport[1] < 0 || viewport[2] <= 0 || viewport[3] <= 0) return FALSE; @@ -688,16 +691,18 @@ _cogl_texture_draw_and_read (CoglTexture *tex, * works) */ - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); - _cogl_matrix_stack_ortho (ctx->projection_stack, + projection_stack = _cogl_draw_buffer_get_projection_stack (draw_buffer); + _cogl_matrix_stack_push (projection_stack); + _cogl_matrix_stack_load_identity (projection_stack); + _cogl_matrix_stack_ortho (projection_stack, 0, (float)(viewport[2]), 0, (float)(viewport[3]), (float)(0), (float)(100)); - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); + modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer); + _cogl_matrix_stack_push (modelview_stack); + _cogl_matrix_stack_load_identity (modelview_stack); /* Direct copy operation */ diff --git a/cogl/cogl-vertex-buffer.c b/cogl/cogl-vertex-buffer.c index c1aa172f4..357d1e6e5 100644 --- a/cogl/cogl-vertex-buffer.c +++ b/cogl/cogl-vertex-buffer.c @@ -138,6 +138,7 @@ #include "cogl-texture-private.h" #include "cogl-material-private.h" #include "cogl-primitives.h" +#include "cogl-draw-buffer-private.h" #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ (VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) @@ -1664,6 +1665,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer) } ctx->n_texcoord_arrays_enabled = max_texcoord_attrib_unit + 1; + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); + options.flags = COGL_MATERIAL_FLUSH_FALLBACK_MASK | COGL_MATERIAL_FLUSH_DISABLE_MASK; @@ -1753,15 +1759,11 @@ cogl_vertex_buffer_draw (CoglHandle handle, return; _cogl_journal_flush (); - cogl_clip_ensure (); buffer = _cogl_vertex_buffer_pointer_from_handle (handle); - cogl_clip_ensure (); - _cogl_flush_matrix_stacks (); enable_state_for_drawing_buffer (buffer); - /* FIXME: flush cogl cache */ GE (glDrawArrays (mode, first, count)); disable_state_for_drawing_buffer (buffer); @@ -1885,7 +1887,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, return; _cogl_journal_flush (); - cogl_clip_ensure (); buffer = _cogl_vertex_buffer_pointer_from_handle (handle); @@ -1894,8 +1895,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle); - cogl_clip_ensure (); - _cogl_flush_matrix_stacks (); enable_state_for_drawing_buffer (buffer); byte_offset = indices_offset * get_indices_type_size (indices->type); @@ -1905,7 +1904,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle, GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, GPOINTER_TO_UINT (indices->vbo_name))); - /* FIXME: flush cogl cache */ GE (glDrawRangeElements (mode, min_index, max_index, count, indices->type, (void *)byte_offset)); diff --git a/cogl/cogl.c b/cogl/cogl.c index 4fb1c7e67..8fdb36ff8 100644 --- a/cogl/cogl.c +++ b/cogl/cogl.c @@ -38,6 +38,7 @@ #include "cogl-context.h" #include "cogl-material-private.h" #include "cogl-winsys.h" +#include "cogl-draw-buffer-private.h" #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) #include "cogl-gles2-wrapper.h" @@ -116,7 +117,12 @@ cogl_clear (const CoglColor *color, gulong buffers) COGL_NOTE (DRAW, "Clear begin"); - cogl_clip_ensure (); + _cogl_journal_flush (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); if (buffers & COGL_BUFFER_BIT_COLOR) { @@ -327,6 +333,10 @@ set_clip_plane (GLint plane_num, #endif GLfloat angle; CoglMatrix inverse_projection; + CoglHandle draw_buffer = _cogl_get_draw_buffer (); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (draw_buffer); + _COGL_GET_CONTEXT (ctx, NO_RETVAL); /* Calculate the angle between the axes and the line crossing the @@ -334,24 +344,25 @@ set_clip_plane (GLint plane_num, angle = atan2f (vertex_b[1] - vertex_a[1], vertex_b[0] - vertex_a[0]) * (180.0/G_PI); - _cogl_matrix_stack_push (ctx->modelview_stack); + _cogl_matrix_stack_push (modelview_stack); + /* Load the identity matrix and multiply by the reverse of the projection matrix so we can specify the plane in screen coordinates */ - _cogl_matrix_stack_load_identity (ctx->modelview_stack); + _cogl_matrix_stack_load_identity (modelview_stack); cogl_matrix_init_from_array (&inverse_projection, ctx->inverse_projection); - _cogl_matrix_stack_multiply (ctx->modelview_stack, &inverse_projection); + _cogl_matrix_stack_multiply (modelview_stack, &inverse_projection); /* Rotate about point a */ - _cogl_matrix_stack_translate (ctx->modelview_stack, + _cogl_matrix_stack_translate (modelview_stack, vertex_a[0], vertex_a[1], vertex_a[2]); /* Rotate the plane by the calculated angle so that it will connect the two points */ - _cogl_matrix_stack_rotate (ctx->modelview_stack, angle, 0.0f, 0.0f, 1.0f); - _cogl_matrix_stack_translate (ctx->modelview_stack, + _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f); + _cogl_matrix_stack_translate (modelview_stack, -vertex_a[0], -vertex_a[1], -vertex_a[2]); - _cogl_flush_matrix_stacks (); + _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW); plane[0] = 0; plane[1] = -1.0; @@ -363,7 +374,7 @@ set_clip_plane (GLint plane_num, GE( glClipPlane (plane_num, plane) ); #endif - _cogl_matrix_stack_pop (ctx->modelview_stack); + _cogl_matrix_stack_pop (modelview_stack); } void @@ -372,7 +383,12 @@ _cogl_set_clip_planes (float x_offset, float width, float height) { + CoglHandle draw_buffer = _cogl_get_draw_buffer (); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (draw_buffer); CoglMatrix modelview_matrix; + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (draw_buffer); CoglMatrix projection_matrix; float vertex_tl[4] = { x_offset, y_offset, 0, 1.0 }; @@ -381,10 +397,8 @@ _cogl_set_clip_planes (float x_offset, float vertex_br[4] = { x_offset + width, y_offset + height, 0, 1.0 }; - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - _cogl_matrix_stack_get (ctx->projection_stack, &projection_matrix); - _cogl_matrix_stack_get (ctx->modelview_stack, &modelview_matrix); + _cogl_matrix_stack_get (projection_stack, &projection_matrix); + _cogl_matrix_stack_get (modelview_stack, &modelview_matrix); project_vertex (&modelview_matrix, &projection_matrix, vertex_tl); project_vertex (&modelview_matrix, &projection_matrix, vertex_tr); @@ -422,6 +436,7 @@ _cogl_add_stencil_clip (float x_offset, gboolean first) { CoglHandle current_source; + CoglHandle draw_buffer = _cogl_get_draw_buffer (); _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -429,6 +444,8 @@ _cogl_add_stencil_clip (float x_offset, * batched geometry before we start... */ _cogl_journal_flush (); + _cogl_draw_buffer_flush_state (draw_buffer, 0); + /* temporarily swap in our special stenciling material */ current_source = cogl_handle_ref (ctx->source_material); cogl_set_source (ctx->stencil_material); @@ -450,6 +467,11 @@ _cogl_add_stencil_clip (float x_offset, } else { + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (draw_buffer); + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (draw_buffer); + /* Add one to every pixel of the stencil buffer in the rectangle */ GE( glStencilFunc (GL_NEVER, 0x1, 0x3) ); @@ -466,16 +488,16 @@ _cogl_add_stencil_clip (float x_offset, rectangle are set will be valid */ GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); + _cogl_matrix_stack_push (projection_stack); + _cogl_matrix_stack_load_identity (projection_stack); - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); + _cogl_matrix_stack_push (modelview_stack); + _cogl_matrix_stack_load_identity (modelview_stack); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); - _cogl_matrix_stack_pop (ctx->modelview_stack); - _cogl_matrix_stack_pop (ctx->projection_stack); + _cogl_matrix_stack_pop (modelview_stack); + _cogl_matrix_stack_pop (projection_stack); } /* make sure our rectangles hit the stencil buffer before we restore @@ -515,19 +537,32 @@ _cogl_disable_clip_planes (void) GE( glDisable (GL_CLIP_PLANE0) ); } -/* XXX: This should be deprecated and Cogl should be left to manage - * the glViewport automatically when switching draw buffers. */ +void +_cogl_set_viewport (int x, + int y, + int width, + int height) +{ + CoglHandle draw_buffer; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + + draw_buffer = _cogl_get_draw_buffer (); + + _cogl_draw_buffer_set_viewport (draw_buffer, + x, + y, + width, + height); +} + +/* XXX: This should be deprecated, and we should expose a way to also + * specify an x and y viewport offset */ void cogl_viewport (guint width, guint height) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - COGL_NOTE (MISC, "glViewport(0, 0, %u, %u)", width, height); - GE( glViewport (0, 0, width, height) ); - - ctx->viewport_width = width; - ctx->viewport_height = height; + _cogl_set_viewport (0, 0, width, height); } void @@ -540,6 +575,7 @@ _cogl_setup_viewport (guint width, { float z_camera; CoglMatrix projection_matrix; + CoglMatrixStack *modelview_stack; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -593,11 +629,13 @@ _cogl_setup_viewport (guint width, cogl_get_projection_matrix (&projection_matrix); z_camera = 0.5 * projection_matrix.xx; - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - _cogl_matrix_stack_translate (ctx->modelview_stack, -0.5f, -0.5f, -z_camera); - _cogl_matrix_stack_scale (ctx->modelview_stack, + modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_load_identity (modelview_stack); + _cogl_matrix_stack_translate (modelview_stack, -0.5f, -0.5f, -z_camera); + _cogl_matrix_stack_scale (modelview_stack, 1.0f / width, -1.0f / height, 1.0f / width); - _cogl_matrix_stack_translate (ctx->modelview_stack, + _cogl_matrix_stack_translate (modelview_stack, 0.0f, -1.0 * height, 0.0f); } @@ -606,9 +644,6 @@ cogl_get_features (void) { _COGL_GET_CONTEXT (ctx, 0); - if (!ctx->features_cached) - _cogl_features_init (); - if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS) ctx->feature_flags &= ~COGL_FEATURE_VBOS; @@ -626,18 +661,24 @@ cogl_features_available (CoglFeatureFlags features) return (ctx->feature_flags & features) == features; } -/* XXX: This function should be deprecated, and replaced with a - * cogl_draw_buffer_get_size() API instead. We don't support offset - * viewports, and you can't have floating point viewport sizes. */ +/* XXX: This function should either be replaced with one returning + * integers, or removed/deprecated and make the + * _cogl_draw_buffer_get_viewport* functions public. + */ void cogl_get_viewport (float v[4]) { + CoglHandle draw_buffer; + int viewport[4]; + int i; + _COGL_GET_CONTEXT (ctx, NO_RETVAL); - v[0] = 0; - v[1] = 0; - v[2] = ctx->viewport_width; - v[3] = ctx->viewport_height; + draw_buffer = _cogl_get_draw_buffer (); + _cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport); + + for (i = 0; i < 4; i++) + v[i] = viewport[i]; } void @@ -733,7 +774,7 @@ cogl_disable_fog (void) void cogl_flush_gl_state (int flags) { - _cogl_flush_matrix_stacks (); + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); } #endif @@ -752,18 +793,20 @@ cogl_read_pixels (int x, CoglPixelFormat format, guint8 *pixels) { - GLint viewport[4]; - GLint viewport_height; - int rowstride = width * 4; - guint8 *temprow; + int viewport_height; + int rowstride = width * 4; + guint8 *temprow; + CoglHandle draw_buffer; + + _COGL_GET_CONTEXT (ctx, NO_RETVAL); g_return_if_fail (format == COGL_PIXEL_FORMAT_RGBA_8888); g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER); temprow = g_alloca (rowstride * sizeof (guint8)); - glGetIntegerv (GL_VIEWPORT, viewport); - viewport_height = viewport[3]; + draw_buffer = _cogl_get_draw_buffer (); + viewport_height = _cogl_draw_buffer_get_viewport_height (draw_buffer); /* The y co-ordinate should be given in OpenGL's coordinate system so 0 is the bottom row */ @@ -825,12 +868,13 @@ cogl_begin_gl (void) /* Flush all batched primitives */ cogl_flush (); - /* Flush our clipping state to GL */ - cogl_clip_ensure (); - - /* Flush any client side matrix state */ - _cogl_flush_matrix_stacks (); - + /* Flush framebuffer state, including clip state, modelview and + * projection matrix state + * + * NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); /* Setup the state for the current material */ @@ -940,36 +984,41 @@ _cogl_destroy_texture_units (void) void cogl_push_matrix (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_push (ctx->modelview_stack); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_push (modelview_stack); } void cogl_pop_matrix (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_pop (ctx->modelview_stack); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_pop (modelview_stack); } void cogl_scale (float x, float y, float z) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_scale (ctx->modelview_stack, x, y, z); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_scale (modelview_stack, x, y, z); } void cogl_translate (float x, float y, float z) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_translate (ctx->modelview_stack, x, y, z); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_translate (modelview_stack, x, y, z); } void cogl_rotate (float angle, float x, float y, float z) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_rotate (ctx->modelview_stack, angle, x, y, z); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z); } void @@ -997,12 +1046,14 @@ cogl_frustum (float left, float z_far) { float c, d; + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ()); _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_load_identity (ctx->projection_stack); + _cogl_matrix_stack_load_identity (projection_stack); - _cogl_matrix_stack_frustum (ctx->projection_stack, + _cogl_matrix_stack_frustum (projection_stack, left, right, bottom, @@ -1036,12 +1087,14 @@ cogl_ortho (float left, float z_far) { CoglMatrix ortho; + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ()); _COGL_GET_CONTEXT (ctx, NO_RETVAL); cogl_matrix_init_identity (&ortho); cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far); - _cogl_matrix_stack_set (ctx->projection_stack, &ortho); + _cogl_matrix_stack_set (projection_stack, &ortho); /* Calculate and store the inverse of the matrix */ memset (ctx->inverse_projection, 0, sizeof (float) * 16); @@ -1060,41 +1113,44 @@ cogl_ortho (float left, void cogl_get_modelview_matrix (CoglMatrix *matrix) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_get (ctx->modelview_stack, matrix); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_get (modelview_stack, matrix); } void cogl_set_modelview_matrix (CoglMatrix *matrix) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_set (ctx->modelview_stack, matrix); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_set (modelview_stack, matrix); } void cogl_get_projection_matrix (CoglMatrix *matrix) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_get (ctx->projection_stack, matrix); + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_get (projection_stack, matrix); } void cogl_set_projection_matrix (CoglMatrix *matrix) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_set (ctx->projection_stack, matrix); + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ()); + _cogl_matrix_stack_set (projection_stack, matrix); /* FIXME: Update the inverse projection matrix!! Presumably use * of clip planes must currently be broken if this API is used. */ } -void -_cogl_flush_matrix_stacks (void) +CoglClipStackState * +_cogl_get_clip_state (void) { - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - _cogl_matrix_stack_flush_to_gl (ctx->projection_stack, - COGL_MATRIX_PROJECTION); - _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, - COGL_MATRIX_MODELVIEW); + CoglHandle draw_buffer; + + draw_buffer = _cogl_get_draw_buffer (); + return _cogl_draw_buffer_get_clip_state (draw_buffer); } diff --git a/cogl/cogl.h.in b/cogl/cogl.h.in index 524aec71d..23e417a29 100644 --- a/cogl/cogl.h.in +++ b/cogl/cogl.h.in @@ -867,6 +867,7 @@ void cogl_flush_gl_state (int flags); /* private */ void _cogl_set_indirect_context (gboolean indirect); +void _cogl_set_viewport (int x, int y, int width, int height); G_END_DECLS diff --git a/cogl/driver/gl/Makefile.am b/cogl/driver/gl/Makefile.am index 81a21c90e..afe961780 100644 --- a/cogl/driver/gl/Makefile.am +++ b/cogl/driver/gl/Makefile.am @@ -25,8 +25,6 @@ libclutter_cogl_driver_la_SOURCES = \ cogl.c \ cogl-primitives.c \ cogl-texture-driver.c \ - cogl-fbo.h \ - cogl-fbo.c \ cogl-shader-private.h \ cogl-shader.c \ cogl-program.h \ diff --git a/cogl/driver/gl/cogl-context-driver.c b/cogl/driver/gl/cogl-context-driver.c index dcf65ef26..c27721fd0 100644 --- a/cogl/driver/gl/cogl-context-driver.c +++ b/cogl/driver/gl/cogl-context-driver.c @@ -30,15 +30,16 @@ void _cogl_create_context_driver (CoglContext *_context) { - _context->drv.pf_glGenRenderbuffersEXT = NULL; - _context->drv.pf_glBindRenderbufferEXT = NULL; - _context->drv.pf_glRenderbufferStorageEXT = NULL; - _context->drv.pf_glGenFramebuffersEXT = NULL; - _context->drv.pf_glBindFramebufferEXT = NULL; - _context->drv.pf_glFramebufferTexture2DEXT = NULL; - _context->drv.pf_glFramebufferRenderbufferEXT = NULL; - _context->drv.pf_glCheckFramebufferStatusEXT = NULL; - _context->drv.pf_glDeleteFramebuffersEXT = NULL; + _context->drv.pf_glGenRenderbuffers = NULL; + _context->drv.pf_glBindRenderbuffer = NULL; + _context->drv.pf_glRenderbufferStorage = NULL; + _context->drv.pf_glGenFramebuffers = NULL; + _context->drv.pf_glBindFramebuffer = NULL; + _context->drv.pf_glFramebufferTexture2D = NULL; + _context->drv.pf_glFramebufferRenderbuffer = NULL; + _context->drv.pf_glCheckFramebufferStatus = NULL; + _context->drv.pf_glDeleteFramebuffers = NULL; + _context->drv.pf_glBlitFramebufferEXT = NULL; _context->drv.pf_glRenderbufferStorageMultisampleEXT = NULL; diff --git a/cogl/driver/gl/cogl-context-driver.h b/cogl/driver/gl/cogl-context-driver.h index ac5e61621..ff266d663 100644 --- a/cogl/driver/gl/cogl-context-driver.h +++ b/cogl/driver/gl/cogl-context-driver.h @@ -29,19 +29,20 @@ typedef struct _CoglContextDriver { /* Relying on glext.h to define these */ - COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; - COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; - COGL_PFNGLBINDRENDERBUFFEREXTPROC pf_glBindRenderbufferEXT; - COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC pf_glRenderbufferStorageEXT; - COGL_PFNGLGENFRAMEBUFFERSEXTPROC pf_glGenFramebuffersEXT; - COGL_PFNGLBINDFRAMEBUFFEREXTPROC pf_glBindFramebufferEXT; - COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pf_glFramebufferTexture2DEXT; - COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC pf_glFramebufferRenderbufferEXT; - COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pf_glCheckFramebufferStatusEXT; - COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; + COGL_PFNGLGENRENDERBUFFERSPROC pf_glGenRenderbuffers; + COGL_PFNGLDELETERENDERBUFFERSPROC pf_glDeleteRenderbuffers; + COGL_PFNGLBINDRENDERBUFFERPROC pf_glBindRenderbuffer; + COGL_PFNGLRENDERBUFFERSTORAGEPROC pf_glRenderbufferStorage; + COGL_PFNGLGENFRAMEBUFFERSPROC pf_glGenFramebuffers; + COGL_PFNGLBINDFRAMEBUFFERPROC pf_glBindFramebuffer; + COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC pf_glFramebufferTexture2D; + COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC pf_glFramebufferRenderbuffer; + COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC pf_glCheckFramebufferStatus; + COGL_PFNGLDELETEFRAMEBUFFERSPROC pf_glDeleteFramebuffers; + COGL_PFNGLGENERATEMIPMAPPROC pf_glGenerateMipmap; + COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; - COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; diff --git a/cogl/driver/gl/cogl-defines.h.in b/cogl/driver/gl/cogl-defines.h.in index 1c79bedfa..9d04be9af 100644 --- a/cogl/driver/gl/cogl-defines.h.in +++ b/cogl/driver/gl/cogl-defines.h.in @@ -698,34 +698,34 @@ G_BEGIN_DECLS #endif typedef void - (APIENTRYP COGL_PFNGLGENRENDERBUFFERSEXTPROC) + (APIENTRYP COGL_PFNGLGENRENDERBUFFERSPROC) (GLsizei n, GLuint *renderbuffers); typedef void - (APIENTRYP COGL_PFNGLBINDRENDERBUFFEREXTPROC) + (APIENTRYP COGL_PFNGLBINDRENDERBUFFERPROC) (GLenum target, GLuint renderbuffer); typedef void - (APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC) + (APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void - (APIENTRYP COGL_PFNGLGENFRAMEBUFFERSEXTPROC) + (APIENTRYP COGL_PFNGLGENFRAMEBUFFERSPROC) (GLsizei n, GLuint *framebuffers); typedef void - (APIENTRYP COGL_PFNGLBINDFRAMEBUFFEREXTPROC) + (APIENTRYP COGL_PFNGLBINDFRAMEBUFFERPROC) (GLenum target, GLuint framebuffer); typedef void - (APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) + (APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC) (GLenum target, GLenum attachment, GLenum textarget, @@ -733,26 +733,30 @@ typedef void GLint level); typedef void - (APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) + (APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef GLenum - (APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) + (APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC) (GLenum target); typedef void - (APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) + (APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSPROC) (GLsizei n, const GLuint *framebuffers); typedef void - (APIENTRYP COGL_PFNGLDELETERENDERBUFFERSEXTPROC) + (APIENTRYP COGL_PFNGLDELETERENDERBUFFERSPROC) (GLsizei n, const GLuint *renderbuffers); +typedef void + (APIENTRYP COGL_PFNGLGENERATEMIPMAPPROC) + (GLenum target); + typedef void (APIENTRYP COGL_PFNGLBLITFRAMEBUFFEREXTPROC) (GLint srcX0, @@ -774,10 +778,6 @@ typedef void GLsizei width, GLsizei height); -typedef void - (APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC) - (GLenum target); - typedef GLhandleARB (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (void); diff --git a/cogl/driver/gl/cogl-fbo.c b/cogl/driver/gl/cogl-fbo.c deleted file mode 100644 index 99315e6b0..000000000 --- a/cogl/driver/gl/cogl-fbo.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2007,2008,2009 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "cogl.h" -#include "cogl-internal.h" -#include "cogl-util.h" -#include "cogl-texture-private.h" -#include "cogl-fbo.h" -#include "cogl-context.h" -#include "cogl-handle.h" - -/* Expecting EXT functions not to be defined - redirect to pointers in context */ -#define glGenRenderbuffersEXT ctx->drv.pf_glGenRenderbuffersEXT -#define glDeleteRenderbuffersEXT ctx->drv.pf_glDeleteRenderbuffersEXT -#define glBindRenderbufferEXT ctx->drv.pf_glBindRenderbufferEXT -#define glRenderbufferStorageEXT ctx->drv.pf_glRenderbufferStorageEXT -#define glGenFramebuffersEXT ctx->drv.pf_glGenFramebuffersEXT -#define glBindFramebufferEXT ctx->drv.pf_glBindFramebufferEXT -#define glFramebufferTexture2DEXT ctx->drv.pf_glFramebufferTexture2DEXT -#define glFramebufferRenderbufferEXT ctx->drv.pf_glFramebufferRenderbufferEXT -#define glCheckFramebufferStatusEXT ctx->drv.pf_glCheckFramebufferStatusEXT -#define glDeleteFramebuffersEXT ctx->drv.pf_glDeleteFramebuffersEXT -#define glBlitFramebufferEXT ctx->drv.pf_glBlitFramebufferEXT -#define glRenderbufferStorageMultisampleEXT ctx->drv.pf_glRenderbufferStorageMultisampleEXT - -#ifndef GL_READ_FRAMEBUFFER_EXT -#define GL_READ_FRAMEBUFFER_EXT 0x8CA8 -#endif -#ifndef GL_DRAW_FRAMEBUFFER_EXT -#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9 -#endif - -static void _cogl_offscreen_free (CoglFbo *fbo); - -COGL_HANDLE_DEFINE (Fbo, offscreen); - -CoglHandle -cogl_offscreen_new_to_texture (CoglHandle texhandle) -{ - CoglFbo *fbo; - int width; - int height; - GLuint tex_gl_handle; - GLenum tex_gl_target; - GLuint fbo_gl_handle; - GLuint gl_stencil_handle; - GLenum status; - - _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); - - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) - return COGL_INVALID_HANDLE; - - /* Make texhandle is a valid texture object */ - if (!cogl_is_texture (texhandle)) - return COGL_INVALID_HANDLE; - - /* The texture must not be sliced */ - if (cogl_texture_is_sliced (texhandle)) - return COGL_INVALID_HANDLE; - - /* Pick the single texture slice width, height and GL id */ - - width = cogl_texture_get_width (texhandle); - height = cogl_texture_get_height (texhandle); - - if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) - return COGL_INVALID_HANDLE; - - if (tex_gl_target != GL_TEXTURE_2D) - return COGL_INVALID_HANDLE; - - /* Create a renderbuffer for stenciling */ - GE( glGenRenderbuffersEXT (1, &gl_stencil_handle) ); - GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, gl_stencil_handle) ); - GE( glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_STENCIL_INDEX8_EXT, - cogl_texture_get_width (texhandle), - cogl_texture_get_height (texhandle)) ); - GE( glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, 0) ); - - /* Generate framebuffer */ - glGenFramebuffersEXT (1, &fbo_gl_handle); - GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo_gl_handle) ); - GE( glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, - tex_gl_target, tex_gl_handle, 0) ); - GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, - GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, gl_stencil_handle) ); - - /* XXX: The framebuffer_object spec isn't clear in defining whether attaching - * a texture as a renderbuffer with mipmap filtering enabled while the - * mipmaps have not been uploaded should result in an incomplete framebuffer - * object. (different drivers make different decisions) - * - * To avoid an error with drivers that do consider this a problem we - * explicitly set non mipmapped filters here. These will later be reset when - * the texture is actually used for rendering according to the filters set on - * the corresponding CoglMaterial. - */ - _cogl_texture_set_filters (texhandle, GL_NEAREST, GL_NEAREST); - - /* Make sure it's complete */ - status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - /* Stencil renderbuffers aren't always supported. Try again - without the stencil buffer */ - GE( glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, - GL_STENCIL_ATTACHMENT_EXT, - GL_RENDERBUFFER_EXT, - 0) ); - GE( glDeleteRenderbuffersEXT (1, &gl_stencil_handle) ); - gl_stencil_handle = 0; - - status = glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT); - - if (status != GL_FRAMEBUFFER_COMPLETE_EXT) - { - /* Still failing, so give up */ - GE( glDeleteFramebuffersEXT (1, &fbo_gl_handle) ); - GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) ); - return COGL_INVALID_HANDLE; - } - } - - GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) ); - - /* Allocate and init a CoglFbo object (store non-wasted size - for subsequent blits and viewport setup) */ - fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); - fbo->width = width; - fbo->height = height; - fbo->gl_handle = fbo_gl_handle; - fbo->gl_stencil_handle = gl_stencil_handle; - - return _cogl_offscreen_handle_new (fbo); -} - -static void -_cogl_offscreen_free (CoglFbo *fbo) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* Frees FBO resources but its handle is not - released! Do that separately before this! */ - if (fbo->gl_stencil_handle) - GE( glDeleteRenderbuffersEXT (1, &fbo->gl_stencil_handle) ); - GE( glDeleteFramebuffersEXT (1, &fbo->gl_handle) ); - g_free (fbo); -} - -void -cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) -{ - CoglFbo *fbo = NULL; - CoglDrawBufferState *draw_buffer; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - _cogl_journal_flush (); - - g_assert (ctx->draw_buffer_stack != NULL); - draw_buffer = ctx->draw_buffer_stack->data; - - if (target == COGL_OFFSCREEN_BUFFER) - { - /* Make sure it is a valid fbo handle */ - if (!cogl_is_offscreen (offscreen)) - return; - - fbo = _cogl_offscreen_pointer_from_handle (offscreen); - - /* Check current draw buffer target */ - if (draw_buffer->target != COGL_OFFSCREEN_BUFFER) - { - /* Push the viewport and matrix setup if redirecting - from a non-screen buffer */ - GE( glPushAttrib (GL_VIEWPORT_BIT) ); - - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); - - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - } - else - { - /* Override viewport and matrix setup if redirecting - from another offscreen buffer */ - _cogl_matrix_stack_load_identity (ctx->projection_stack); - - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - } - - /* Setup new viewport and matrices */ - cogl_viewport (fbo->width, fbo->height); - _cogl_matrix_stack_translate (ctx->modelview_stack, -1.0f, -1.0f, 0.0f); - _cogl_matrix_stack_scale (ctx->modelview_stack, 2.0f / fbo->width, 2.0f / fbo->height, 1.0f); - - /* Bind offscreen framebuffer object */ - GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo->gl_handle) ); - GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); - } - else if (target & COGL_WINDOW_BUFFER) - { - /* Check current draw buffer target */ - if (draw_buffer->target == COGL_OFFSCREEN_BUFFER) - { - /* Pop viewport and matrices if redirecting back - from an offscreen buffer */ - GE( glPopAttrib () ); - - _cogl_matrix_stack_pop (ctx->projection_stack); - - _cogl_matrix_stack_pop (ctx->modelview_stack); - } - - /* Bind window framebuffer object */ - GE( glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0) ); - } - - /* Store new target */ - draw_buffer->target = target; - if (draw_buffer->offscreen != offscreen) - { - if (draw_buffer->offscreen != COGL_INVALID_HANDLE) - cogl_handle_unref (draw_buffer->offscreen); - if (offscreen != COGL_INVALID_HANDLE) - cogl_handle_ref (offscreen); - draw_buffer->offscreen = offscreen; - } -} - -void -cogl_push_draw_buffer(void) -{ - CoglDrawBufferState *old; - CoglDrawBufferState *draw_buffer; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_assert (ctx->draw_buffer_stack != NULL); - old = ctx->draw_buffer_stack->data; - - draw_buffer = g_slice_new0 (CoglDrawBufferState); - *draw_buffer = *old; - - ctx->draw_buffer_stack = - g_slist_prepend (ctx->draw_buffer_stack, draw_buffer); -} - -void -cogl_pop_draw_buffer(void) -{ - CoglDrawBufferState *to_pop; - CoglDrawBufferState *to_restore; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_assert (ctx->draw_buffer_stack != NULL); - if (ctx->draw_buffer_stack->next == NULL) - { - g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()"); - return; - } - - to_pop = ctx->draw_buffer_stack->data; - to_restore = ctx->draw_buffer_stack->next->data; - - /* the logic in cogl_set_draw_buffer() only works if - * to_pop is still on top of the stack, because - * cogl_set_draw_buffer() needs to know the previous - * state. - */ - cogl_set_draw_buffer (to_restore->target, to_restore->offscreen); - - /* cogl_set_draw_buffer() should have set top of stack - * to to_restore - */ - g_assert (to_restore->target == to_pop->target); - g_assert (to_restore->offscreen == to_pop->offscreen); - - g_assert (ctx->draw_buffer_stack->data == to_pop); - ctx->draw_buffer_stack = - g_slist_remove_link (ctx->draw_buffer_stack, - ctx->draw_buffer_stack); - - g_slice_free (CoglDrawBufferState, to_pop); -} - diff --git a/cogl/driver/gl/cogl-fbo.h b/cogl/driver/gl/cogl-fbo.h deleted file mode 100644 index 8499f8fb0..000000000 --- a/cogl/driver/gl/cogl-fbo.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2007,2008,2009 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __COGL_FBO_H -#define __COGL_FBO_H - -#include "cogl-handle.h" - -typedef struct -{ - CoglHandleObject _parent; - int width; - int height; - GLuint gl_handle; - GLuint gl_stencil_handle; - -} CoglFbo; - -#endif /* __COGL_FBO_H */ diff --git a/cogl/driver/gl/cogl-primitives.c b/cogl/driver/gl/cogl-primitives.c index 3c1c9e656..d2bc19335 100644 --- a/cogl/driver/gl/cogl-primitives.c +++ b/cogl/driver/gl/cogl-primitives.c @@ -30,6 +30,8 @@ #include "cogl-context.h" #include "cogl-clip-stack.h" #include "cogl-material-private.h" +#include "cogl-clip-stack.h" +#include "cogl-draw-buffer-private.h" #include #include @@ -74,7 +76,7 @@ _cogl_path_add_node (gboolean new_sub_path, } void -_cogl_path_stroke_nodes () +_cogl_path_stroke_nodes (void) { guint path_start = 0; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; @@ -82,6 +84,13 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _cogl_journal_flush (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); @@ -90,7 +99,6 @@ _cogl_path_stroke_nodes () options.disable_layers = (guint32)~0; _cogl_material_flush_gl_state (ctx->source_material, &options); - _cogl_flush_matrix_stacks (); while (path_start < ctx->path_nodes->len) { @@ -127,20 +135,33 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, CoglPathNode *path, gboolean merge) { - guint path_start = 0; - guint sub_path_num = 0; - float bounds_x; - float bounds_y; - float bounds_w; - float bounds_h; - gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; - CoglHandle prev_source; - int i; + guint path_start = 0; + guint sub_path_num = 0; + float bounds_x; + float bounds_y; + float bounds_w; + float bounds_h; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; + CoglHandle prev_source; + int i; + CoglHandle draw_buffer = _cogl_get_draw_buffer (); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (draw_buffer); + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (draw_buffer); + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* We don't track changes to the stencil buffer in the journal + * so we need to flush any batched geometry first */ _cogl_journal_flush (); + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (draw_buffer, 0); + /* Just setup a simple material that doesn't use texturing... */ prev_source = cogl_handle_ref (ctx->source_material); cogl_set_source (ctx->stencil_material); @@ -161,7 +182,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } else { - GE( glClear (GL_STENCIL_BUFFER_BIT) ); + cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL); GE( glStencilMask (1) ); GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) ); } @@ -179,8 +200,6 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } ctx->n_texcoord_arrays_enabled = 0; - _cogl_flush_matrix_stacks (); - while (path_start < path_size) { GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), @@ -194,8 +213,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, significant bit */ GE( glStencilMask (merge ? 6 : 3) ); GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) ); - glRectf (bounds_x, bounds_y, - bounds_x + bounds_w, bounds_y + bounds_h); + cogl_rectangle (bounds_x, bounds_y, + bounds_x + bounds_w, bounds_y + bounds_h); + /* Make sure the rectangle hits the stencil buffer before + * directly changing other GL state. */ + _cogl_journal_flush (); + /* NB: The journal flushing may trash the modelview state and + * enable flags */ + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); + cogl_enable (enable_flags); + GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); } @@ -216,19 +244,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, /* Decrement all of the bits twice so that only pixels where the value is 3 will remain */ - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); + _cogl_matrix_stack_push (projection_stack); + _cogl_matrix_stack_load_identity (projection_stack); + _cogl_matrix_stack_flush_to_gl (projection_stack, + COGL_MATRIX_PROJECTION); - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); + _cogl_matrix_stack_push (modelview_stack); + _cogl_matrix_stack_load_identity (modelview_stack); + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); - _cogl_flush_matrix_stacks (); + cogl_rectangle (-1.0, -1.0, 1.0, 1.0); + cogl_rectangle (-1.0, -1.0, 1.0, 1.0); + /* Make sure these rectangles hit the stencil buffer before we + * restore the stencil op/func. */ + _cogl_journal_flush (); - glRectf (-1.0, -1.0, 1.0, 1.0); - glRectf (-1.0, -1.0, 1.0, 1.0); - - _cogl_matrix_stack_pop (ctx->modelview_stack); - _cogl_matrix_stack_pop (ctx->projection_stack); + _cogl_matrix_stack_pop (modelview_stack); + _cogl_matrix_stack_pop (projection_stack); } GE( glStencilMask (~(GLuint) 0) ); @@ -244,8 +277,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } void -_cogl_path_fill_nodes () +_cogl_path_fill_nodes (void) { + CoglHandle draw_buffer; + CoglClipStackState *clip_state; float bounds_x; float bounds_y; float bounds_w; @@ -253,6 +288,11 @@ _cogl_path_fill_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _cogl_journal_flush (); + + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max, &bounds_x, &bounds_y, &bounds_w, &bounds_h); @@ -261,12 +301,13 @@ _cogl_path_fill_nodes () ctx->path_nodes->len, &g_array_index (ctx->path_nodes, CoglPathNode, 0), - ctx->clip.stencil_used); + clip_state->stencil_used); cogl_rectangle (bounds_x, bounds_y, bounds_x + bounds_w, bounds_y + bounds_h); /* The stencil buffer now contains garbage so the clip area needs to be rebuilt */ - ctx->clip.stack_dirty = TRUE; + _cogl_clip_stack_state_dirty (clip_state); } + diff --git a/cogl/driver/gl/cogl-texture-driver.c b/cogl/driver/gl/cogl-texture-driver.c index e4c868dbd..742fab807 100644 --- a/cogl/driver/gl/cogl-texture-driver.c +++ b/cogl/driver/gl/cogl-texture-driver.c @@ -45,7 +45,7 @@ #include #include -#define glGenerateMipmap ctx->drv.pf_glGenerateMipmapEXT +#define glGenerateMipmap ctx->drv.pf_glGenerateMipmap void _cogl_texture_driver_bind (GLenum gl_target, diff --git a/cogl/driver/gl/cogl.c b/cogl/driver/gl/cogl.c index 04d3b750a..e81ec377c 100644 --- a/cogl/driver/gl/cogl.c +++ b/cogl/driver/gl/cogl.c @@ -32,6 +32,12 @@ #include "cogl-internal.h" #include "cogl-context.h" +typedef struct _CoglGLSymbolTableEntry +{ + const char *name; + void *ptr; +} CoglGLSymbolTableEntry; + gboolean cogl_check_extension (const gchar *name, const gchar *ext) { @@ -57,6 +63,26 @@ cogl_check_extension (const gchar *name, const gchar *ext) return FALSE; } +gboolean +_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table, + const char *suffix) +{ + int i; + gboolean status = TRUE; + for (i = 0; symbol_table[i].name; i++) + { + char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix); + *((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name); + g_free (full_name); + if (!*((CoglFuncPtr *)symbol_table[i].ptr)) + { + status = FALSE; + break; + } + } + return status; +} + #ifdef HAVE_CLUTTER_OSX static gboolean really_enable_npot (void) @@ -90,6 +116,9 @@ _cogl_features_init (void) const gchar *gl_extensions; GLint max_clip_planes = 0; GLint num_stencil_bits = 0; + gboolean fbo_ARB = FALSE; + gboolean fbo_EXT = FALSE; + const char *suffix; _COGL_GET_CONTEXT (ctx, NO_RETVAL); @@ -284,64 +313,35 @@ _cogl_features_init (void) flags |= COGL_FEATURE_SHADERS_GLSL; } - if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) || - cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions)) + fbo_ARB = cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions); + if (fbo_ARB) + suffix = ""; + else { - ctx->drv.pf_glGenRenderbuffersEXT = - (COGL_PFNGLGENRENDERBUFFERSEXTPROC) - cogl_get_proc_address ("glGenRenderbuffersEXT"); + fbo_EXT = cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions); + if (fbo_EXT) + suffix = "EXT"; + } - ctx->drv.pf_glDeleteRenderbuffersEXT = - (COGL_PFNGLDELETERENDERBUFFERSEXTPROC) - cogl_get_proc_address ("glDeleteRenderbuffersEXT"); + if (fbo_ARB || fbo_EXT) + { + CoglGLSymbolTableEntry symbol_table[] = { + {"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers}, + {"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers}, + {"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer}, + {"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage}, + {"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers}, + {"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer}, + {"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D}, + {"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer}, + {"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus}, + {"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers}, + {"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap}, + {NULL, NULL} + }; - ctx->drv.pf_glBindRenderbufferEXT = - (COGL_PFNGLBINDRENDERBUFFEREXTPROC) - cogl_get_proc_address ("glBindRenderbufferEXT"); - - ctx->drv.pf_glRenderbufferStorageEXT = - (COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC) - cogl_get_proc_address ("glRenderbufferStorageEXT"); - - ctx->drv.pf_glGenFramebuffersEXT = - (COGL_PFNGLGENFRAMEBUFFERSEXTPROC) - cogl_get_proc_address ("glGenFramebuffersEXT"); - - ctx->drv.pf_glBindFramebufferEXT = - (COGL_PFNGLBINDFRAMEBUFFEREXTPROC) - cogl_get_proc_address ("glBindFramebufferEXT"); - - ctx->drv.pf_glFramebufferTexture2DEXT = - (COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) - cogl_get_proc_address ("glFramebufferTexture2DEXT"); - - ctx->drv.pf_glFramebufferRenderbufferEXT = - (COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) - cogl_get_proc_address ("glFramebufferRenderbufferEXT"); - - ctx->drv.pf_glCheckFramebufferStatusEXT = - (COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) - cogl_get_proc_address ("glCheckFramebufferStatusEXT"); - - ctx->drv.pf_glDeleteFramebuffersEXT = - (COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) - cogl_get_proc_address ("glDeleteFramebuffersEXT"); - - ctx->drv.pf_glGenerateMipmapEXT = - (COGL_PFNGLGENERATEMIPMAPEXTPROC) - cogl_get_proc_address ("glGenerateMipmapEXT"); - - if (ctx->drv.pf_glGenRenderbuffersEXT && - ctx->drv.pf_glBindRenderbufferEXT && - ctx->drv.pf_glRenderbufferStorageEXT && - ctx->drv.pf_glGenFramebuffersEXT && - ctx->drv.pf_glBindFramebufferEXT && - ctx->drv.pf_glFramebufferTexture2DEXT && - ctx->drv.pf_glFramebufferRenderbufferEXT && - ctx->drv.pf_glCheckFramebufferStatusEXT && - ctx->drv.pf_glDeleteFramebuffersEXT && - ctx->drv.pf_glGenerateMipmapEXT) - flags |= COGL_FEATURE_OFFSCREEN; + if (_cogl_resolve_gl_symbols (symbol_table, suffix)) + flags |= COGL_FEATURE_OFFSCREEN; } if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions)) diff --git a/cogl/driver/gles/Makefile.am b/cogl/driver/gles/Makefile.am index 0a44fb465..182b29b84 100644 --- a/cogl/driver/gles/Makefile.am +++ b/cogl/driver/gles/Makefile.am @@ -22,11 +22,9 @@ libclutter_cogl_driver_la_CPPFLAGS = \ $(CLUTTER_DEBUG_CFLAGS) \ $(MAINTAINER_CFLAGS) libclutter_cogl_driver_la_SOURCES = \ - cogl-fbo.h \ cogl.c \ cogl-primitives.c \ cogl-texture-driver.c \ - cogl-fbo.c \ cogl-context-driver.c \ cogl-context-driver.h \ cogl-gles2-wrapper.h \ diff --git a/cogl/driver/gles/cogl-context-driver.c b/cogl/driver/gles/cogl-context-driver.c index 6660db1f3..ae2a06477 100644 --- a/cogl/driver/gles/cogl-context-driver.c +++ b/cogl/driver/gles/cogl-context-driver.c @@ -31,6 +31,16 @@ void _cogl_create_context_driver (CoglContext *context) { + context->drv.pf_glGenRenderbuffers = NULL; + context->drv.pf_glBindRenderbuffer = NULL; + context->drv.pf_glRenderbufferStorage = NULL; + context->drv.pf_glGenFramebuffers = NULL; + context->drv.pf_glBindFramebuffer = NULL; + context->drv.pf_glFramebufferTexture2D = NULL; + context->drv.pf_glFramebufferRenderbuffer = NULL; + context->drv.pf_glCheckFramebufferStatus = NULL; + context->drv.pf_glDeleteFramebuffers = NULL; + /* Init the GLES2 wrapper */ #ifdef HAVE_COGL_GLES2 cogl_gles2_wrapper_init (&context->drv.gles2); diff --git a/cogl/driver/gles/cogl-context-driver.h b/cogl/driver/gles/cogl-context-driver.h index 9b5996e74..de24eb775 100644 --- a/cogl/driver/gles/cogl-context-driver.h +++ b/cogl/driver/gles/cogl-context-driver.h @@ -24,17 +24,26 @@ #ifndef __COGL_CONTEXT_DRIVER_H #define __COGL_CONTEXT_DRIVER_H +#include "cogl.h" #include "cogl-gles2-wrapper.h" typedef struct _CoglContextDriver { + COGL_PFNGLGENRENDERBUFFERSPROC pf_glGenRenderbuffers; + COGL_PFNGLDELETERENDERBUFFERSPROC pf_glDeleteRenderbuffers; + COGL_PFNGLBINDRENDERBUFFERPROC pf_glBindRenderbuffer; + COGL_PFNGLRENDERBUFFERSTORAGEPROC pf_glRenderbufferStorage; + COGL_PFNGLGENFRAMEBUFFERSPROC pf_glGenFramebuffers; + COGL_PFNGLBINDFRAMEBUFFERPROC pf_glBindFramebuffer; + COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC pf_glFramebufferTexture2D; + COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC pf_glFramebufferRenderbuffer; + COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC pf_glCheckFramebufferStatus; + COGL_PFNGLDELETEFRAMEBUFFERSPROC pf_glDeleteFramebuffers; + COGL_PFNGLGENERATEMIPMAPPROC pf_glGenerateMipmap; + #ifdef HAVE_COGL_GLES2 CoglGles2Wrapper gles2; - - /* Viewport store for FBOs. Needed because glPushAttrib() isn't - supported */ - GLint viewport_store[4]; #endif } CoglContextDriver; diff --git a/cogl/driver/gles/cogl-defines.h.in b/cogl/driver/gles/cogl-defines.h.in index 97045df94..8f0cff1da 100644 --- a/cogl/driver/gles/cogl-defines.h.in +++ b/cogl/driver/gles/cogl-defines.h.in @@ -633,6 +633,76 @@ G_BEGIN_DECLS #define CGL_SHININESS 0x1601 #endif +/* Extension function prototypes */ + +#ifndef APIENTRY +#define APIENTRY +#endif + +#ifndef APIENTRYP +#define APIENTRYP APIENTRY * +#endif + +typedef void + (APIENTRYP COGL_PFNGLGENRENDERBUFFERSPROC) + (GLsizei n, + GLuint *renderbuffers); + +typedef void + (APIENTRYP COGL_PFNGLBINDRENDERBUFFERPROC) + (GLenum target, + GLuint renderbuffer); + +typedef void + (APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEPROC) + (GLenum target, + GLenum internalformat, + GLsizei width, + GLsizei height); + +typedef void + (APIENTRYP COGL_PFNGLGENFRAMEBUFFERSPROC) + (GLsizei n, + GLuint *framebuffers); + +typedef void + (APIENTRYP COGL_PFNGLBINDFRAMEBUFFERPROC) + (GLenum target, + GLuint framebuffer); + +typedef void + (APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC) + (GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level); + +typedef void + (APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC) + (GLenum target, + GLenum attachment, + GLenum renderbuffertarget, + GLuint renderbuffer); + +typedef GLenum + (APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC) + (GLenum target); + +typedef void + (APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSPROC) + (GLsizei n, + const GLuint *framebuffers); + +typedef void + (APIENTRYP COGL_PFNGLDELETERENDERBUFFERSPROC) + (GLsizei n, + const GLuint *renderbuffers); + +typedef void + (APIENTRYP COGL_PFNGLGENERATEMIPMAPPROC) + (GLenum target); + G_END_DECLS #endif diff --git a/cogl/driver/gles/cogl-fbo.c b/cogl/driver/gles/cogl-fbo.c deleted file mode 100644 index 41b5c6b0c..000000000 --- a/cogl/driver/gles/cogl-fbo.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2008,2009 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "cogl.h" -#include "cogl-internal.h" -#include "cogl-util.h" -#include "cogl-texture-private.h" -#include "cogl-fbo.h" -#include "cogl-context.h" -#include "cogl-handle.h" -#include "cogl-gles2-wrapper.h" - -#ifdef HAVE_COGL_GLES2 - -static void _cogl_offscreen_free (CoglFbo *fbo); - -COGL_HANDLE_DEFINE (Fbo, offscreen); - -CoglHandle -cogl_offscreen_new_to_texture (CoglHandle texhandle) -{ - CoglFbo *fbo; - int width; - int height; - GLuint tex_gl_handle; - GLenum tex_gl_target; - GLuint fbo_gl_handle; - GLuint gl_stencil_handle; - GLenum status; - - _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE); - - if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) - return COGL_INVALID_HANDLE; - - /* Make texhandle is a valid texture object */ - if (!cogl_is_texture (texhandle)) - return COGL_INVALID_HANDLE; - - /* The texture must not be sliced */ - if (cogl_texture_is_sliced (texhandle)) - return COGL_INVALID_HANDLE; - - /* Pick the single texture slice width, height and GL id */ - - width = cogl_texture_get_width (texhandle); - height = cogl_texture_get_height (texhandle); - - if (!cogl_texture_get_gl_texture (texhandle, &tex_gl_handle, &tex_gl_target)) - return COGL_INVALID_HANDLE; - - if (tex_gl_target != GL_TEXTURE_2D) - return COGL_INVALID_HANDLE; - - /* Create a renderbuffer for stenciling */ - GE( glGenRenderbuffers (1, &gl_stencil_handle) ); - GE( glBindRenderbuffer (GL_RENDERBUFFER, gl_stencil_handle) ); - GE( glRenderbufferStorage (GL_RENDERBUFFER, GL_STENCIL_INDEX8, - cogl_texture_get_width (texhandle), - cogl_texture_get_height (texhandle)) ); - GE( glBindRenderbuffer (GL_RENDERBUFFER, 0) ); - - /* Generate framebuffer */ - glGenFramebuffers (1, &fbo_gl_handle); - GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo_gl_handle) ); - GE( glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - tex_gl_target, tex_gl_handle, 0) ); - GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, gl_stencil_handle) ); - - /* Make sure it's complete */ - status = glCheckFramebufferStatus (GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - /* Stencil renderbuffers aren't always supported. Try again - without the stencil buffer */ - GE( glFramebufferRenderbuffer (GL_FRAMEBUFFER, - GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, - 0) ); - GE( glDeleteRenderbuffers (1, &gl_stencil_handle) ); - gl_stencil_handle = 0; - - status = glCheckFramebufferStatus (GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) - { - /* Still failing, so give up */ - GE( glDeleteFramebuffers (1, &fbo_gl_handle) ); - GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) ); - return COGL_INVALID_HANDLE; - } - } - - GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) ); - - /* Allocate and init a CoglFbo object (store non-wasted size - for subsequent blits and viewport setup) */ - fbo = (CoglFbo*) g_malloc (sizeof (CoglFbo)); - fbo->width = width; - fbo->height = height; - fbo->gl_handle = fbo_gl_handle; - fbo->gl_stencil_handle = gl_stencil_handle; - - return _cogl_offscreen_handle_new (fbo); -} - -static void -_cogl_offscreen_free (CoglFbo *fbo) -{ - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - /* Frees FBO resources but its handle is not - released! Do that separately before this! */ - if (fbo->gl_stencil_handle) - GE( glDeleteRenderbuffers (1, &fbo->gl_stencil_handle) ); - GE( glDeleteFramebuffers (1, &fbo->gl_handle) ); - g_free (fbo); -} - -void -cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) -{ - CoglFbo *fbo = NULL; - CoglDrawBufferState *draw_buffer; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - _cogl_journal_flush (); - - g_assert (ctx->draw_buffer_stack != NULL); - draw_buffer = ctx->draw_buffer_stack->data; - - if (target == COGL_OFFSCREEN_BUFFER) - { - /* Make sure it is a valid fbo handle */ - if (!cogl_is_offscreen (offscreen)) - return; - - fbo = _cogl_offscreen_pointer_from_handle (offscreen); - - /* Check current draw buffer target */ - if (draw_buffer->target != COGL_OFFSCREEN_BUFFER) - { - /* Push the viewport and matrix setup if redirecting - from a non-screen buffer */ - GE( glGetIntegerv (GL_VIEWPORT, ctx->drv.viewport_store) ); - - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); - - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - } - else - { - /* Override viewport and matrix setup if redirecting - from another offscreen buffer */ - _cogl_matrix_stack_load_identity (ctx->projection_stack); - - _cogl_matrix_stack_load_identity (ctx->modelview_stack); - } - - /* Setup new viewport and matrices */ -<<<<<<< HEAD:clutter/cogl/cogl/driver/gles/cogl-fbo.c - GE( glViewport (0, 0, fbo->width, fbo->height) ); - _cogl_matrix_stack_translate (ctx->modelview_stack, -1.0f, -1.0f, 0.0f); - _cogl_matrix_stack_scale (ctx->modelview_stack, - 2.0f / fbo->width, 2.0f / fbo->height, 1.0f); -======= - cogl_viewport (fbo->width, fbo->height); - _cogl_current_matrix_translate (-1.0f, -1.0f, 0.0f); - _cogl_current_matrix_scale (2.0f / fbo->width, 2.0f / fbo->height, 1.0f); ->>>>>>> c3e471c... [cogl-fbo] Bring the gles code more in line with gl code:clutter/cogl/cogl/driver/gles/cogl-fbo.c - - /* Bind offscreen framebuffer object */ - GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo->gl_handle) ); - GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) ); - } - else if (target & COGL_WINDOW_BUFFER) - { - /* Check current draw buffer target */ - if (draw_buffer->target == COGL_OFFSCREEN_BUFFER) - { - /* Pop viewport and matrices if redirecting back - from an offscreen buffer */ - GE( glViewport (ctx->drv.viewport_store[0], - ctx->drv.viewport_store[1], - ctx->drv.viewport_store[2], - ctx->drv.viewport_store[3]) ); - - _cogl_matrix_stack_pop (ctx->projection_stack); - - _cogl_matrix_stack_pop (ctx->modelview_stack); - } - - /* Bind window framebuffer object */ - GE( glBindFramebuffer (GL_FRAMEBUFFER, 0) ); - } - - /* Store new target */ - draw_buffer->target = target; - if (draw_buffer->offscreen != offscreen) - { - if (draw_buffer->offscreen != COGL_INVALID_HANDLE) - cogl_handle_unref (draw_buffer->offscreen); - if (offscreen != COGL_INVALID_HANDLE) - cogl_handle_ref (offscreen); - draw_buffer->offscreen = offscreen; - } -} - -void -cogl_push_draw_buffer(void) -{ - CoglDrawBufferState *old; - CoglDrawBufferState *draw_buffer; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_assert (ctx->draw_buffer_stack != NULL); - old = ctx->draw_buffer_stack->data; - - draw_buffer = g_slice_new0 (CoglDrawBufferState); - *draw_buffer = *old; - - ctx->draw_buffer_stack = - g_slist_prepend (ctx->draw_buffer_stack, draw_buffer); -} - -void -cogl_pop_draw_buffer(void) -{ - CoglDrawBufferState *to_pop; - CoglDrawBufferState *to_restore; - - _COGL_GET_CONTEXT (ctx, NO_RETVAL); - - g_assert (ctx->draw_buffer_stack != NULL); - if (ctx->draw_buffer_stack->next == NULL) - { - g_warning ("1 more cogl_pop_draw_buffer() than cogl_push_draw_buffer()"); - return; - } - - to_pop = ctx->draw_buffer_stack->data; - to_restore = ctx->draw_buffer_stack->next->data; - - /* the logic in cogl_set_draw_buffer() only works if - * to_pop is still on top of the stack, because - * cogl_set_draw_buffer() needs to know the previous - * state. - */ - cogl_set_draw_buffer (to_restore->target, to_restore->offscreen); - - /* cogl_set_draw_buffer() should have set top of stack - * to to_restore - */ - g_assert (to_restore->target == to_pop->target); - g_assert (to_restore->offscreen == to_pop->offscreen); - - g_assert (ctx->draw_buffer_stack->data == to_pop); - ctx->draw_buffer_stack = - g_slist_remove_link (ctx->draw_buffer_stack, - ctx->draw_buffer_stack); - - g_slice_free (CoglDrawBufferState, to_pop); -} - -#else /* HAVE_COGL_GLES2 */ - -/* No support on regular OpenGL 1.1 */ - -gboolean -cogl_is_offscreen (CoglHandle handle) -{ - return FALSE; -} - -CoglHandle -cogl_offscreen_new_to_texture (CoglHandle texhandle) -{ - return COGL_INVALID_HANDLE; -} - -CoglHandle -cogl_offscreen_ref (CoglHandle handle) -{ - return COGL_INVALID_HANDLE; -} - -void -cogl_offscreen_unref (CoglHandle handle) -{ -} - -void -cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen) -{ -} - -#endif /* HAVE_COGL_GLES2 */ diff --git a/cogl/driver/gles/cogl-fbo.h b/cogl/driver/gles/cogl-fbo.h deleted file mode 100644 index 8499f8fb0..000000000 --- a/cogl/driver/gles/cogl-fbo.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Cogl - * - * An object oriented GL/GLES Abstraction/Utility Layer - * - * Copyright (C) 2007,2008,2009 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, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -#ifndef __COGL_FBO_H -#define __COGL_FBO_H - -#include "cogl-handle.h" - -typedef struct -{ - CoglHandleObject _parent; - int width; - int height; - GLuint gl_handle; - GLuint gl_stencil_handle; - -} CoglFbo; - -#endif /* __COGL_FBO_H */ diff --git a/cogl/driver/gles/cogl-primitives.c b/cogl/driver/gles/cogl-primitives.c index f31bd2143..09d637e7d 100644 --- a/cogl/driver/gles/cogl-primitives.c +++ b/cogl/driver/gles/cogl-primitives.c @@ -30,6 +30,9 @@ #include "cogl-context.h" #include "cogl-clip-stack.h" #include "cogl-material-private.h" +#include "cogl-clip-stack.h" +#include "cogl-draw-buffer-private.h" +#include "cogl-clip-stack.h" #include #include @@ -72,7 +75,7 @@ _cogl_path_add_node (gboolean new_sub_path, } void -_cogl_path_stroke_nodes () +_cogl_path_stroke_nodes (void) { guint path_start = 0; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; @@ -80,13 +83,21 @@ _cogl_path_stroke_nodes () _COGL_GET_CONTEXT (ctx, NO_RETVAL); + _cogl_journal_flush (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); + enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); cogl_enable (enable_flags); options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK; + /* disable all texture layers */ options.disable_layers = (guint32)~0; - _cogl_material_flush_gl_state (ctx->source_material,&options); - _cogl_flush_matrix_stacks(); + + _cogl_material_flush_gl_state (ctx->source_material, &options); while (path_start < ctx->path_nodes->len) { @@ -129,18 +140,38 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, CoglPathNode *path, gboolean merge) { - guint path_start = 0; - guint sub_path_num = 0; - float bounds_x; - float bounds_y; - float bounds_w; - float bounds_h; - gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; + guint path_start = 0; + guint sub_path_num = 0; + float bounds_x; + float bounds_y; + float bounds_w; + float bounds_h; + gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; + CoglHandle prev_source; + int i; + CoglHandle draw_buffer = _cogl_get_draw_buffer (); + CoglMatrixStack *modelview_stack = + _cogl_draw_buffer_get_modelview_stack (draw_buffer); + CoglMatrixStack *projection_stack = + _cogl_draw_buffer_get_projection_stack (draw_buffer); + _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* We don't track changes to the stencil buffer in the journal + * so we need to flush any batched geometry first */ + _cogl_journal_flush (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (draw_buffer, 0); + /* Just setup a simple material that doesn't use texturing... */ - _cogl_material_flush_gl_state (ctx->stencil_material, NULL); + prev_source = cogl_handle_ref (ctx->source_material); + cogl_set_source (ctx->stencil_material); + + _cogl_material_flush_gl_state (ctx->source_material, NULL); enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material); @@ -156,7 +187,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, } else { - GE( glClear (GL_STENCIL_BUFFER_BIT) ); + cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL); GE( glStencilMask (1) ); GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) ); } @@ -167,7 +198,13 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glColorMask (FALSE, FALSE, FALSE, FALSE) ); GE( glDepthMask (FALSE) ); - _cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, COGL_MATRIX_MODELVIEW); + for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++) + { + GE (glClientActiveTexture (GL_TEXTURE0 + i)); + GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY)); + } + ctx->n_texcoord_arrays_enabled = 0; + while (path_start < path_size) { GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), @@ -183,6 +220,14 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) ); cogl_rectangle (bounds_x, bounds_y, bounds_x + bounds_w, bounds_y + bounds_h); + /* Make sure the rectangle hits the stencil buffer before + * directly changing other GL state. */ + _cogl_journal_flush (); + /* NB: The journal flushing may trash the modelview state and + * enable flags */ + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); + cogl_enable (enable_flags); GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) ); } @@ -204,17 +249,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min, /* Decrement all of the bits twice so that only pixels where the value is 3 will remain */ - _cogl_matrix_stack_push (ctx->projection_stack); - _cogl_matrix_stack_load_identity (ctx->projection_stack); + _cogl_matrix_stack_push (projection_stack); + _cogl_matrix_stack_load_identity (projection_stack); + _cogl_matrix_stack_flush_to_gl (projection_stack, + COGL_MATRIX_PROJECTION); - _cogl_matrix_stack_push (ctx->modelview_stack); - _cogl_matrix_stack_load_identity (ctx->modelview_stack); + _cogl_matrix_stack_push (modelview_stack); + _cogl_matrix_stack_load_identity (modelview_stack); + _cogl_matrix_stack_flush_to_gl (modelview_stack, + COGL_MATRIX_MODELVIEW); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_rectangle (-1.0, -1.0, 1.0, 1.0); + /* Make sure these rectangles hit the stencil buffer before we + * restore the stencil op/func. */ + _cogl_journal_flush (); - _cogl_matrix_stack_pop (ctx->modelview_stack); - _cogl_matrix_stack_pop (ctx->projection_stack); + _cogl_matrix_stack_pop (modelview_stack); + _cogl_matrix_stack_pop (projection_stack); } GE( glStencilMask (~(GLuint) 0) ); @@ -250,6 +302,21 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, _COGL_GET_CONTEXT (ctx, NO_RETVAL); + /* We are going to use GL to draw directly so make sure any + * previously batched geometry gets to GL before we start... + */ + _cogl_journal_flush (); + + /* NB: _cogl_draw_buffer_flush_state may disrupt various state (such + * as the material state) when flushing the clip stack, so should + * always be done first when preparing to draw. */ + _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0); + + _cogl_material_flush_gl_state (ctx->source_material, NULL); + + cogl_enable (COGL_ENABLE_VERTEX_ARRAY + | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); + /* clear scanline intersection lists */ for (i=0; i < bounds_h; i++) scanlines[i]=NULL; @@ -386,8 +453,6 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, } /* render triangles */ - cogl_enable (COGL_ENABLE_VERTEX_ARRAY - | (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0)); GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) ); GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3)); g_free (coords); @@ -395,7 +460,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path, } void -_cogl_path_fill_nodes () +_cogl_path_fill_nodes (void) { float bounds_x; float bounds_y; @@ -409,19 +474,27 @@ _cogl_path_fill_nodes () if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER)) { + CoglHandle draw_buffer; + CoglClipStackState *clip_state; + + _cogl_journal_flush (); + + draw_buffer = _cogl_get_draw_buffer (); + clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer); + _cogl_add_path_to_stencil_buffer (ctx->path_nodes_min, ctx->path_nodes_max, ctx->path_nodes->len, &g_array_index (ctx->path_nodes, CoglPathNode, 0), - ctx->clip.stencil_used); + clip_state->stencil_used); cogl_rectangle (bounds_x, bounds_y, bounds_x + bounds_w, bounds_y + bounds_h); /* The stencil buffer now contains garbage so the clip area needs to be rebuilt */ - ctx->clip.stack_dirty = TRUE; + _cogl_clip_stack_state_dirty (clip_state); } else { diff --git a/cogl/driver/gles/cogl.c b/cogl/driver/gles/cogl.c index aa7da6ef2..565ff0fa7 100644 --- a/cogl/driver/gles/cogl.c +++ b/cogl/driver/gles/cogl.c @@ -31,6 +31,56 @@ #include "cogl-internal.h" #include "cogl-context.h" +typedef struct _CoglGLSymbolTableEntry +{ + const char *name; + void *ptr; +} CoglGLSymbolTableEntry; + +gboolean +cogl_check_extension (const gchar *name, const gchar *ext) +{ + gchar *end; + gint name_len, n; + + if (name == NULL || ext == NULL) + return FALSE; + + end = (gchar*)(ext + strlen(ext)); + + name_len = strlen(name); + + while (ext < end) + { + n = strcspn(ext, " "); + + if ((name_len == n) && (!strncmp(name, ext, n))) + return TRUE; + ext += (n + 1); + } + + return FALSE; +} + +gboolean +_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table, + const char *suffix) +{ + int i; + gboolean status = TRUE; + for (i = 0; symbol_table[i].name; i++) + { + char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix); + *((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name); + g_free (full_name); + if (!*((CoglFuncPtr *)symbol_table[i].ptr)) + { + status = FALSE; + break; + } + } + return status; +} void @@ -39,9 +89,34 @@ _cogl_features_init (void) CoglFeatureFlags flags = 0; int max_clip_planes = 0; GLint num_stencil_bits = 0; + const char *gl_extensions; _COGL_GET_CONTEXT (ctx, NO_RETVAL); + gl_extensions = (const char*) glGetString (GL_EXTENSIONS); + + if (cogl_check_extension ("GL_OES_framebuffer_object", gl_extensions)) + { + g_assert (0); + CoglGLSymbolTableEntry symbol_table[] = { + {"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers}, + {"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers}, + {"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer}, + {"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage}, + {"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers}, + {"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer}, + {"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D}, + {"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer}, + {"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus}, + {"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers}, + {"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap}, + {NULL, NULL} + }; + + if (_cogl_resolve_gl_symbols (symbol_table, "OES")) + flags |= COGL_FEATURE_OFFSCREEN; + } + GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) ); /* We need at least three stencil bits to combine clips */ if (num_stencil_bits > 2)