[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
This commit is contained in:
Robert Bragg 2009-09-25 14:34:34 +01:00
parent 6b2ff320ca
commit bb3a008318
30 changed files with 1474 additions and 1090 deletions

View File

@ -120,6 +120,8 @@ libclutter_cogl_la_SOURCES = \
$(srcdir)/cogl-spans.c \ $(srcdir)/cogl-spans.c \
$(srcdir)/cogl-journal-private.h \ $(srcdir)/cogl-journal-private.h \
$(srcdir)/cogl-journal.c \ $(srcdir)/cogl-journal.c \
$(srcdir)/cogl-draw-buffer-private.h \
$(srcdir)/cogl-draw-buffer.c \
$(BUILT_SOURCES) \ $(BUILT_SOURCES) \
$(NULL) $(NULL)

View File

@ -34,6 +34,7 @@
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-draw-buffer-private.h"
/* These are defined in the particular backend (float in GL vs fixed /* These are defined in the particular backend (float in GL vs fixed
in GL ES) */ in GL ES) */
@ -119,15 +120,24 @@ cogl_clip_push_window_rect (float x_offset,
float width, float width,
float height) float height)
{ {
CoglClipStackEntryWindowRect *entry; CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack; CoglClipStack *stack;
float v[4]; CoglClipStackEntryWindowRect *entry;
float viewport_height;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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); entry = g_slice_new (CoglClipStackEntryWindowRect);
@ -135,14 +145,14 @@ cogl_clip_push_window_rect (float x_offset,
* with (0,0) at bottom left. */ * with (0,0) at bottom left. */
entry->type = COGL_CLIP_STACK_WINDOW_RECT; entry->type = COGL_CLIP_STACK_WINDOW_RECT;
entry->x0 = x_offset; entry->x0 = x_offset;
entry->y0 = v[3] - y_offset - height; entry->y0 = viewport_height - y_offset - height;
entry->x1 = x_offset + width; entry->x1 = x_offset + width;
entry->y1 = v[3] - y_offset; entry->y1 = viewport_height - y_offset;
/* Store it in the stack */ /* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry); 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 /* Scale from OpenGL <-1,1> coordinates system to window coordinates
@ -214,17 +224,26 @@ cogl_clip_push (float x_offset,
float width, float width,
float height) float height)
{ {
CoglClipStackEntryRect *entry; CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack; CoglClipStack *stack;
CoglClipStackEntryRect *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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 /* Try and catch window space rectangles so we can redirect to
* cogl_clip_push_window_rect which will use scissoring. */ * cogl_clip_push_window_rect which will use scissoring. */
if (try_pushing_rect_as_window_rect (x_offset, y_offset, width, height)) if (try_pushing_rect_as_window_rect (x_offset, y_offset, width, height))
return; 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); entry = g_slice_new (CoglClipStackEntryRect);
@ -240,18 +259,27 @@ cogl_clip_push (float x_offset,
/* Store it in the stack */ /* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry); stack->stack_top = g_list_prepend (stack->stack_top, entry);
ctx->clip.stack_dirty = TRUE; clip_state->stack_dirty = TRUE;
} }
void void
cogl_clip_push_from_path_preserve (void) cogl_clip_push_from_path_preserve (void)
{ {
CoglClipStackEntryPath *entry; CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack; CoglClipStack *stack;
CoglClipStackEntryPath *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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) entry = g_malloc (sizeof (CoglClipStackEntryPath)
+ sizeof (CoglPathNode) * (ctx->path_nodes->len - 1)); + sizeof (CoglPathNode) * (ctx->path_nodes->len - 1));
@ -268,7 +296,7 @@ cogl_clip_push_from_path_preserve (void)
/* Store it in the stack */ /* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry); stack->stack_top = g_list_prepend (stack->stack_top, entry);
ctx->clip.stack_dirty = TRUE; clip_state->stack_dirty = TRUE;
} }
void void
@ -279,16 +307,18 @@ cogl_clip_push_from_path (void)
cogl_path_new (); cogl_path_new ();
} }
void static void
cogl_clip_pop (void) _cogl_clip_pop_real (CoglClipStackState *clip_state)
{ {
gpointer entry;
CoglClipStack *stack; CoglClipStack *stack;
gpointer entry;
CoglClipStackEntryType type; 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); 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 = g_list_delete_link (stack->stack_top,
stack->stack_top); stack->stack_top);
ctx->clip.stack_dirty = TRUE; clip_state->stack_dirty = TRUE;
} }
void 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_clip_planes = FALSE;
gboolean using_stencil_buffer = FALSE; gboolean using_stencil_buffer = FALSE;
GList *node; GList *node;
CoglClipStack *stack;
gint scissor_x0 = 0; gint scissor_x0 = 0;
gint scissor_y0 = 0; gint scissor_y0 = 0;
gint scissor_x1 = G_MAXINT; gint scissor_x1 = G_MAXINT;
gint scissor_y1 = 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); if (!clip_state->stack_dirty)
return;
modelview_stack = ctx->modelview_stack;
/* The current primitive journal does not support tracking changes to the /* The current primitive journal does not support tracking changes to the
* clip stack... */ * clip stack... */
_cogl_journal_flush (); _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; has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
ctx->clip.stencil_used = FALSE;
stack = clip_state->stacks->data;
clip_state->stencil_used = FALSE;
_cogl_disable_clip_planes (); _cogl_disable_clip_planes ();
_cogl_disable_stencil_buffer (); _cogl_disable_stencil_buffer ();
@ -433,74 +485,111 @@ _cogl_clip_stack_rebuild (void)
scissor_y1 - scissor_y0)); 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 void
cogl_clip_ensure (void) cogl_clip_ensure (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglClipStackState *clip_state;
if (ctx->clip.stack_dirty) clip_state = _cogl_draw_buffer_get_clip_state (_cogl_get_draw_buffer ());
_cogl_clip_stack_rebuild (); _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 void
cogl_clip_stack_save (void) cogl_clip_stack_save (void)
{ {
CoglClipStack *stack; CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
stack = g_slice_new (CoglClipStack); draw_buffer = _cogl_get_draw_buffer ();
stack->stack_top = NULL; 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 void
cogl_clip_stack_restore (void) cogl_clip_stack_restore (void)
{ {
CoglClipStack *stack; CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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; _cogl_clip_stack_restore_real (clip_state);
/* 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;
} }
void void
_cogl_clip_stack_state_init (void) _cogl_clip_stack_state_init (CoglClipStackState *clip_state)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
ctx->clip.stacks = NULL; clip_state->stacks = NULL;
ctx->clip.stack_dirty = TRUE; clip_state->stack_dirty = TRUE;
/* Add an intial stack */ /* Add an intial stack */
cogl_clip_stack_save (); _cogl_clip_stack_save_real (clip_state);
} }
void 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 */ /* Destroy all of the stacks */
while (ctx->clip.stacks) while (clip_state->stacks)
cogl_clip_stack_restore (); _cogl_clip_stack_restore_real (clip_state);
} }
void
_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state)
{
clip_state->stack_dirty = TRUE;
}

View File

@ -35,9 +35,10 @@ struct _CoglClipStackState
gboolean stencil_used; gboolean stencil_used;
}; };
void _cogl_clip_stack_state_init (void); void _cogl_clip_stack_state_init (CoglClipStackState *state);
void _cogl_clip_stack_state_destroy (void); void _cogl_clip_stack_state_destroy (CoglClipStackState *state);
void _cogl_clip_stack_rebuild (void); void _cogl_clip_stack_state_dirty (CoglClipStackState *state);
void _cogl_clip_stack_merge (void);
void _cogl_flush_clip_state (CoglClipStackState *clip_state);
#endif /* __COGL_CLIP_STACK_H */ #endif /* __COGL_CLIP_STACK_H */

View File

@ -32,6 +32,7 @@
#include "cogl-journal-private.h" #include "cogl-journal-private.h"
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h> #include <string.h>
@ -46,7 +47,7 @@ cogl_create_context (void)
{ {
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 }; GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
gulong enable_flags = 0; gulong enable_flags = 0;
CoglDrawBufferState *draw_buffer; CoglHandle window_buffer;
if (_context != NULL) if (_context != NULL)
return FALSE; return FALSE;
@ -66,8 +67,6 @@ cogl_create_context (void)
_context->indirect = gl_is_indirect; _context->indirect = gl_is_indirect;
_context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW; _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->texture_units = NULL;
_context->default_material = cogl_material_new (); _context->default_material = cogl_material_new ();
@ -87,11 +86,14 @@ cogl_create_context (void)
sizeof (CoglLayerInfo)); sizeof (CoglLayerInfo));
_context->n_texcoord_arrays_enabled = 0; _context->n_texcoord_arrays_enabled = 0;
draw_buffer = g_slice_new0 (CoglDrawBufferState); _context->draw_buffer_stack = _cogl_create_draw_buffer_stack ();
draw_buffer->target = COGL_WINDOW_BUFFER; window_buffer = _cogl_onscreen_new ();
draw_buffer->offscreen = COGL_INVALID_HANDLE; /* XXX: When setting up the window buffer, cogl_set_draw_buffer
_context->draw_buffer_stack = * assumes that the handle can be found in ctx->window_buffer */
g_slist_prepend (NULL, draw_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->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
_context->last_path = 0; _context->last_path = 0;
@ -99,20 +101,16 @@ cogl_create_context (void)
_context->in_begin_gl_block = FALSE; _context->in_begin_gl_block = FALSE;
_context->viewport_width = 0;
_context->viewport_height = 0;
_context->quad_indices_byte = COGL_INVALID_HANDLE; _context->quad_indices_byte = COGL_INVALID_HANDLE;
_context->quad_indices_short = COGL_INVALID_HANDLE; _context->quad_indices_short = COGL_INVALID_HANDLE;
_context->quad_indices_short_len = 0; _context->quad_indices_short_len = 0;
_context->texture_download_material = COGL_INVALID_HANDLE; _context->texture_download_material = COGL_INVALID_HANDLE;
/* Initialise the clip stack */
_cogl_clip_stack_state_init ();
/* Initialise the driver specific state */ /* Initialise the driver specific state */
/* TODO: combine these two into one function */
_cogl_create_context_driver (_context); _cogl_create_context_driver (_context);
_cogl_features_init ();
/* Create default textures used for fall backs */ /* Create default textures used for fall backs */
_context->default_gl_texture_2d_tex = _context->default_gl_texture_2d_tex =
@ -146,16 +144,14 @@ cogl_create_context (void)
void void
_cogl_destroy_context () _cogl_destroy_context ()
{ {
if (_context == NULL) if (_context == NULL)
return; 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_destroy_texture_units ();
_cogl_free_draw_buffer_stack (_context->draw_buffer_stack);
if (_context->path_nodes) if (_context->path_nodes)
g_array_free (_context->path_nodes, TRUE); g_array_free (_context->path_nodes, TRUE);

View File

@ -38,12 +38,6 @@ typedef struct
GLubyte c[4]; GLubyte c[4];
} CoglTextureGLVertex; } CoglTextureGLVertex;
typedef struct
{
CoglBufferTarget target;
CoglHandle offscreen;
} CoglDrawBufferState;
typedef struct typedef struct
{ {
/* Features cache */ /* Features cache */
@ -60,9 +54,6 @@ typedef struct
/* Client-side matrix stack or NULL if none */ /* Client-side matrix stack or NULL if none */
CoglMatrixMode flushed_matrix_mode; CoglMatrixMode flushed_matrix_mode;
CoglMatrixStack *projection_stack;
CoglMatrixStack *modelview_stack;
GList *texture_units; GList *texture_units;
/* Cache of inverse projection matrix */ /* Cache of inverse projection matrix */
@ -91,11 +82,11 @@ typedef struct
GArray *current_layers; GArray *current_layers;
guint n_texcoord_arrays_enabled; guint n_texcoord_arrays_enabled;
/* Framebuffer objects */ /* Draw Buffers */
GSList *draw_buffer_stack; GSList *draw_buffer_stack;
CoglHandle window_buffer;
/* Clip stack */ gboolean dirty_bound_framebuffer;
CoglClipStackState clip; gboolean dirty_viewport;
/* Primitives */ /* Primitives */
floatVec2 path_start; floatVec2 path_start;
@ -114,9 +105,6 @@ typedef struct
gboolean in_begin_gl_block; gboolean in_begin_gl_block;
guint viewport_width;
guint viewport_height;
CoglHandle texture_download_material; CoglHandle texture_download_material;
CoglContextDriver drv; CoglContextDriver drv;

View File

@ -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 */

555
cogl/cogl-draw-buffer.c Normal file
View File

@ -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);
}

View File

@ -32,6 +32,7 @@
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-vertex-buffer-private.h" #include "cogl-vertex-buffer-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h> #include <string.h>
#include <gmodule.h> #include <gmodule.h>
@ -531,6 +532,8 @@ _cogl_journal_flush (void)
GLuint journal_vbo; GLuint journal_vbo;
gboolean vbo_fallback = gboolean vbo_fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE; (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
CoglHandle draw_buffer;
CoglMatrixStack *modelview_stack;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -547,20 +550,19 @@ _cogl_journal_flush (void)
else else
state.vbo_offset = (char *)ctx->logged_vertices->data; state.vbo_offset = (char *)ctx->logged_vertices->data;
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack, draw_buffer = _cogl_get_draw_buffer ();
COGL_MATRIX_PROJECTION); 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 (modelview_stack);
_cogl_matrix_stack_push (ctx->modelview_stack);
/* If we have transformed all our quads at log time then we ensure no /* If we have transformed all our quads at log time then we ensure no
* further model transform is applied by loading the identity matrix * further model transform is applied by loading the identity matrix
* here... */ * here... */
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{ {
_cogl_matrix_stack_load_identity (ctx->modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
COGL_MATRIX_MODELVIEW);
} }
/* batch_and_call() batches a list of journal entries according to some /* 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 */ _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
&state); /* data */ &state); /* data */
_cogl_matrix_stack_pop (ctx->modelview_stack); _cogl_matrix_stack_pop (modelview_stack);
for (i = 0; i < ctx->journal->len; i++) for (i = 0; i < ctx->journal->len; i++)
{ {
@ -607,6 +609,18 @@ _cogl_journal_flush (void)
g_array_set_size (ctx->logged_vertices, 0); 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 void
_cogl_journal_log_quad (float x_1, _cogl_journal_log_quad (float x_1,
float y_1, float y_1,
@ -632,6 +646,9 @@ _cogl_journal_log_quad (float x_1,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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 /* The vertex data is logged into a separate array in a layout that can be
* directly passed to OpenGL * directly passed to OpenGL
*/ */

View File

@ -32,6 +32,7 @@
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-vertex-buffer-private.h" #include "cogl-vertex-buffer-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h> #include <string.h>
#include <math.h> #include <math.h>
@ -396,8 +397,6 @@ _cogl_rectangles_with_multitexture_coords (
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_clip_ensure ();
material = ctx->source_material; material = ctx->source_material;
layers = cogl_material_get_layers (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; options.layer0_override_texture = gl_handle;
_cogl_material_flush_gl_state (ctx->source_material, &options); _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices)); 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.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
options.fallback_layers = fallback_layers; options.fallback_layers = fallback_layers;
_cogl_material_flush_gl_state (ctx->source_material, &options); _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices)); GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
} }
@ -866,7 +863,11 @@ cogl_polygon (CoglTextureVertex *vertices,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush (); _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; material = ctx->source_material;
layers = cogl_material_get_layers (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_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure ();
if (ctx->path_nodes->len == 0) if (ctx->path_nodes->len == 0)
return; return;
@ -1055,10 +1053,7 @@ cogl_path_stroke_preserve (void)
if (ctx->path_nodes->len == 0) if (ctx->path_nodes->len == 0)
return; return;
_cogl_journal_flush (); _cogl_path_stroke_nodes ();
cogl_clip_ensure ();
_cogl_path_stroke_nodes();
} }
void void

View File

@ -42,6 +42,7 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-handle.h" #include "cogl-handle.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-draw-buffer-private.h"
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
@ -667,7 +668,8 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
GLuint target_gl_type) GLuint target_gl_type)
{ {
gint bpp; gint bpp;
GLint viewport[4]; CoglHandle draw_buffer;
int viewport[4];
CoglBitmap alpha_bmp; CoglBitmap alpha_bmp;
CoglHandle prev_source; CoglHandle prev_source;
CoglMatrixStack *projection_stack; CoglMatrixStack *projection_stack;
@ -677,8 +679,9 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888); 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 */ /* 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 || if (viewport[0] < 0 || viewport[1] < 0 ||
viewport[2] <= 0 || viewport[3] <= 0) viewport[2] <= 0 || viewport[3] <= 0)
return FALSE; return FALSE;
@ -688,16 +691,18 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
* works) * works)
*/ */
_cogl_matrix_stack_push (ctx->projection_stack); projection_stack = _cogl_draw_buffer_get_projection_stack (draw_buffer);
_cogl_matrix_stack_load_identity (ctx->projection_stack); _cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_ortho (ctx->projection_stack, _cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_ortho (projection_stack,
0, (float)(viewport[2]), 0, (float)(viewport[2]),
0, (float)(viewport[3]), 0, (float)(viewport[3]),
(float)(0), (float)(0),
(float)(100)); (float)(100));
_cogl_matrix_stack_push (ctx->modelview_stack); modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer);
_cogl_matrix_stack_load_identity (ctx->modelview_stack); _cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
/* Direct copy operation */ /* Direct copy operation */

View File

@ -138,6 +138,7 @@
#include "cogl-texture-private.h" #include "cogl-texture-private.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-primitives.h" #include "cogl-primitives.h"
#include "cogl-draw-buffer-private.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \ #define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1))) (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; 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 = options.flags =
COGL_MATERIAL_FLUSH_FALLBACK_MASK | COGL_MATERIAL_FLUSH_FALLBACK_MASK |
COGL_MATERIAL_FLUSH_DISABLE_MASK; COGL_MATERIAL_FLUSH_DISABLE_MASK;
@ -1753,15 +1759,11 @@ cogl_vertex_buffer_draw (CoglHandle handle,
return; return;
_cogl_journal_flush (); _cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle); buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure ();
_cogl_flush_matrix_stacks ();
enable_state_for_drawing_buffer (buffer); enable_state_for_drawing_buffer (buffer);
/* FIXME: flush cogl cache */
GE (glDrawArrays (mode, first, count)); GE (glDrawArrays (mode, first, count));
disable_state_for_drawing_buffer (buffer); disable_state_for_drawing_buffer (buffer);
@ -1885,7 +1887,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
return; return;
_cogl_journal_flush (); _cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle); 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); indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
cogl_clip_ensure ();
_cogl_flush_matrix_stacks ();
enable_state_for_drawing_buffer (buffer); enable_state_for_drawing_buffer (buffer);
byte_offset = indices_offset * get_indices_type_size (indices->type); 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, GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name))); GPOINTER_TO_UINT (indices->vbo_name)));
/* FIXME: flush cogl cache */
GE (glDrawRangeElements (mode, min_index, max_index, GE (glDrawRangeElements (mode, min_index, max_index,
count, indices->type, (void *)byte_offset)); count, indices->type, (void *)byte_offset));

View File

@ -38,6 +38,7 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-winsys.h" #include "cogl-winsys.h"
#include "cogl-draw-buffer-private.h"
#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES) #if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
#include "cogl-gles2-wrapper.h" #include "cogl-gles2-wrapper.h"
@ -116,7 +117,12 @@ cogl_clear (const CoglColor *color, gulong buffers)
COGL_NOTE (DRAW, "Clear begin"); 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) if (buffers & COGL_BUFFER_BIT_COLOR)
{ {
@ -327,6 +333,10 @@ set_clip_plane (GLint plane_num,
#endif #endif
GLfloat angle; GLfloat angle;
CoglMatrix inverse_projection; 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); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Calculate the angle between the axes and the line crossing the /* 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], angle = atan2f (vertex_b[1] - vertex_a[1],
vertex_b[0] - vertex_a[0]) * (180.0/G_PI); 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 /* Load the identity matrix and multiply by the reverse of the
projection matrix so we can specify the plane in screen projection matrix so we can specify the plane in screen
coordinates */ coordinates */
_cogl_matrix_stack_load_identity (ctx->modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack);
cogl_matrix_init_from_array (&inverse_projection, cogl_matrix_init_from_array (&inverse_projection,
ctx->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 */ /* 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]); vertex_a[0], vertex_a[1], vertex_a[2]);
/* Rotate the plane by the calculated angle so that it will connect /* Rotate the plane by the calculated angle so that it will connect
the two points */ the two points */
_cogl_matrix_stack_rotate (ctx->modelview_stack, angle, 0.0f, 0.0f, 1.0f); _cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
_cogl_matrix_stack_translate (ctx->modelview_stack, _cogl_matrix_stack_translate (modelview_stack,
-vertex_a[0], -vertex_a[1], -vertex_a[2]); -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[0] = 0;
plane[1] = -1.0; plane[1] = -1.0;
@ -363,7 +374,7 @@ set_clip_plane (GLint plane_num,
GE( glClipPlane (plane_num, plane) ); GE( glClipPlane (plane_num, plane) );
#endif #endif
_cogl_matrix_stack_pop (ctx->modelview_stack); _cogl_matrix_stack_pop (modelview_stack);
} }
void void
@ -372,7 +383,12 @@ _cogl_set_clip_planes (float x_offset,
float width, float width,
float height) float height)
{ {
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrix modelview_matrix; CoglMatrix modelview_matrix;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
CoglMatrix projection_matrix; CoglMatrix projection_matrix;
float vertex_tl[4] = { x_offset, y_offset, 0, 1.0 }; 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, float vertex_br[4] = { x_offset + width, y_offset + height,
0, 1.0 }; 0, 1.0 };
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_matrix_stack_get (projection_stack, &projection_matrix);
_cogl_matrix_stack_get (modelview_stack, &modelview_matrix);
_cogl_matrix_stack_get (ctx->projection_stack, &projection_matrix);
_cogl_matrix_stack_get (ctx->modelview_stack, &modelview_matrix);
project_vertex (&modelview_matrix, &projection_matrix, vertex_tl); project_vertex (&modelview_matrix, &projection_matrix, vertex_tl);
project_vertex (&modelview_matrix, &projection_matrix, vertex_tr); project_vertex (&modelview_matrix, &projection_matrix, vertex_tr);
@ -422,6 +436,7 @@ _cogl_add_stencil_clip (float x_offset,
gboolean first) gboolean first)
{ {
CoglHandle current_source; CoglHandle current_source;
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -429,6 +444,8 @@ _cogl_add_stencil_clip (float x_offset,
* batched geometry before we start... */ * batched geometry before we start... */
_cogl_journal_flush (); _cogl_journal_flush ();
_cogl_draw_buffer_flush_state (draw_buffer, 0);
/* temporarily swap in our special stenciling material */ /* temporarily swap in our special stenciling material */
current_source = cogl_handle_ref (ctx->source_material); current_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material); cogl_set_source (ctx->stencil_material);
@ -450,6 +467,11 @@ _cogl_add_stencil_clip (float x_offset,
} }
else 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 /* Add one to every pixel of the stencil buffer in the
rectangle */ rectangle */
GE( glStencilFunc (GL_NEVER, 0x1, 0x3) ); GE( glStencilFunc (GL_NEVER, 0x1, 0x3) );
@ -466,16 +488,16 @@ _cogl_add_stencil_clip (float x_offset,
rectangle are set will be valid */ rectangle are set will be valid */
GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
_cogl_matrix_stack_push (ctx->projection_stack); _cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (ctx->projection_stack); _cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_push (ctx->modelview_stack); _cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (ctx->modelview_stack); _cogl_matrix_stack_load_identity (modelview_stack);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0); cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
_cogl_matrix_stack_pop (ctx->modelview_stack); _cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack); _cogl_matrix_stack_pop (projection_stack);
} }
/* make sure our rectangles hit the stencil buffer before we restore /* 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) ); GE( glDisable (GL_CLIP_PLANE0) );
} }
/* XXX: This should be deprecated and Cogl should be left to manage void
* the glViewport automatically when switching draw buffers. */ _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 void
cogl_viewport (guint width, cogl_viewport (guint width,
guint height) guint height)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _cogl_set_viewport (0, 0, width, height);
COGL_NOTE (MISC, "glViewport(0, 0, %u, %u)", width, height);
GE( glViewport (0, 0, width, height) );
ctx->viewport_width = width;
ctx->viewport_height = height;
} }
void void
@ -540,6 +575,7 @@ _cogl_setup_viewport (guint width,
{ {
float z_camera; float z_camera;
CoglMatrix projection_matrix; CoglMatrix projection_matrix;
CoglMatrixStack *modelview_stack;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -593,11 +629,13 @@ _cogl_setup_viewport (guint width,
cogl_get_projection_matrix (&projection_matrix); cogl_get_projection_matrix (&projection_matrix);
z_camera = 0.5 * projection_matrix.xx; z_camera = 0.5 * projection_matrix.xx;
_cogl_matrix_stack_load_identity (ctx->modelview_stack); modelview_stack =
_cogl_matrix_stack_translate (ctx->modelview_stack, -0.5f, -0.5f, -z_camera); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_scale (ctx->modelview_stack, _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); 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); 0.0f, -1.0 * height, 0.0f);
} }
@ -606,9 +644,6 @@ cogl_get_features (void)
{ {
_COGL_GET_CONTEXT (ctx, 0); _COGL_GET_CONTEXT (ctx, 0);
if (!ctx->features_cached)
_cogl_features_init ();
if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS) if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS)
ctx->feature_flags &= ~COGL_FEATURE_VBOS; ctx->feature_flags &= ~COGL_FEATURE_VBOS;
@ -626,18 +661,24 @@ cogl_features_available (CoglFeatureFlags features)
return (ctx->feature_flags & features) == features; return (ctx->feature_flags & features) == features;
} }
/* XXX: This function should be deprecated, and replaced with a /* XXX: This function should either be replaced with one returning
* cogl_draw_buffer_get_size() API instead. We don't support offset * integers, or removed/deprecated and make the
* viewports, and you can't have floating point viewport sizes. */ * _cogl_draw_buffer_get_viewport* functions public.
*/
void void
cogl_get_viewport (float v[4]) cogl_get_viewport (float v[4])
{ {
CoglHandle draw_buffer;
int viewport[4];
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
v[0] = 0; draw_buffer = _cogl_get_draw_buffer ();
v[1] = 0; _cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport);
v[2] = ctx->viewport_width;
v[3] = ctx->viewport_height; for (i = 0; i < 4; i++)
v[i] = viewport[i];
} }
void void
@ -733,7 +774,7 @@ cogl_disable_fog (void)
void void
cogl_flush_gl_state (int flags) cogl_flush_gl_state (int flags)
{ {
_cogl_flush_matrix_stacks (); _cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
} }
#endif #endif
@ -752,18 +793,20 @@ cogl_read_pixels (int x,
CoglPixelFormat format, CoglPixelFormat format,
guint8 *pixels) guint8 *pixels)
{ {
GLint viewport[4]; int viewport_height;
GLint viewport_height; int rowstride = width * 4;
int rowstride = width * 4; guint8 *temprow;
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 (format == COGL_PIXEL_FORMAT_RGBA_8888);
g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER); g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER);
temprow = g_alloca (rowstride * sizeof (guint8)); temprow = g_alloca (rowstride * sizeof (guint8));
glGetIntegerv (GL_VIEWPORT, viewport); draw_buffer = _cogl_get_draw_buffer ();
viewport_height = viewport[3]; viewport_height = _cogl_draw_buffer_get_viewport_height (draw_buffer);
/* The y co-ordinate should be given in OpenGL's coordinate system /* The y co-ordinate should be given in OpenGL's coordinate system
so 0 is the bottom row */ so 0 is the bottom row */
@ -825,12 +868,13 @@ cogl_begin_gl (void)
/* Flush all batched primitives */ /* Flush all batched primitives */
cogl_flush (); cogl_flush ();
/* Flush our clipping state to GL */ /* Flush framebuffer state, including clip state, modelview and
cogl_clip_ensure (); * projection matrix state
*
/* Flush any client side matrix state */ * NB: _cogl_draw_buffer_flush_state may disrupt various state (such
_cogl_flush_matrix_stacks (); * 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 */ /* Setup the state for the current material */
@ -940,36 +984,41 @@ _cogl_destroy_texture_units (void)
void void
cogl_push_matrix (void) cogl_push_matrix (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_push (ctx->modelview_stack); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_push (modelview_stack);
} }
void void
cogl_pop_matrix (void) cogl_pop_matrix (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_pop (ctx->modelview_stack); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_pop (modelview_stack);
} }
void void
cogl_scale (float x, float y, float z) cogl_scale (float x, float y, float z)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_scale (ctx->modelview_stack, x, y, z); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_scale (modelview_stack, x, y, z);
} }
void void
cogl_translate (float x, float y, float z) cogl_translate (float x, float y, float z)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_translate (ctx->modelview_stack, x, y, z); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_translate (modelview_stack, x, y, z);
} }
void void
cogl_rotate (float angle, float x, float y, float z) cogl_rotate (float angle, float x, float y, float z)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_rotate (ctx->modelview_stack, angle, x, y, z); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
} }
void void
@ -997,12 +1046,14 @@ cogl_frustum (float left,
float z_far) float z_far)
{ {
float c, d; float c, d;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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, left,
right, right,
bottom, bottom,
@ -1036,12 +1087,14 @@ cogl_ortho (float left,
float z_far) float z_far)
{ {
CoglMatrix ortho; CoglMatrix ortho;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_matrix_init_identity (&ortho); cogl_matrix_init_identity (&ortho);
cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far); 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 */ /* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16); memset (ctx->inverse_projection, 0, sizeof (float) * 16);
@ -1060,41 +1113,44 @@ cogl_ortho (float left,
void void
cogl_get_modelview_matrix (CoglMatrix *matrix) cogl_get_modelview_matrix (CoglMatrix *matrix)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_get (ctx->modelview_stack, matrix); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_get (modelview_stack, matrix);
} }
void void
cogl_set_modelview_matrix (CoglMatrix *matrix) cogl_set_modelview_matrix (CoglMatrix *matrix)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *modelview_stack =
_cogl_matrix_stack_set (ctx->modelview_stack, matrix); _cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_set (modelview_stack, matrix);
} }
void void
cogl_get_projection_matrix (CoglMatrix *matrix) cogl_get_projection_matrix (CoglMatrix *matrix)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *projection_stack =
_cogl_matrix_stack_get (ctx->projection_stack, matrix); _cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_get (projection_stack, matrix);
} }
void void
cogl_set_projection_matrix (CoglMatrix *matrix) cogl_set_projection_matrix (CoglMatrix *matrix)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglMatrixStack *projection_stack =
_cogl_matrix_stack_set (ctx->projection_stack, matrix); _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 /* FIXME: Update the inverse projection matrix!! Presumably use
* of clip planes must currently be broken if this API is used. */ * of clip planes must currently be broken if this API is used. */
} }
void CoglClipStackState *
_cogl_flush_matrix_stacks (void) _cogl_get_clip_state (void)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglHandle draw_buffer;
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
COGL_MATRIX_PROJECTION); draw_buffer = _cogl_get_draw_buffer ();
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, return _cogl_draw_buffer_get_clip_state (draw_buffer);
COGL_MATRIX_MODELVIEW);
} }

View File

@ -867,6 +867,7 @@ void cogl_flush_gl_state (int flags);
/* private */ /* private */
void _cogl_set_indirect_context (gboolean indirect); void _cogl_set_indirect_context (gboolean indirect);
void _cogl_set_viewport (int x, int y, int width, int height);
G_END_DECLS G_END_DECLS

View File

@ -25,8 +25,6 @@ libclutter_cogl_driver_la_SOURCES = \
cogl.c \ cogl.c \
cogl-primitives.c \ cogl-primitives.c \
cogl-texture-driver.c \ cogl-texture-driver.c \
cogl-fbo.h \
cogl-fbo.c \
cogl-shader-private.h \ cogl-shader-private.h \
cogl-shader.c \ cogl-shader.c \
cogl-program.h \ cogl-program.h \

View File

@ -30,15 +30,16 @@
void void
_cogl_create_context_driver (CoglContext *_context) _cogl_create_context_driver (CoglContext *_context)
{ {
_context->drv.pf_glGenRenderbuffersEXT = NULL; _context->drv.pf_glGenRenderbuffers = NULL;
_context->drv.pf_glBindRenderbufferEXT = NULL; _context->drv.pf_glBindRenderbuffer = NULL;
_context->drv.pf_glRenderbufferStorageEXT = NULL; _context->drv.pf_glRenderbufferStorage = NULL;
_context->drv.pf_glGenFramebuffersEXT = NULL; _context->drv.pf_glGenFramebuffers = NULL;
_context->drv.pf_glBindFramebufferEXT = NULL; _context->drv.pf_glBindFramebuffer = NULL;
_context->drv.pf_glFramebufferTexture2DEXT = NULL; _context->drv.pf_glFramebufferTexture2D = NULL;
_context->drv.pf_glFramebufferRenderbufferEXT = NULL; _context->drv.pf_glFramebufferRenderbuffer = NULL;
_context->drv.pf_glCheckFramebufferStatusEXT = NULL; _context->drv.pf_glCheckFramebufferStatus = NULL;
_context->drv.pf_glDeleteFramebuffersEXT = NULL; _context->drv.pf_glDeleteFramebuffers = NULL;
_context->drv.pf_glBlitFramebufferEXT = NULL; _context->drv.pf_glBlitFramebufferEXT = NULL;
_context->drv.pf_glRenderbufferStorageMultisampleEXT = NULL; _context->drv.pf_glRenderbufferStorageMultisampleEXT = NULL;

View File

@ -29,19 +29,20 @@
typedef struct _CoglContextDriver typedef struct _CoglContextDriver
{ {
/* Relying on glext.h to define these */ /* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT; COGL_PFNGLGENRENDERBUFFERSPROC pf_glGenRenderbuffers;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT; COGL_PFNGLDELETERENDERBUFFERSPROC pf_glDeleteRenderbuffers;
COGL_PFNGLBINDRENDERBUFFEREXTPROC pf_glBindRenderbufferEXT; COGL_PFNGLBINDRENDERBUFFERPROC pf_glBindRenderbuffer;
COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC pf_glRenderbufferStorageEXT; COGL_PFNGLRENDERBUFFERSTORAGEPROC pf_glRenderbufferStorage;
COGL_PFNGLGENFRAMEBUFFERSEXTPROC pf_glGenFramebuffersEXT; COGL_PFNGLGENFRAMEBUFFERSPROC pf_glGenFramebuffers;
COGL_PFNGLBINDFRAMEBUFFEREXTPROC pf_glBindFramebufferEXT; COGL_PFNGLBINDFRAMEBUFFERPROC pf_glBindFramebuffer;
COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC pf_glFramebufferTexture2DEXT; COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC pf_glFramebufferTexture2D;
COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC pf_glFramebufferRenderbufferEXT; COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC pf_glFramebufferRenderbuffer;
COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC pf_glCheckFramebufferStatusEXT; COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC pf_glCheckFramebufferStatus;
COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC pf_glDeleteFramebuffersEXT; COGL_PFNGLDELETEFRAMEBUFFERSPROC pf_glDeleteFramebuffers;
COGL_PFNGLGENERATEMIPMAPPROC pf_glGenerateMipmap;
COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT; COGL_PFNGLBLITFRAMEBUFFEREXTPROC pf_glBlitFramebufferEXT;
COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT; COGL_PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC pf_glRenderbufferStorageMultisampleEXT;
COGL_PFNGLGENERATEMIPMAPEXTPROC pf_glGenerateMipmapEXT;
COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB; COGL_PFNGLCREATEPROGRAMOBJECTARBPROC pf_glCreateProgramObjectARB;
COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB; COGL_PFNGLCREATESHADEROBJECTARBPROC pf_glCreateShaderObjectARB;

View File

@ -698,34 +698,34 @@ G_BEGIN_DECLS
#endif #endif
typedef void typedef void
(APIENTRYP COGL_PFNGLGENRENDERBUFFERSEXTPROC) (APIENTRYP COGL_PFNGLGENRENDERBUFFERSPROC)
(GLsizei n, (GLsizei n,
GLuint *renderbuffers); GLuint *renderbuffers);
typedef void typedef void
(APIENTRYP COGL_PFNGLBINDRENDERBUFFEREXTPROC) (APIENTRYP COGL_PFNGLBINDRENDERBUFFERPROC)
(GLenum target, (GLenum target,
GLuint renderbuffer); GLuint renderbuffer);
typedef void typedef void
(APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC) (APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEPROC)
(GLenum target, (GLenum target,
GLenum internalformat, GLenum internalformat,
GLsizei width, GLsizei width,
GLsizei height); GLsizei height);
typedef void typedef void
(APIENTRYP COGL_PFNGLGENFRAMEBUFFERSEXTPROC) (APIENTRYP COGL_PFNGLGENFRAMEBUFFERSPROC)
(GLsizei n, (GLsizei n,
GLuint *framebuffers); GLuint *framebuffers);
typedef void typedef void
(APIENTRYP COGL_PFNGLBINDFRAMEBUFFEREXTPROC) (APIENTRYP COGL_PFNGLBINDFRAMEBUFFERPROC)
(GLenum target, (GLenum target,
GLuint framebuffer); GLuint framebuffer);
typedef void typedef void
(APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC)
(GLenum target, (GLenum target,
GLenum attachment, GLenum attachment,
GLenum textarget, GLenum textarget,
@ -733,26 +733,30 @@ typedef void
GLint level); GLint level);
typedef void typedef void
(APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC)
(GLenum target, (GLenum target,
GLenum attachment, GLenum attachment,
GLenum renderbuffertarget, GLenum renderbuffertarget,
GLuint renderbuffer); GLuint renderbuffer);
typedef GLenum typedef GLenum
(APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC)
(GLenum target); (GLenum target);
typedef void typedef void
(APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC) (APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSPROC)
(GLsizei n, (GLsizei n,
const GLuint *framebuffers); const GLuint *framebuffers);
typedef void typedef void
(APIENTRYP COGL_PFNGLDELETERENDERBUFFERSEXTPROC) (APIENTRYP COGL_PFNGLDELETERENDERBUFFERSPROC)
(GLsizei n, (GLsizei n,
const GLuint *renderbuffers); const GLuint *renderbuffers);
typedef void
(APIENTRYP COGL_PFNGLGENERATEMIPMAPPROC)
(GLenum target);
typedef void typedef void
(APIENTRYP COGL_PFNGLBLITFRAMEBUFFEREXTPROC) (APIENTRYP COGL_PFNGLBLITFRAMEBUFFEREXTPROC)
(GLint srcX0, (GLint srcX0,
@ -774,10 +778,6 @@ typedef void
GLsizei width, GLsizei width,
GLsizei height); GLsizei height);
typedef void
(APIENTRYP COGL_PFNGLGENERATEMIPMAPEXTPROC)
(GLenum target);
typedef GLhandleARB typedef GLhandleARB
(APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC) (APIENTRYP COGL_PFNGLCREATEPROGRAMOBJECTARBPROC)
(void); (void);

View File

@ -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);
}

View File

@ -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 */

View File

@ -30,6 +30,8 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-clip-stack.h"
#include "cogl-draw-buffer-private.h"
#include <string.h> #include <string.h>
#include <gmodule.h> #include <gmodule.h>
@ -74,7 +76,7 @@ _cogl_path_add_node (gboolean new_sub_path,
} }
void void
_cogl_path_stroke_nodes () _cogl_path_stroke_nodes (void)
{ {
guint path_start = 0; guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@ -82,6 +84,13 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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); enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags); cogl_enable (enable_flags);
@ -90,7 +99,6 @@ _cogl_path_stroke_nodes ()
options.disable_layers = (guint32)~0; options.disable_layers = (guint32)~0;
_cogl_material_flush_gl_state (ctx->source_material, &options); _cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
while (path_start < ctx->path_nodes->len) while (path_start < ctx->path_nodes->len)
{ {
@ -127,20 +135,33 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path, CoglPathNode *path,
gboolean merge) gboolean merge)
{ {
guint path_start = 0; guint path_start = 0;
guint sub_path_num = 0; guint sub_path_num = 0;
float bounds_x; float bounds_x;
float bounds_y; float bounds_y;
float bounds_w; float bounds_w;
float bounds_h; float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source; CoglHandle prev_source;
int i; 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); _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 (); _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... */ /* Just setup a simple material that doesn't use texturing... */
prev_source = cogl_handle_ref (ctx->source_material); prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material); cogl_set_source (ctx->stencil_material);
@ -161,7 +182,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
} }
else else
{ {
GE( glClear (GL_STENCIL_BUFFER_BIT) ); cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
GE( glStencilMask (1) ); GE( glStencilMask (1) );
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) ); 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; ctx->n_texcoord_arrays_enabled = 0;
_cogl_flush_matrix_stacks ();
while (path_start < path_size) while (path_start < path_size)
{ {
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@ -194,8 +213,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
significant bit */ significant bit */
GE( glStencilMask (merge ? 6 : 3) ); GE( glStencilMask (merge ? 6 : 3) );
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) ); GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
glRectf (bounds_x, bounds_y, cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h); 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) ); 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 /* Decrement all of the bits twice so that only pixels where the
value is 3 will remain */ value is 3 will remain */
_cogl_matrix_stack_push (ctx->projection_stack); _cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (ctx->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_push (modelview_stack);
_cogl_matrix_stack_load_identity (ctx->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); _cogl_matrix_stack_pop (modelview_stack);
glRectf (-1.0, -1.0, 1.0, 1.0); _cogl_matrix_stack_pop (projection_stack);
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack);
} }
GE( glStencilMask (~(GLuint) 0) ); GE( glStencilMask (~(GLuint) 0) );
@ -244,8 +277,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
} }
void void
_cogl_path_fill_nodes () _cogl_path_fill_nodes (void)
{ {
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
float bounds_x; float bounds_x;
float bounds_y; float bounds_y;
float bounds_w; float bounds_w;
@ -253,6 +288,11 @@ _cogl_path_fill_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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, _cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
&bounds_x, &bounds_y, &bounds_w, &bounds_h); &bounds_x, &bounds_y, &bounds_w, &bounds_h);
@ -261,12 +301,13 @@ _cogl_path_fill_nodes ()
ctx->path_nodes->len, ctx->path_nodes->len,
&g_array_index (ctx->path_nodes, &g_array_index (ctx->path_nodes,
CoglPathNode, 0), CoglPathNode, 0),
ctx->clip.stencil_used); clip_state->stencil_used);
cogl_rectangle (bounds_x, bounds_y, cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h); bounds_x + bounds_w, bounds_y + bounds_h);
/* The stencil buffer now contains garbage so the clip area needs to /* The stencil buffer now contains garbage so the clip area needs to
be rebuilt */ be rebuilt */
ctx->clip.stack_dirty = TRUE; _cogl_clip_stack_state_dirty (clip_state);
} }

View File

@ -45,7 +45,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#define glGenerateMipmap ctx->drv.pf_glGenerateMipmapEXT #define glGenerateMipmap ctx->drv.pf_glGenerateMipmap
void void
_cogl_texture_driver_bind (GLenum gl_target, _cogl_texture_driver_bind (GLenum gl_target,

View File

@ -32,6 +32,12 @@
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-context.h" #include "cogl-context.h"
typedef struct _CoglGLSymbolTableEntry
{
const char *name;
void *ptr;
} CoglGLSymbolTableEntry;
gboolean gboolean
cogl_check_extension (const gchar *name, const gchar *ext) cogl_check_extension (const gchar *name, const gchar *ext)
{ {
@ -57,6 +63,26 @@ cogl_check_extension (const gchar *name, const gchar *ext)
return FALSE; 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 #ifdef HAVE_CLUTTER_OSX
static gboolean static gboolean
really_enable_npot (void) really_enable_npot (void)
@ -90,6 +116,9 @@ _cogl_features_init (void)
const gchar *gl_extensions; const gchar *gl_extensions;
GLint max_clip_planes = 0; GLint max_clip_planes = 0;
GLint num_stencil_bits = 0; GLint num_stencil_bits = 0;
gboolean fbo_ARB = FALSE;
gboolean fbo_EXT = FALSE;
const char *suffix;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -284,64 +313,35 @@ _cogl_features_init (void)
flags |= COGL_FEATURE_SHADERS_GLSL; flags |= COGL_FEATURE_SHADERS_GLSL;
} }
if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) || fbo_ARB = cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions);
cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions)) if (fbo_ARB)
suffix = "";
else
{ {
ctx->drv.pf_glGenRenderbuffersEXT = fbo_EXT = cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions);
(COGL_PFNGLGENRENDERBUFFERSEXTPROC) if (fbo_EXT)
cogl_get_proc_address ("glGenRenderbuffersEXT"); suffix = "EXT";
}
ctx->drv.pf_glDeleteRenderbuffersEXT = if (fbo_ARB || fbo_EXT)
(COGL_PFNGLDELETERENDERBUFFERSEXTPROC) {
cogl_get_proc_address ("glDeleteRenderbuffersEXT"); 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 = if (_cogl_resolve_gl_symbols (symbol_table, suffix))
(COGL_PFNGLBINDRENDERBUFFEREXTPROC) flags |= COGL_FEATURE_OFFSCREEN;
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_check_extension ("GL_EXT_framebuffer_blit", gl_extensions)) if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))

View File

@ -22,11 +22,9 @@ libclutter_cogl_driver_la_CPPFLAGS = \
$(CLUTTER_DEBUG_CFLAGS) \ $(CLUTTER_DEBUG_CFLAGS) \
$(MAINTAINER_CFLAGS) $(MAINTAINER_CFLAGS)
libclutter_cogl_driver_la_SOURCES = \ libclutter_cogl_driver_la_SOURCES = \
cogl-fbo.h \
cogl.c \ cogl.c \
cogl-primitives.c \ cogl-primitives.c \
cogl-texture-driver.c \ cogl-texture-driver.c \
cogl-fbo.c \
cogl-context-driver.c \ cogl-context-driver.c \
cogl-context-driver.h \ cogl-context-driver.h \
cogl-gles2-wrapper.h \ cogl-gles2-wrapper.h \

View File

@ -31,6 +31,16 @@
void void
_cogl_create_context_driver (CoglContext *context) _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 */ /* Init the GLES2 wrapper */
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
cogl_gles2_wrapper_init (&context->drv.gles2); cogl_gles2_wrapper_init (&context->drv.gles2);

View File

@ -24,17 +24,26 @@
#ifndef __COGL_CONTEXT_DRIVER_H #ifndef __COGL_CONTEXT_DRIVER_H
#define __COGL_CONTEXT_DRIVER_H #define __COGL_CONTEXT_DRIVER_H
#include "cogl.h"
#include "cogl-gles2-wrapper.h" #include "cogl-gles2-wrapper.h"
typedef struct _CoglContextDriver 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 #ifdef HAVE_COGL_GLES2
CoglGles2Wrapper gles2; CoglGles2Wrapper gles2;
/* Viewport store for FBOs. Needed because glPushAttrib() isn't
supported */
GLint viewport_store[4];
#endif #endif
} CoglContextDriver; } CoglContextDriver;

View File

@ -633,6 +633,76 @@ G_BEGIN_DECLS
#define CGL_SHININESS 0x1601 #define CGL_SHININESS 0x1601
#endif #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 G_END_DECLS
#endif #endif

View File

@ -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 */

View File

@ -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 */

View File

@ -30,6 +30,9 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-clip-stack.h" #include "cogl-clip-stack.h"
#include "cogl-material-private.h" #include "cogl-material-private.h"
#include "cogl-clip-stack.h"
#include "cogl-draw-buffer-private.h"
#include "cogl-clip-stack.h"
#include <string.h> #include <string.h>
#include <gmodule.h> #include <gmodule.h>
@ -72,7 +75,7 @@ _cogl_path_add_node (gboolean new_sub_path,
} }
void void
_cogl_path_stroke_nodes () _cogl_path_stroke_nodes (void)
{ {
guint path_start = 0; guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@ -80,13 +83,21 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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); enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags); cogl_enable (enable_flags);
options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK; options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
/* disable all texture layers */
options.disable_layers = (guint32)~0; 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) while (path_start < ctx->path_nodes->len)
{ {
@ -129,18 +140,38 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path, CoglPathNode *path,
gboolean merge) gboolean merge)
{ {
guint path_start = 0; guint path_start = 0;
guint sub_path_num = 0; guint sub_path_num = 0;
float bounds_x; float bounds_x;
float bounds_y; float bounds_y;
float bounds_w; float bounds_w;
float bounds_h; float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY; 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); _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... */ /* 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 |= enable_flags |=
_cogl_material_get_cogl_enable_flags (ctx->source_material); _cogl_material_get_cogl_enable_flags (ctx->source_material);
@ -156,7 +187,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
} }
else else
{ {
GE( glClear (GL_STENCIL_BUFFER_BIT) ); cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
GE( glStencilMask (1) ); GE( glStencilMask (1) );
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) ); 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( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (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) while (path_start < path_size)
{ {
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode), 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) ); GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
cogl_rectangle (bounds_x, bounds_y, cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h); 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) ); 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 /* Decrement all of the bits twice so that only pixels where the
value is 3 will remain */ value is 3 will remain */
_cogl_matrix_stack_push (ctx->projection_stack); _cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (ctx->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_push (modelview_stack);
_cogl_matrix_stack_load_identity (ctx->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);
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 (modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack); _cogl_matrix_stack_pop (projection_stack);
} }
GE( glStencilMask (~(GLuint) 0) ); GE( glStencilMask (~(GLuint) 0) );
@ -250,6 +302,21 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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 */ /* clear scanline intersection lists */
for (i=0; i < bounds_h; i++) for (i=0; i < bounds_h; i++)
scanlines[i]=NULL; scanlines[i]=NULL;
@ -386,8 +453,6 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
} }
/* render triangles */ /* render triangles */
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) ); GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) );
GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3)); GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
g_free (coords); g_free (coords);
@ -395,7 +460,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
} }
void void
_cogl_path_fill_nodes () _cogl_path_fill_nodes (void)
{ {
float bounds_x; float bounds_x;
float bounds_y; float bounds_y;
@ -409,19 +474,27 @@ _cogl_path_fill_nodes ()
if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER)) 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, _cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
ctx->path_nodes_max, ctx->path_nodes_max,
ctx->path_nodes->len, ctx->path_nodes->len,
&g_array_index (ctx->path_nodes, &g_array_index (ctx->path_nodes,
CoglPathNode, 0), CoglPathNode, 0),
ctx->clip.stencil_used); clip_state->stencil_used);
cogl_rectangle (bounds_x, bounds_y, cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h); bounds_x + bounds_w, bounds_y + bounds_h);
/* The stencil buffer now contains garbage so the clip area needs to /* The stencil buffer now contains garbage so the clip area needs to
be rebuilt */ be rebuilt */
ctx->clip.stack_dirty = TRUE; _cogl_clip_stack_state_dirty (clip_state);
} }
else else
{ {

View File

@ -31,6 +31,56 @@
#include "cogl-internal.h" #include "cogl-internal.h"
#include "cogl-context.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 void
@ -39,9 +89,34 @@ _cogl_features_init (void)
CoglFeatureFlags flags = 0; CoglFeatureFlags flags = 0;
int max_clip_planes = 0; int max_clip_planes = 0;
GLint num_stencil_bits = 0; GLint num_stencil_bits = 0;
const char *gl_extensions;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _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) ); GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
/* We need at least three stencil bits to combine clips */ /* We need at least three stencil bits to combine clips */
if (num_stencil_bits > 2) if (num_stencil_bits > 2)