Merge commit 'cogl-reorg-draw-buffers'

* cogl-reorg-draw-buffers: (38 commits)
  [test-fbo] greatly simplify the test
  [tests] test-backface-culling: test culling with offscreen rendering
  [tests] Adds test-cogl-readpixels.c for very basic cogl_read_pixels testing
  [tests] Adds test-cogl-offscreen to validate offscreen draw buffer
  [tests] test-cogl-viewport tests semantics of over/under size viewports
  [test-texture-fbo] comment the colors defined in corner_colors
  Add a conformance test for clutter_texture_new_from_actor
  [cogl-texture-2d-sliced] allow COGL_FORMAT_ANY with _new_with_size()
  [texture] fix rounding when calculating update_fbo viewport offset
  [texture] switch to a new design for handling offscreen rendering
  [texture] split out fbo update code from cluter_texture_paint
  [texture] push/pop draw buffer when painting actors to a texture
  [texture] Avoid redundant use of cogl_clip_stack_save when drawing offscreen
  [cogl-draw-buffer] fix Cogl -> GL viewport coord conversion
  [cogl_clip_push_window_rect] fix Cogl -> GL coordinate conversion
  [matrix] Adds cogl_matrix_get_inverse API
  [debug] Adds a COGL_DEBUG=matrices debug option
  [cogl-matrix] Import Mesa's matrix manipulation code
  [cogl] avoid any state changes when cogl_set_backface_culling_enable is a nop
  [cogl] Use clockwise face winding for offscreen buffers with culling enabled
  ...
This commit is contained in:
Robert Bragg 2009-11-04 03:46:45 +00:00
commit 9cfc8acb77
40 changed files with 3806 additions and 1181 deletions

View File

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

View File

@ -34,6 +34,7 @@
#include "cogl-primitives.h"
#include "cogl-context.h"
#include "cogl-internal.h"
#include "cogl-draw-buffer-private.h"
/* These are defined in the particular backend (float in GL vs fixed
in GL ES) */
@ -113,45 +114,79 @@ struct _CoglClipStackEntryPath
CoglPathNode path[1];
};
/* FIXME: deprecate and replace with:
* void
* cogl_clip_push_window_rectangle (int x_offset,
* int y_offset,
* int width,
* int height);
*/
void
cogl_clip_push_window_rect (float x_offset,
float y_offset,
float width,
float height)
{
CoglClipStackEntryWindowRect *entry;
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack;
float v[4];
int draw_buffer_height;
CoglClipStackEntryWindowRect *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
stack = (CoglClipStack *) ctx->clip.stacks->data;
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
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;
draw_buffer_height = _cogl_draw_buffer_get_height (draw_buffer);
entry = g_slice_new (CoglClipStackEntryWindowRect);
/* We convert from coords with (0,0) at top left to coords
* with (0,0) at bottom left. */
/* We store the entry coordinates in OpenGL window coordinate space and so
* because Cogl defines the window origin to be top left but OpenGL defines
* it as bottom left we may need to convert the incoming coordinates.
*
* NB: Cogl forces all offscreen rendering to be done upside down so in this
* case no conversion is needed.
*/
entry->type = COGL_CLIP_STACK_WINDOW_RECT;
entry->x0 = x_offset;
entry->y0 = v[3] - y_offset - height;
entry->x1 = x_offset + width;
entry->y1 = v[3] - y_offset;
if (cogl_is_offscreen (draw_buffer))
{
entry->y0 = y_offset;
entry->y1 = y_offset + height;
}
else
{
entry->y0 = draw_buffer_height - y_offset - height;
entry->y1 = draw_buffer_height - y_offset;
}
/* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry);
ctx->clip.stack_dirty = TRUE;
clip_state->stack_dirty = TRUE;
}
/* Scale from OpenGL <-1,1> coordinates system to window coordinates
* <0,window-size> with (0,0) being top left. */
#define VIEWPORT_SCALE_X(x, w, width, origin) \
((((((x) / (w)) + 1.0) / 2) * (width)) + (origin))
#define VIEWPORT_SCALE_Y(y, w, height, origin) \
((height) - (((((y) / (w)) + 1.0) / 2) * (height)) + (origin))
/* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
* to Cogl window/draw-buffer coordinates (ranging from 0 to buffer-size) with
* (0,0) being top left. */
#define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \
( ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x) )
/* Note: for Y we first flip all coordinates around the X axis while in
* normalized device coodinates */
#define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \
( ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y) )
/* Transform a homogeneous vertex position from model space to Cogl
* window coordinates (with 0,0 being top left) */
static void
transform_point (CoglMatrix *matrix_mv,
CoglMatrix *matrix_p,
@ -162,14 +197,19 @@ transform_point (CoglMatrix *matrix_mv,
float z = 0;
float w = 1;
/* Apply the model view matrix */
/* Apply the modelview matrix transform */
cogl_matrix_transform_point (matrix_mv, x, y, &z, &w);
/* Apply the projection matrix */
/* Apply the projection matrix transform */
cogl_matrix_transform_point (matrix_p, x, y, &z, &w);
/* Perform perspective division */
*x /= w;
*y /= w;
/* Apply viewport transform */
*x = VIEWPORT_SCALE_X (*x, w, viewport[2], viewport[0]);
*y = VIEWPORT_SCALE_Y (*y, w, viewport[3], viewport[1]);
*x = VIEWPORT_TRANSFORM_X (*x, viewport[0], viewport[2]);
*y = VIEWPORT_TRANSFORM_Y (*y, viewport[1], viewport[3]);
}
#undef VIEWPORT_SCALE_X
@ -193,6 +233,15 @@ try_pushing_rect_as_window_rect (float x_offset,
cogl_get_modelview_matrix (&matrix);
/* If the modelview meets these constraints then a transformed rectangle
* should still be a rectangle when it reaches screen coordinates.
*
* FIXME: we are are making certain assumptions about the projection
* matrix a.t.m and should really be looking at the combined modelview
* and projection matrix.
* FIXME: we don't consider rotations that are a multiple of 90 degrees
* which could be quite common.
*/
if (matrix.xy != 0 || matrix.xz != 0 ||
matrix.yx != 0 || matrix.yz != 0 ||
matrix.zx != 0 || matrix.zy != 0)
@ -204,6 +253,15 @@ try_pushing_rect_as_window_rect (float x_offset,
transform_point (&matrix, &matrix_p, v, &_x0, &_y0);
transform_point (&matrix, &matrix_p, v, &_x1, &_y1);
/* Consider that the modelview matrix may flip the rectangle
* along the x or y axis... */
#define SWAP(A,B) do { float tmp = B; B = A; A = tmp; } while (0)
if (_x0 > _x1)
SWAP (_x0, _x1);
if (_y0 > _y1)
SWAP (_y0, _y1);
#undef SWAP
cogl_clip_push_window_rect (_x0, _y0, _x1 - _x0, _y1 - _y0);
return TRUE;
}
@ -214,17 +272,26 @@ cogl_clip_push (float x_offset,
float width,
float height)
{
CoglClipStackEntryRect *entry;
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack;
CoglClipStackEntryRect *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
/* Try and catch window space rectangles so we can redirect to
* cogl_clip_push_window_rect which will use scissoring. */
if (try_pushing_rect_as_window_rect (x_offset, y_offset, width, height))
return;
stack = (CoglClipStack *) ctx->clip.stacks->data;
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
stack = clip_state->stacks->data;
entry = g_slice_new (CoglClipStackEntryRect);
@ -240,18 +307,27 @@ cogl_clip_push (float x_offset,
/* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry);
ctx->clip.stack_dirty = TRUE;
clip_state->stack_dirty = TRUE;
}
void
cogl_clip_push_from_path_preserve (void)
{
CoglClipStackEntryPath *entry;
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
CoglClipStack *stack;
CoglClipStackEntryPath *entry;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
stack = (CoglClipStack *) ctx->clip.stacks->data;
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
stack = clip_state->stacks->data;
entry = g_malloc (sizeof (CoglClipStackEntryPath)
+ sizeof (CoglPathNode) * (ctx->path_nodes->len - 1));
@ -268,7 +344,7 @@ cogl_clip_push_from_path_preserve (void)
/* Store it in the stack */
stack->stack_top = g_list_prepend (stack->stack_top, entry);
ctx->clip.stack_dirty = TRUE;
clip_state->stack_dirty = TRUE;
}
void
@ -279,16 +355,18 @@ cogl_clip_push_from_path (void)
cogl_path_new ();
}
void
cogl_clip_pop (void)
static void
_cogl_clip_pop_real (CoglClipStackState *clip_state)
{
gpointer entry;
CoglClipStack *stack;
gpointer entry;
CoglClipStackEntryType type;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
stack = (CoglClipStack *) ctx->clip.stacks->data;
stack = clip_state->stacks->data;
g_return_if_fail (stack->stack_top != NULL);
@ -306,35 +384,57 @@ cogl_clip_pop (void)
stack->stack_top = g_list_delete_link (stack->stack_top,
stack->stack_top);
ctx->clip.stack_dirty = TRUE;
clip_state->stack_dirty = TRUE;
}
void
_cogl_clip_stack_rebuild (void)
cogl_clip_pop (void)
{
int has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
_cogl_clip_pop_real (clip_state);
}
void
_cogl_flush_clip_state (CoglClipStackState *clip_state)
{
CoglClipStack *stack;
int has_clip_planes;
gboolean using_clip_planes = FALSE;
gboolean using_stencil_buffer = FALSE;
GList *node;
CoglClipStack *stack;
gint scissor_x0 = 0;
gint scissor_y0 = 0;
gint scissor_x1 = G_MAXINT;
gint scissor_y1 = G_MAXINT;
CoglMatrixStack *modelview_stack;
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
modelview_stack = ctx->modelview_stack;
if (!clip_state->stack_dirty)
return;
/* The current primitive journal does not support tracking changes to the
* clip stack... */
_cogl_journal_flush ();
stack = (CoglClipStack *) ctx->clip.stacks->data;
/* XXX: the handling of clipping is quite complex. It may involve use of
* the Cogl Journal or other Cogl APIs which may end up recursively
* wanting to ensure the clip state is flushed. We need to ensure we
* don't recurse infinitely...
*/
clip_state->stack_dirty = FALSE;
ctx->clip.stack_dirty = FALSE;
ctx->clip.stencil_used = FALSE;
has_clip_planes = cogl_features_available (COGL_FEATURE_FOUR_CLIP_PLANES);
stack = clip_state->stacks->data;
clip_state->stencil_used = FALSE;
_cogl_disable_clip_planes ();
_cogl_disable_stencil_buffer ();
@ -433,74 +533,111 @@ _cogl_clip_stack_rebuild (void)
scissor_y1 - scissor_y0));
}
ctx->clip.stencil_used = using_stencil_buffer;
clip_state->stencil_used = using_stencil_buffer;
}
/* XXX: This should never have been made public API! */
void
cogl_clip_ensure (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
CoglClipStackState *clip_state;
if (ctx->clip.stack_dirty)
_cogl_clip_stack_rebuild ();
clip_state = _cogl_draw_buffer_get_clip_state (_cogl_get_draw_buffer ());
_cogl_flush_clip_state (clip_state);
}
static void
_cogl_clip_stack_save_real (CoglClipStackState *clip_state)
{
CoglClipStack *stack;
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
stack = g_slice_new (CoglClipStack);
stack->stack_top = NULL;
clip_state->stacks = g_slist_prepend (clip_state->stacks, stack);
clip_state->stack_dirty = TRUE;
}
void
cogl_clip_stack_save (void)
{
CoglClipStack *stack;
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
stack = g_slice_new (CoglClipStack);
stack->stack_top = NULL;
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
ctx->clip.stacks = g_slist_prepend (ctx->clip.stacks, stack);
_cogl_clip_stack_save_real (clip_state);
}
ctx->clip.stack_dirty = TRUE;
static void
_cogl_clip_stack_restore_real (CoglClipStackState *clip_state)
{
CoglClipStack *stack;
g_return_if_fail (clip_state->stacks != NULL);
/* We don't log clip stack changes in the journal so we must flush
* it before making modifications */
_cogl_journal_flush ();
stack = clip_state->stacks->data;
/* Empty the current stack */
while (stack->stack_top)
_cogl_clip_pop_real (clip_state);
/* Revert to an old stack */
g_slice_free (CoglClipStack, stack);
clip_state->stacks = g_slist_delete_link (clip_state->stacks,
clip_state->stacks);
clip_state->stack_dirty = TRUE;
}
void
cogl_clip_stack_restore (void)
{
CoglClipStack *stack;
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (ctx->clip.stacks != NULL);
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
stack = (CoglClipStack *) ctx->clip.stacks->data;
/* Empty the current stack */
while (stack->stack_top)
cogl_clip_pop ();
/* Revert to an old stack */
g_slice_free (CoglClipStack, stack);
ctx->clip.stacks = g_slist_delete_link (ctx->clip.stacks,
ctx->clip.stacks);
ctx->clip.stack_dirty = TRUE;
_cogl_clip_stack_restore_real (clip_state);
}
void
_cogl_clip_stack_state_init (void)
_cogl_clip_stack_state_init (CoglClipStackState *clip_state)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
ctx->clip.stacks = NULL;
ctx->clip.stack_dirty = TRUE;
clip_state->stacks = NULL;
clip_state->stack_dirty = TRUE;
/* Add an intial stack */
cogl_clip_stack_save ();
_cogl_clip_stack_save_real (clip_state);
}
void
_cogl_clip_stack_state_destroy (void)
_cogl_clip_stack_state_destroy (CoglClipStackState *clip_state)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Destroy all of the stacks */
while (ctx->clip.stacks)
cogl_clip_stack_restore ();
while (clip_state->stacks)
_cogl_clip_stack_restore_real (clip_state);
}
void
_cogl_clip_stack_state_dirty (CoglClipStackState *clip_state)
{
clip_state->stack_dirty = TRUE;
}

View File

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

View File

@ -32,6 +32,7 @@
#include "cogl-journal-private.h"
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h>
@ -46,7 +47,7 @@ cogl_create_context (void)
{
GLubyte default_texture_data[] = { 0xff, 0xff, 0xff, 0x0 };
gulong enable_flags = 0;
CoglDrawBufferState *draw_buffer;
CoglHandle window_buffer;
if (_context != NULL)
return FALSE;
@ -58,16 +59,24 @@ cogl_create_context (void)
_context->feature_flags = 0;
_context->features_cached = FALSE;
/* Initialise the driver specific state */
/* TODO: combine these two into one function */
_cogl_create_context_driver (_context);
_cogl_features_init ();
_context->enable_flags = 0;
_context->color_alpha = 0;
_context->enable_backface_culling = FALSE;
_context->flushed_front_winding = COGL_FRONT_WINDING_COUNTER_CLOCKWISE;
_context->indirect = gl_is_indirect;
cogl_matrix_init_identity (&_context->identity_matrix);
cogl_matrix_init_identity (&_context->y_flip_matrix);
cogl_matrix_scale (&_context->y_flip_matrix, 1, -1, 1);
_context->flushed_matrix_mode = COGL_MATRIX_MODELVIEW;
_context->modelview_stack = _cogl_matrix_stack_new ();
_context->projection_stack = _cogl_matrix_stack_new ();
_context->texture_units = NULL;
_context->default_material = cogl_material_new ();
@ -87,11 +96,14 @@ cogl_create_context (void)
sizeof (CoglLayerInfo));
_context->n_texcoord_arrays_enabled = 0;
draw_buffer = g_slice_new0 (CoglDrawBufferState);
draw_buffer->target = COGL_WINDOW_BUFFER;
draw_buffer->offscreen = COGL_INVALID_HANDLE;
_context->draw_buffer_stack =
g_slist_prepend (NULL, draw_buffer);
_context->draw_buffer_stack = _cogl_create_draw_buffer_stack ();
window_buffer = _cogl_onscreen_new ();
/* XXX: When setting up the window buffer, cogl_set_draw_buffer
* assumes that the handle can be found in ctx->window_buffer */
_context->window_buffer = window_buffer;
cogl_set_draw_buffer (COGL_WINDOW_BUFFER, 0/* ignored */);
_context->dirty_bound_framebuffer = TRUE;
_context->dirty_gl_viewport = TRUE;
_context->path_nodes = g_array_new (FALSE, FALSE, sizeof (CoglPathNode));
_context->last_path = 0;
@ -99,21 +111,12 @@ cogl_create_context (void)
_context->in_begin_gl_block = FALSE;
_context->viewport_width = 0;
_context->viewport_height = 0;
_context->quad_indices_byte = COGL_INVALID_HANDLE;
_context->quad_indices_short = COGL_INVALID_HANDLE;
_context->quad_indices_short_len = 0;
_context->texture_download_material = COGL_INVALID_HANDLE;
/* Initialise the clip stack */
_cogl_clip_stack_state_init ();
/* Initialise the driver specific state */
_cogl_create_context_driver (_context);
/* Create default textures used for fall backs */
_context->default_gl_texture_2d_tex =
cogl_texture_new_from_data (1, /* width */
@ -139,6 +142,7 @@ cogl_create_context (void)
enable_flags =
_cogl_material_get_cogl_enable_flags (_context->source_material);
cogl_enable (enable_flags);
_cogl_flush_face_winding ();
return TRUE;
}
@ -146,16 +150,14 @@ cogl_create_context (void)
void
_cogl_destroy_context ()
{
if (_context == NULL)
return;
_cogl_clip_stack_state_destroy ();
_cogl_matrix_stack_destroy (_context->modelview_stack);
_cogl_matrix_stack_destroy (_context->projection_stack);
_cogl_destroy_texture_units ();
_cogl_free_draw_buffer_stack (_context->draw_buffer_stack);
if (_context->path_nodes)
g_array_free (_context->path_nodes, TRUE);

View File

@ -38,12 +38,6 @@ typedef struct
GLubyte c[4];
} CoglTextureGLVertex;
typedef struct
{
CoglBufferTarget target;
CoglHandle offscreen;
} CoglDrawBufferState;
typedef struct
{
/* Features cache */
@ -55,19 +49,18 @@ typedef struct
guint8 color_alpha;
gboolean enable_backface_culling;
CoglFrontWinding flushed_front_winding;
gboolean indirect;
/* A few handy matrix constants */
CoglMatrix identity_matrix;
CoglMatrix y_flip_matrix;
/* Client-side matrix stack or NULL if none */
CoglMatrixMode flushed_matrix_mode;
CoglMatrixStack *projection_stack;
CoglMatrixStack *modelview_stack;
GList *texture_units;
/* Cache of inverse projection matrix */
float inverse_projection[16];
/* Materials */
CoglHandle default_material;
CoglHandle source_material;
@ -91,11 +84,11 @@ typedef struct
GArray *current_layers;
guint n_texcoord_arrays_enabled;
/* Framebuffer objects */
/* Draw Buffers */
GSList *draw_buffer_stack;
/* Clip stack */
CoglClipStackState clip;
CoglHandle window_buffer;
gboolean dirty_bound_framebuffer;
gboolean dirty_gl_viewport;
/* Primitives */
floatVec2 path_start;
@ -114,9 +107,6 @@ typedef struct
gboolean in_begin_gl_block;
guint viewport_width;
guint viewport_height;
CoglHandle texture_download_material;
CoglContextDriver drv;

View File

@ -46,7 +46,8 @@ static const GDebugKey cogl_debug_keys[] = {
{ "disable-vbos", COGL_DEBUG_DISABLE_VBOS },
{ "journal", COGL_DEBUG_JOURNAL },
{ "batching", COGL_DEBUG_BATCHING },
{ "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM }
{ "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM },
{ "matrices", COGL_DEBUG_MATRICES }
};
static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys);

View File

@ -44,7 +44,8 @@ typedef enum {
COGL_DEBUG_DISABLE_VBOS = 1 << 12,
COGL_DEBUG_JOURNAL = 1 << 13,
COGL_DEBUG_BATCHING = 1 << 14,
COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM = 1 << 15
COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM = 1 << 15,
COGL_DEBUG_MATRICES = 1 << 16
} CoglDebugFlags;
#ifdef COGL_ENABLE_DEBUG

View File

@ -0,0 +1,133 @@
/*
* 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);
int
_cogl_draw_buffer_get_width (CoglHandle handle);
int
_cogl_draw_buffer_get_height (CoglHandle handle);
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);
gboolean
cogl_is_offscreen (CoglHandle handle);
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 */

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

@ -0,0 +1,602 @@
/*
* 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;
}
int
_cogl_draw_buffer_get_width (CoglHandle handle)
{
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
return draw_buffer->width;
}
int
_cogl_draw_buffer_get_height (CoglHandle handle)
{
CoglDrawBuffer *draw_buffer = COGL_DRAW_BUFFER (handle);
return draw_buffer->height;
}
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_gl_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);
}
void
_cogl_onscreen_clutter_backend_set_size (int width, int height)
{
CoglDrawBuffer *draw_buffer;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
draw_buffer = COGL_DRAW_BUFFER (ctx->window_buffer);
if (draw_buffer->width == width && draw_buffer->height == height)
return;
draw_buffer->width = width;
draw_buffer->height = height;
/* We'll need to recalculate the GL viewport state derived
* from the Cogl viewport */
ctx->dirty_gl_viewport = 1;
}
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_gl_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_gl_viewport)
{
int gl_viewport_y;
/* Convert the Cogl viewport y offset to an OpenGL viewport y offset
* NB: OpenGL defines its window and viewport origins to be bottom
* left, while Cogl defines them to be top left.
* NB: We render upside down to offscreen draw buffers so we don't
* need to convert the y offset in this case. */
if (cogl_is_offscreen (draw_buffer))
gl_viewport_y = draw_buffer->viewport_y;
else
gl_viewport_y = draw_buffer->height -
(draw_buffer->viewport_y + draw_buffer->viewport_height);
GE (glViewport (draw_buffer->viewport_x,
gl_viewport_y,
draw_buffer->viewport_width,
draw_buffer->viewport_height));
ctx->dirty_gl_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

@ -34,6 +34,12 @@ typedef enum
COGL_MATRIX_TEXTURE
} CoglMatrixMode;
typedef enum
{
COGL_FRONT_WINDING_CLOCKWISE,
COGL_FRONT_WINDING_COUNTER_CLOCKWISE
} CoglFrontWinding;
#ifdef HAVE_COGL_GLES2
typedef enum {
COGL_BOXED_NONE,
@ -105,4 +111,7 @@ _cogl_destroy_texture_units (void);
void _cogl_flush_matrix_stacks (void);
void
_cogl_flush_face_winding (void);
#endif /* __COGL_INTERNAL_H */

View File

@ -32,6 +32,7 @@
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#include "cogl-vertex-buffer-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h>
#include <gmodule.h>
@ -301,6 +302,7 @@ _cogl_journal_flush_material_and_entries (CoglJournalEntry *batch_start,
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
enable_flags |= COGL_ENABLE_COLOR_ARRAY;
cogl_enable (enable_flags);
_cogl_flush_face_winding ();
/* If we haven't transformed the quads in software then we need to also break
* up batches according to changes in the modelview matrix... */
@ -531,6 +533,8 @@ _cogl_journal_flush (void)
GLuint journal_vbo;
gboolean vbo_fallback =
(cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
CoglHandle draw_buffer;
CoglMatrixStack *modelview_stack;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -547,20 +551,19 @@ _cogl_journal_flush (void)
else
state.vbo_offset = (char *)ctx->logged_vertices->data;
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
COGL_MATRIX_PROJECTION);
draw_buffer = _cogl_get_draw_buffer ();
modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer);
state.modelview_stack = modelview_stack;
state.modelview_stack = ctx->modelview_stack;
_cogl_matrix_stack_push (ctx->modelview_stack);
_cogl_matrix_stack_push (modelview_stack);
/* If we have transformed all our quads at log time then we ensure no
* further model transform is applied by loading the identity matrix
* here... */
if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack,
COGL_MATRIX_MODELVIEW);
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
}
/* batch_and_call() batches a list of journal entries according to some
@ -591,7 +594,7 @@ _cogl_journal_flush (void)
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
&state); /* data */
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (modelview_stack);
for (i = 0; i < ctx->journal->len; i++)
{
@ -607,6 +610,18 @@ _cogl_journal_flush (void)
g_array_set_size (ctx->logged_vertices, 0);
}
static void
_cogl_journal_init (void)
{
/* Here we flush anything that we know must remain constant until the
* next the the journal is flushed. Note: This lets up flush things
* that themselves depend on the journal, such as clip state. */
/* NB: the journal deals with flushing the modelview stack manually */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (),
COGL_DRAW_BUFFER_FLUSH_SKIP_MODELVIEW);
}
void
_cogl_journal_log_quad (float x_1,
float y_1,
@ -632,6 +647,9 @@ _cogl_journal_log_quad (float x_1,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->logged_vertices->len == 0)
_cogl_journal_init ();
/* The vertex data is logged into a separate array in a layout that can be
* directly passed to OpenGL
*/

1698
cogl/cogl-matrix-mesa.c Normal file

File diff suppressed because it is too large Load Diff

226
cogl/cogl-matrix-mesa.h Normal file
View File

@ -0,0 +1,226 @@
/*
* Cogl
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 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.
*/
/*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* \file math/m_matrix.h
* Defines basic structures for matrix-handling.
*/
#ifndef _M_MATRIX_H
#define _M_MATRIX_H
#include <cogl-matrix.h>
#include <glib.h>
/**
* \name Symbolic names to some of the entries in the matrix
*
* These are handy for the viewport mapping, which is expressed as a matrix.
*/
/*@{*/
#define MAT_SX 0
#define MAT_SY 5
#define MAT_SZ 10
#define MAT_TX 12
#define MAT_TY 13
#define MAT_TZ 14
/*@}*/
/**
* Different kinds of 4x4 transformation matrices.
* We use these to select specific optimized vertex transformation routines.
*/
enum CoglMatrixType {
COGL_MATRIX_TYPE_GENERAL, /**< general 4x4 matrix */
COGL_MATRIX_TYPE_IDENTITY, /**< identity matrix */
COGL_MATRIX_TYPE_3D_NO_ROT, /**< orthogonal projection and others... */
COGL_MATRIX_TYPE_PERSPECTIVE, /**< perspective projection matrix */
COGL_MATRIX_TYPE_2D, /**< 2-D transformation */
COGL_MATRIX_TYPE_2D_NO_ROT, /**< 2-D scale & translate only */
COGL_MATRIX_TYPE_3D /**< 3-D transformation */
} ;
#if 0
/**
* Matrix type to represent 4x4 transformation matrices.
*/
typedef struct {
float *m; /**< 16 matrix elements (16-byte aligned) */
float *inv; /**< optional 16-element inverse (16-byte aligned) */
unsigned int flags; /**< possible values determined by (of \link
* MatFlags MAT_FLAG_* flags\endlink)
*/
enum CoglMatrixType type;
} CoglMatrix;
#endif
void
_math_matrix_multiply (CoglMatrix *result,
const CoglMatrix *a,
const CoglMatrix *b);
void
_math_matrix_multiply_array (CoglMatrix *result, const float *b);
void
_math_matrix_init_from_array (CoglMatrix *matrix, const float *array);
void
_math_matrix_translate (CoglMatrix *matrix, float x, float y, float z);
void
_math_matrix_rotate (CoglMatrix *matrix, float angle,
float x, float y, float z);
void
_math_matrix_scale (CoglMatrix *matrix, float x, float y, float z);
void
_math_matrix_ortho (CoglMatrix *matrix,
float left, float right,
float bottom, float top,
float nearval, float farval);
void
_math_matrix_frustum (CoglMatrix *matrix,
float left, float right,
float bottom, float top,
float nearval, float farval);
void
_math_matrix_viewport (CoglMatrix *matrix,
int x, int y, int width, int height,
float z_near, float z_far, float depth_max);
void
_math_matrix_init_identity (CoglMatrix *matrix);
gboolean
_math_matrix_update_inverse (CoglMatrix *matrix);
void
_math_matrix_update_type_and_flags (CoglMatrix *matrix);
void
_math_matrix_print (const CoglMatrix *matrix);
gboolean
_math_matrix_is_length_preserving (const CoglMatrix *matrix);
gboolean
_math_matrix_has_rotation (const CoglMatrix *matrix);
gboolean
_math_matrix_is_general_scale (const CoglMatrix *matrix);
gboolean
_math_matrix_is_dirty (const CoglMatrix *matrix);
/**
* \name Related functions that don't actually operate on CoglMatrix structs
*/
/*@{*/
void
_math_transposef ( float to[16], const float from[16]);
void
_math_transposed (double to[16], const double from[16]);
void
_math_transposefd (float to[16], const double from[16]);
/*
* Transform a point (column vector) by a matrix: Q = M * P
*/
#define TRANSFORM_POINT( Q, M, P ) \
Q[0] = M[0] * P[0] + M[4] * P[1] + M[8] * P[2] + M[12] * P[3]; \
Q[1] = M[1] * P[0] + M[5] * P[1] + M[9] * P[2] + M[13] * P[3]; \
Q[2] = M[2] * P[0] + M[6] * P[1] + M[10] * P[2] + M[14] * P[3]; \
Q[3] = M[3] * P[0] + M[7] * P[1] + M[11] * P[2] + M[15] * P[3];
#define TRANSFORM_POINT3( Q, M, P ) \
Q[0] = M[0] * P[0] + M[4] * P[1] + M[8] * P[2] + M[12]; \
Q[1] = M[1] * P[0] + M[5] * P[1] + M[9] * P[2] + M[13]; \
Q[2] = M[2] * P[0] + M[6] * P[1] + M[10] * P[2] + M[14]; \
Q[3] = M[3] * P[0] + M[7] * P[1] + M[11] * P[2] + M[15];
/*
* Transform a normal (row vector) by a matrix: [NX NY NZ] = N * MAT
*/
#define TRANSFORM_NORMAL( TO, N, MAT ) \
do { \
TO[0] = N[0] * MAT[0] + N[1] * MAT[1] + N[2] * MAT[2]; \
TO[1] = N[0] * MAT[4] + N[1] * MAT[5] + N[2] * MAT[6]; \
TO[2] = N[0] * MAT[8] + N[1] * MAT[9] + N[2] * MAT[10]; \
} while (0)
/**
* Transform a direction by a matrix.
*/
#define TRANSFORM_DIRECTION( TO, DIR, MAT ) \
do { \
TO[0] = DIR[0] * MAT[0] + DIR[1] * MAT[4] + DIR[2] * MAT[8]; \
TO[1] = DIR[0] * MAT[1] + DIR[1] * MAT[5] + DIR[2] * MAT[9]; \
TO[2] = DIR[0] * MAT[2] + DIR[1] * MAT[6] + DIR[2] * MAT[10];\
} while (0)
void
_mesa_transform_vector (float u[4], const float v[4], const float m[16]);
/*@}*/
#endif

View File

@ -3,7 +3,7 @@
*
* An object oriented GL/GLES Abstraction/Utility Layer
*
* Copyright (C) 2007,2008,2009 Intel Corporation.
* 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
@ -19,21 +19,29 @@
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*
* Authors:
* Robert Bragg <robert@linux.intel.com>
*/
#ifndef __COGL_FBO_H
#define __COGL_FBO_H
#ifndef __COGL_MATRIX_PRIVATE_H
#define __COGL_MATRIX_PRIVATE_H
#include "cogl-handle.h"
#include <glib.h>
typedef struct
{
CoglHandleObject _parent;
int width;
int height;
GLuint gl_handle;
GLuint gl_stencil_handle;
G_BEGIN_DECLS
} CoglFbo;
#define _COGL_MATRIX_DEBUG_PRINT(MATRIX) \
if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_MATRICES)) \
{ \
g_print ("%s:\n", G_STRFUNC); \
_cogl_matrix_print (MATRIX); \
}
void
_cogl_matrix_print (CoglMatrix *matrix);
G_END_DECLS
#endif /* __COGL_MATRIX_PRIVATE_H */
#endif /* __COGL_FBO_H */

View File

@ -22,6 +22,7 @@
*
* Authors:
* Havoc Pennington <hp@pobox.com> for litl
* Robert Bragg <robert@linux.intel.com>
*/
#ifdef HAVE_CONFIG_H
@ -32,6 +33,7 @@
#include "cogl-context.h"
#include "cogl-internal.h"
#include "cogl-matrix-stack.h"
#include "cogl-draw-buffer-private.h"
typedef struct {
CoglMatrix matrix;
@ -346,6 +348,17 @@ _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
state->is_identity = FALSE;
}
gboolean
_cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
CoglMatrix *inverse)
{
CoglMatrixState *state;
state = _cogl_matrix_stack_top_mutable (stack, TRUE);
return cogl_matrix_get_inverse (&state->matrix, inverse);
}
void
_cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix)
@ -412,21 +425,35 @@ _cogl_matrix_stack_flush_to_gl (CoglMatrixStack *stack,
ctx->flushed_matrix_mode = mode;
}
/* In theory it might help the GL implementation if we used our
* local analysis of the matrix and called Translate/Scale rather
* than LoadMatrix to send a 2D matrix
/* Because Cogl defines texture coordinates to have a top left origin and
* because offscreen draw buffers may be used for rendering to textures we
* always render upside down to offscreen buffers.
*/
if (state->is_identity)
if (mode == COGL_MATRIX_PROJECTION &&
cogl_is_offscreen (_cogl_get_draw_buffer ()))
{
if (!stack->flushed_identity)
GE (glLoadIdentity ());
stack->flushed_identity = TRUE;
CoglMatrix flipped_projection;
CoglMatrix *projection =
state->is_identity ? &ctx->identity_matrix : &state->matrix;
cogl_matrix_multiply (&flipped_projection,
&ctx->y_flip_matrix, projection);
GE (glLoadMatrixf (cogl_matrix_get_array (&flipped_projection)));
stack->flushed_identity = FALSE;
}
else
{
GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix)));
stack->flushed_identity = FALSE;
if (state->is_identity)
{
if (!stack->flushed_identity)
GE (glLoadIdentity ());
stack->flushed_identity = TRUE;
}
else
{
GE (glLoadMatrixf (cogl_matrix_get_array (&state->matrix)));
stack->flushed_identity = FALSE;
}
}
stack->flushed_state = state;
}

View File

@ -71,6 +71,9 @@ void _cogl_matrix_stack_ortho (CoglMatrixStack *stack,
float top,
float z_near,
float z_far);
gboolean _cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
CoglMatrix *inverse);
void _cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix);
void _cogl_matrix_stack_set (CoglMatrixStack *stack,

View File

@ -24,20 +24,41 @@
* Robert Bragg <robert@linux.intel.com>
*/
#define USE_MESA_MATRIX_API
#include <cogl.h>
#include <cogl-matrix.h>
#include <cogl-matrix-private.h>
#ifdef USE_MESA_MATRIX_API
#include <cogl-matrix-mesa.h>
#endif
#include <glib.h>
#include <math.h>
#include <string.h>
void
_cogl_matrix_print (CoglMatrix *matrix)
{
float *m = (float *)matrix;
int y;
for (y = 0; y < 4; y++)
g_print ("\t%6.4f %6.4f %6.4f %6.4f\n", m[y], m[4+y], m[8+y], m[12+y]);
}
void
cogl_matrix_init_identity (CoglMatrix *matrix)
{
#ifndef USE_MESA_MATRIX_API
matrix->xx = 1; matrix->xy = 0; matrix->xz = 0; matrix->xw = 0;
matrix->yx = 0; matrix->yy = 1; matrix->yz = 0; matrix->yw = 0;
matrix->zx = 0; matrix->zy = 0; matrix->zz = 1; matrix->zw = 0;
matrix->wx = 0; matrix->wy = 0; matrix->wz = 0; matrix->ww = 1;
#else
_math_matrix_init_identity (matrix);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
@ -45,6 +66,7 @@ cogl_matrix_multiply (CoglMatrix *result,
const CoglMatrix *a,
const CoglMatrix *b)
{
#ifndef USE_MESA_MATRIX_API
CoglMatrix r;
/* row 0 */
@ -73,10 +95,14 @@ cogl_matrix_multiply (CoglMatrix *result,
/* The idea was that having this unrolled; it might be easier for the
* compiler to vectorize, but that's probably not true. Mesa does it
* using a single for (i=0; i<4; i++) approach, may that's better...
* using a single for (i=0; i<4; i++) approach, maybe that's better...
*/
*result = r;
#else
_math_matrix_multiply (result, a, b);
#endif
_COGL_MATRIX_DEBUG_PRINT (result);
}
void
@ -86,6 +112,7 @@ cogl_matrix_rotate (CoglMatrix *matrix,
float y,
float z)
{
#ifndef USE_MESA_MATRIX_API
CoglMatrix rotation;
CoglMatrix result;
float c, s;
@ -116,6 +143,10 @@ cogl_matrix_rotate (CoglMatrix *matrix,
cogl_matrix_multiply (&result, matrix, &rotation);
*matrix = result;
#else
_math_matrix_rotate (matrix, angle, x, y, z);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
@ -124,10 +155,15 @@ cogl_matrix_translate (CoglMatrix *matrix,
float y,
float z)
{
#ifndef USE_MESA_MATRIX_API
matrix->xw = matrix->xx * x + matrix->xy * y + matrix->xz * z + matrix->xw;
matrix->yw = matrix->yx * x + matrix->yy * y + matrix->yz * z + matrix->yw;
matrix->zw = matrix->zx * x + matrix->zy * y + matrix->zz * z + matrix->zw;
matrix->ww = matrix->wx * x + matrix->wy * y + matrix->wz * z + matrix->ww;
#else
_math_matrix_translate (matrix, x, y, z);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
@ -136,23 +172,16 @@ cogl_matrix_scale (CoglMatrix *matrix,
float sy,
float sz)
{
#ifndef USE_MESA_MATRIX_API
matrix->xx *= sx; matrix->xy *= sy; matrix->xz *= sz;
matrix->yx *= sx; matrix->yy *= sy; matrix->yz *= sz;
matrix->zx *= sx; matrix->zy *= sy; matrix->zz *= sz;
matrix->wx *= sx; matrix->wy *= sy; matrix->wz *= sz;
}
#if 0
gboolean
cogl_matrix_invert (CoglMatrix *matrix)
{
/* TODO */
/* Note: It might be nice to also use the flag based tricks that mesa does
* to alow it to track the type of transformations a matrix represents
* so it can use various assumptions to optimise the inversion.
*/
}
#else
_math_matrix_scale (matrix, sx, sy, sz);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
cogl_matrix_frustum (CoglMatrix *matrix,
@ -163,6 +192,7 @@ cogl_matrix_frustum (CoglMatrix *matrix,
float z_near,
float z_far)
{
#ifndef USE_MESA_MATRIX_API
float x, y, a, b, c, d;
CoglMatrix frustum;
@ -194,6 +224,10 @@ cogl_matrix_frustum (CoglMatrix *matrix,
frustum.ww = 0.0f;
cogl_matrix_multiply (matrix, matrix, &frustum);
#else
_math_matrix_frustum (matrix, left, right, bottom, top, z_near, z_far);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
@ -212,6 +246,7 @@ cogl_matrix_perspective (CoglMatrix *matrix,
ymax, /* top */
z_near,
z_far);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
@ -223,6 +258,7 @@ cogl_matrix_ortho (CoglMatrix *matrix,
float near_val,
float far_val)
{
#ifndef USE_MESA_MATRIX_API
CoglMatrix ortho;
/* column 0 */
@ -250,12 +286,21 @@ cogl_matrix_ortho (CoglMatrix *matrix,
ortho.ww = 1.0;
cogl_matrix_multiply (matrix, matrix, &ortho);
#else
_math_matrix_ortho (matrix, left, right, bottom, top, near_val, far_val);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
{
#ifndef USE_MESA_MATRIX_API
memcpy (matrix, array, sizeof (float) * 16);
#else
_math_matrix_init_from_array (matrix, array);
#endif
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
const float *
@ -264,6 +309,27 @@ cogl_matrix_get_array (const CoglMatrix *matrix)
return (float *)matrix;
}
gboolean
cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse)
{
#ifndef USE_MESA_MATRIX_API
#warning "cogl_matrix_get_inverse not supported without Mesa matrix API"
cogl_matrix_init_identity (inverse);
return FALSE;
#else
if (_math_matrix_update_inverse ((CoglMatrix *)matrix))
{
cogl_matrix_init_from_array (inverse, matrix->inv);
return TRUE;
}
else
{
cogl_matrix_init_identity (inverse);
return FALSE;
}
#endif
}
void
cogl_matrix_transform_point (const CoglMatrix *matrix,
float *x,

View File

@ -101,9 +101,9 @@ struct _CoglMatrix
/* Note: we may want to extend this later with private flags
* and a cache of the inverse transform matrix. */
float _padding0[16];
gulong _padding1;
gulong _padding2;
float inv[16];
gulong type;
gulong flags;
gulong _padding3;
};
@ -266,6 +266,27 @@ void cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array);
*/
G_CONST_RETURN float *cogl_matrix_get_array (const CoglMatrix *matrix);
/**
* cogl_matrix_get_inverse:
* @matrix: A 4x4 transformation matrix
* @inverse: The destination for a 4x4 inverse transformation matrix
*
* This gets the inverse transform of a given matrix and uses it to initialize
* a new CoglMatrix.
*
* Note: that although the first parameter is annotated as const to indicate
* that the transform it represents isn't modified this function may
* technically save a copy of the inverse transform within the given CoglMatrix
* so that subsequent requests for the inverse transform may avoid costly
* inversion calculations.
*
* Returns TRUE if the inverse was successfully calculated or FALSE for
* degenerate transformations that can't be inverted (in this case the matrix
* will simply be initialized with the identity matrix)
*/
gboolean
cogl_matrix_get_inverse (const CoglMatrix *matrix, CoglMatrix *inverse);
/**
* cogl_matrix_transform_point:
* @matrix: A 4x4 transformation matrix

View File

@ -32,6 +32,7 @@
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#include "cogl-vertex-buffer-private.h"
#include "cogl-draw-buffer-private.h"
#include <string.h>
#include <math.h>
@ -396,8 +397,6 @@ _cogl_rectangles_with_multitexture_coords (
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_clip_ensure ();
material = ctx->source_material;
layers = cogl_material_get_layers (material);
@ -706,7 +705,6 @@ draw_polygon_sub_texture_cb (CoglHandle tex_handle,
options.layer0_override_texture = gl_handle;
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, state->n_vertices));
}
@ -840,7 +838,6 @@ _cogl_multitexture_polygon_single_primitive (CoglTextureVertex *vertices,
options.flags |= COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
options.fallback_layers = fallback_layers;
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
GE (glDrawArrays (GL_TRIANGLE_FAN, 0, n_vertices));
}
@ -866,7 +863,11 @@ cogl_polygon (CoglTextureVertex *vertices,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
material = ctx->source_material;
layers = cogl_material_get_layers (ctx->source_material);
@ -978,6 +979,7 @@ cogl_polygon (CoglTextureVertex *vertices,
}
cogl_enable (enable_flags);
_cogl_flush_face_winding ();
GE (glVertexPointer (3, GL_FLOAT, stride_bytes, v));
@ -1030,9 +1032,6 @@ cogl_path_fill_preserve (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
cogl_clip_ensure ();
if (ctx->path_nodes->len == 0)
return;
@ -1055,10 +1054,7 @@ cogl_path_stroke_preserve (void)
if (ctx->path_nodes->len == 0)
return;
_cogl_journal_flush ();
cogl_clip_ensure ();
_cogl_path_stroke_nodes();
_cogl_path_stroke_nodes ();
}
void

View File

@ -907,7 +907,7 @@ _cogl_texture_2d_sliced_new_with_size (unsigned int width,
/* Since no data, we need some internal format */
if (internal_format == COGL_PIXEL_FORMAT_ANY)
return COGL_INVALID_HANDLE;
internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
/* Rowstride from width */
bpp = _cogl_get_format_bpp (internal_format);

View File

@ -42,6 +42,7 @@
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-primitives.h"
#include "cogl-draw-buffer-private.h"
#include <string.h>
#include <stdlib.h>
@ -667,7 +668,8 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
GLuint target_gl_type)
{
gint bpp;
GLint viewport[4];
CoglHandle draw_buffer;
int viewport[4];
CoglBitmap alpha_bmp;
CoglHandle prev_source;
CoglMatrixStack *projection_stack;
@ -677,8 +679,9 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
bpp = _cogl_get_format_bpp (COGL_PIXEL_FORMAT_RGBA_8888);
draw_buffer = _cogl_get_draw_buffer ();
/* Viewport needs to have some size and be inside the window for this */
GE( glGetIntegerv (GL_VIEWPORT, viewport));
_cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport);
if (viewport[0] < 0 || viewport[1] < 0 ||
viewport[2] <= 0 || viewport[3] <= 0)
return FALSE;
@ -688,16 +691,18 @@ _cogl_texture_draw_and_read (CoglTexture *tex,
* works)
*/
_cogl_matrix_stack_push (ctx->projection_stack);
_cogl_matrix_stack_load_identity (ctx->projection_stack);
_cogl_matrix_stack_ortho (ctx->projection_stack,
projection_stack = _cogl_draw_buffer_get_projection_stack (draw_buffer);
_cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_ortho (projection_stack,
0, (float)(viewport[2]),
0, (float)(viewport[3]),
(float)(0),
(float)(100));
_cogl_matrix_stack_push (ctx->modelview_stack);
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
modelview_stack = _cogl_draw_buffer_get_modelview_stack (draw_buffer);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
/* Direct copy operation */

View File

@ -138,6 +138,7 @@
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#include "cogl-primitives.h"
#include "cogl-draw-buffer-private.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@ -1664,6 +1665,11 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
}
ctx->n_texcoord_arrays_enabled = max_texcoord_attrib_unit + 1;
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
options.flags =
COGL_MATERIAL_FLUSH_FALLBACK_MASK |
COGL_MATERIAL_FLUSH_DISABLE_MASK;
@ -1677,6 +1683,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags);
_cogl_flush_face_winding ();
}
static void
@ -1753,15 +1760,11 @@ cogl_vertex_buffer_draw (CoglHandle handle,
return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure ();
_cogl_flush_matrix_stacks ();
enable_state_for_drawing_buffer (buffer);
/* FIXME: flush cogl cache */
GE (glDrawArrays (mode, first, count));
disable_state_for_drawing_buffer (buffer);
@ -1885,7 +1888,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
@ -1894,8 +1896,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
cogl_clip_ensure ();
_cogl_flush_matrix_stacks ();
enable_state_for_drawing_buffer (buffer);
byte_offset = indices_offset * get_indices_type_size (indices->type);
@ -1905,7 +1905,6 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
GPOINTER_TO_UINT (indices->vbo_name)));
/* FIXME: flush cogl cache */
GE (glDrawRangeElements (mode, min_index, max_index,
count, indices->type, (void *)byte_offset));

View File

@ -38,6 +38,8 @@
#include "cogl-context.h"
#include "cogl-material-private.h"
#include "cogl-winsys.h"
#include "cogl-draw-buffer-private.h"
#include "cogl-matrix-private.h"
#if defined (HAVE_COGL_GLES2) || defined (HAVE_COGL_GLES)
#include "cogl-gles2-wrapper.h"
@ -116,7 +118,12 @@ cogl_clear (const CoglColor *color, gulong buffers)
COGL_NOTE (DRAW, "Clear begin");
cogl_clip_ensure ();
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
if (buffers & COGL_BUFFER_BIT_COLOR)
{
@ -264,6 +271,9 @@ cogl_set_backface_culling_enabled (gboolean setting)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->enable_backface_culling == setting)
return;
/* Currently the journal can't track changes to backface culling state... */
_cogl_journal_flush ();
@ -278,6 +288,38 @@ cogl_get_backface_culling_enabled (void)
return ctx->enable_backface_culling;
}
void
_cogl_flush_face_winding (void)
{
CoglFrontWinding winding;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* The front face winding doesn't matter if we aren't performing any
* backface culling... */
if (!ctx->enable_backface_culling)
return;
/* NB: We use a clockwise face winding order when drawing offscreen because
* all offscreen rendering is done upside down resulting in reversed winding
* for all triangles.
*/
if (cogl_is_offscreen (_cogl_get_draw_buffer ()))
winding = COGL_FRONT_WINDING_CLOCKWISE;
else
winding = COGL_FRONT_WINDING_COUNTER_CLOCKWISE;
if (winding != ctx->flushed_front_winding)
{
if (winding == COGL_FRONT_WINDING_CLOCKWISE)
GE (glFrontFace (GL_CW));
else
GE (glFrontFace (GL_CCW));
ctx->flushed_front_winding = winding;
}
}
void
cogl_set_source_color (const CoglColor *color)
{
@ -326,32 +368,38 @@ set_clip_plane (GLint plane_num,
GLdouble plane[4];
#endif
GLfloat angle;
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);
CoglMatrix inverse_projection;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_get_inverse (projection_stack, &inverse_projection);
/* Calculate the angle between the axes and the line crossing the
two points */
angle = atan2f (vertex_b[1] - vertex_a[1],
vertex_b[0] - vertex_a[0]) * (180.0/G_PI);
_cogl_matrix_stack_push (ctx->modelview_stack);
/* Load the identity matrix and multiply by the reverse of the
projection matrix so we can specify the plane in screen
coordinates */
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
cogl_matrix_init_from_array (&inverse_projection,
ctx->inverse_projection);
_cogl_matrix_stack_multiply (ctx->modelview_stack, &inverse_projection);
_cogl_matrix_stack_push (modelview_stack);
/* Load the inverse of the projection matrix so we can specify the plane
* in screen coordinates */
_cogl_matrix_stack_set (modelview_stack, &inverse_projection);
/* Rotate about point a */
_cogl_matrix_stack_translate (ctx->modelview_stack,
_cogl_matrix_stack_translate (modelview_stack,
vertex_a[0], vertex_a[1], vertex_a[2]);
/* Rotate the plane by the calculated angle so that it will connect
the two points */
_cogl_matrix_stack_rotate (ctx->modelview_stack, angle, 0.0f, 0.0f, 1.0f);
_cogl_matrix_stack_translate (ctx->modelview_stack,
_cogl_matrix_stack_rotate (modelview_stack, angle, 0.0f, 0.0f, 1.0f);
_cogl_matrix_stack_translate (modelview_stack,
-vertex_a[0], -vertex_a[1], -vertex_a[2]);
_cogl_flush_matrix_stacks ();
_cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
plane[0] = 0;
plane[1] = -1.0;
@ -363,7 +411,7 @@ set_clip_plane (GLint plane_num,
GE( glClipPlane (plane_num, plane) );
#endif
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (modelview_stack);
}
void
@ -372,7 +420,12 @@ _cogl_set_clip_planes (float x_offset,
float width,
float height)
{
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrix modelview_matrix;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
CoglMatrix projection_matrix;
float vertex_tl[4] = { x_offset, y_offset, 0, 1.0 };
@ -381,10 +434,8 @@ _cogl_set_clip_planes (float x_offset,
float vertex_br[4] = { x_offset + width, y_offset + height,
0, 1.0 };
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_get (ctx->projection_stack, &projection_matrix);
_cogl_matrix_stack_get (ctx->modelview_stack, &modelview_matrix);
_cogl_matrix_stack_get (projection_stack, &projection_matrix);
_cogl_matrix_stack_get (modelview_stack, &modelview_matrix);
project_vertex (&modelview_matrix, &projection_matrix, vertex_tl);
project_vertex (&modelview_matrix, &projection_matrix, vertex_tr);
@ -422,6 +473,7 @@ _cogl_add_stencil_clip (float x_offset,
gboolean first)
{
CoglHandle current_source;
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -429,6 +481,8 @@ _cogl_add_stencil_clip (float x_offset,
* batched geometry before we start... */
_cogl_journal_flush ();
_cogl_draw_buffer_flush_state (draw_buffer, 0);
/* temporarily swap in our special stenciling material */
current_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
@ -450,6 +504,11 @@ _cogl_add_stencil_clip (float x_offset,
}
else
{
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
/* Add one to every pixel of the stencil buffer in the
rectangle */
GE( glStencilFunc (GL_NEVER, 0x1, 0x3) );
@ -466,16 +525,16 @@ _cogl_add_stencil_clip (float x_offset,
rectangle are set will be valid */
GE( glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
_cogl_matrix_stack_push (ctx->projection_stack);
_cogl_matrix_stack_load_identity (ctx->projection_stack);
_cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_push (ctx->modelview_stack);
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack);
_cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (projection_stack);
}
/* make sure our rectangles hit the stencil buffer before we restore
@ -515,19 +574,32 @@ _cogl_disable_clip_planes (void)
GE( glDisable (GL_CLIP_PLANE0) );
}
/* XXX: This should be deprecated and Cogl should be left to manage
* the glViewport automatically when switching draw buffers. */
void
cogl_set_viewport (int x,
int y,
int width,
int height)
{
CoglHandle draw_buffer;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
draw_buffer = _cogl_get_draw_buffer ();
_cogl_draw_buffer_set_viewport (draw_buffer,
x,
y,
width,
height);
}
/* XXX: This should be deprecated, and we should expose a way to also
* specify an x and y viewport offset */
void
cogl_viewport (guint width,
guint height)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
COGL_NOTE (MISC, "glViewport(0, 0, %u, %u)", width, height);
GE( glViewport (0, 0, width, height) );
ctx->viewport_width = width;
ctx->viewport_height = height;
cogl_set_viewport (0, 0, width, height);
}
void
@ -540,10 +612,11 @@ _cogl_setup_viewport (guint width,
{
float z_camera;
CoglMatrix projection_matrix;
CoglMatrixStack *modelview_stack;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_viewport (width, height);
cogl_set_viewport (0, 0, width, height);
/* For Ortho projection.
* _cogl_matrix_stack_ortho (projection_stack, 0, width, 0, height, -1, 1);
@ -593,11 +666,13 @@ _cogl_setup_viewport (guint width,
cogl_get_projection_matrix (&projection_matrix);
z_camera = 0.5 * projection_matrix.xx;
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_translate (ctx->modelview_stack, -0.5f, -0.5f, -z_camera);
_cogl_matrix_stack_scale (ctx->modelview_stack,
modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_translate (modelview_stack, -0.5f, -0.5f, -z_camera);
_cogl_matrix_stack_scale (modelview_stack,
1.0f / width, -1.0f / height, 1.0f / width);
_cogl_matrix_stack_translate (ctx->modelview_stack,
_cogl_matrix_stack_translate (modelview_stack,
0.0f, -1.0 * height, 0.0f);
}
@ -606,9 +681,6 @@ cogl_get_features (void)
{
_COGL_GET_CONTEXT (ctx, 0);
if (!ctx->features_cached)
_cogl_features_init ();
if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS)
ctx->feature_flags &= ~COGL_FEATURE_VBOS;
@ -626,18 +698,24 @@ cogl_features_available (CoglFeatureFlags features)
return (ctx->feature_flags & features) == features;
}
/* XXX: This function should be deprecated, and replaced with a
* cogl_draw_buffer_get_size() API instead. We don't support offset
* viewports, and you can't have floating point viewport sizes. */
/* XXX: This function should either be replaced with one returning
* integers, or removed/deprecated and make the
* _cogl_draw_buffer_get_viewport* functions public.
*/
void
cogl_get_viewport (float v[4])
{
CoglHandle draw_buffer;
int viewport[4];
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
v[0] = 0;
v[1] = 0;
v[2] = ctx->viewport_width;
v[3] = ctx->viewport_height;
draw_buffer = _cogl_get_draw_buffer ();
_cogl_draw_buffer_get_viewport4fv (draw_buffer, viewport);
for (i = 0; i < 4; i++)
v[i] = viewport[i];
}
void
@ -733,7 +811,7 @@ cogl_disable_fog (void)
void
cogl_flush_gl_state (int flags)
{
_cogl_flush_matrix_stacks ();
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
}
#endif
@ -752,37 +830,52 @@ cogl_read_pixels (int x,
CoglPixelFormat format,
guint8 *pixels)
{
GLint viewport[4];
GLint viewport_height;
int rowstride = width * 4;
guint8 *temprow;
CoglHandle draw_buffer;
int draw_buffer_height;
int rowstride = width * 4;
guint8 *temprow;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
g_return_if_fail (format == COGL_PIXEL_FORMAT_RGBA_8888);
g_return_if_fail (source == COGL_READ_PIXELS_COLOR_BUFFER);
temprow = g_alloca (rowstride * sizeof (guint8));
glGetIntegerv (GL_VIEWPORT, viewport);
viewport_height = viewport[3];
draw_buffer = _cogl_get_draw_buffer ();
_cogl_draw_buffer_flush_state (draw_buffer, 0);
draw_buffer_height = _cogl_draw_buffer_get_height (draw_buffer);
/* The y co-ordinate should be given in OpenGL's coordinate system
so 0 is the bottom row */
y = viewport_height - y - height;
/* Setup the pixel store parameters that may have been changed by
Cogl */
glPixelStorei (GL_PACK_ALIGNMENT, 4);
#ifdef HAVE_COGL_GL
glPixelStorei (GL_PACK_ROW_LENGTH, 0);
glPixelStorei (GL_PACK_SKIP_PIXELS, 0);
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */
* so 0 is the bottom row
*
* NB: all offscreen rendering is done upside down so no conversion
* is necissary in this case.
*/
if (!cogl_is_offscreen (draw_buffer))
y = draw_buffer_height - y - height;
/* make sure any batched primitives get emitted to the GL driver before
* issuing our read pixels... */
cogl_flush ();
glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* Setup the pixel store parameters that may have been changed by
Cogl */
GE (glPixelStorei (GL_PACK_ALIGNMENT, 1));
#ifdef HAVE_COGL_GL
GE (glPixelStorei (GL_PACK_ROW_LENGTH, 0));
GE (glPixelStorei (GL_PACK_SKIP_PIXELS, 0));
GE (glPixelStorei (GL_PACK_SKIP_ROWS, 0));
#endif /* HAVE_COGL_GL */
GE (glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels));
/* NB: All offscreen rendering is done upside down so there is no need
* to flip in this case... */
if (cogl_is_offscreen (draw_buffer))
return;
/* TODO: consider using the GL_MESA_pack_invert extension in the future
* to avoid this flip... */
@ -825,12 +918,13 @@ cogl_begin_gl (void)
/* Flush all batched primitives */
cogl_flush ();
/* Flush our clipping state to GL */
cogl_clip_ensure ();
/* Flush any client side matrix state */
_cogl_flush_matrix_stacks ();
/* Flush framebuffer state, including clip state, modelview and
* projection matrix state
*
* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
/* Setup the state for the current material */
@ -852,6 +946,7 @@ cogl_begin_gl (void)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags);
_cogl_flush_face_winding ();
/* Disable all client texture coordinate arrays */
for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
@ -940,36 +1035,41 @@ _cogl_destroy_texture_units (void)
void
cogl_push_matrix (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_push (ctx->modelview_stack);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_push (modelview_stack);
}
void
cogl_pop_matrix (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_pop (ctx->modelview_stack);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_pop (modelview_stack);
}
void
cogl_scale (float x, float y, float z)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_scale (ctx->modelview_stack, x, y, z);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_scale (modelview_stack, x, y, z);
}
void
cogl_translate (float x, float y, float z)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_translate (ctx->modelview_stack, x, y, z);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_translate (modelview_stack, x, y, z);
}
void
cogl_rotate (float angle, float x, float y, float z)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_rotate (ctx->modelview_stack, angle, x, y, z);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_rotate (modelview_stack, angle, x, y, z);
}
void
@ -996,35 +1096,20 @@ cogl_frustum (float left,
float z_near,
float z_far)
{
float c, d;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_load_identity (ctx->projection_stack);
_cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_frustum (ctx->projection_stack,
_cogl_matrix_stack_frustum (projection_stack,
left,
right,
bottom,
top,
z_near,
z_far);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
c = - (z_far + z_near) / (z_far - z_near);
d = - (2 * (z_far * z_near)) / (z_far - z_near);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = (right - left) / (2 * z_near);
M(0,3) = (right + left) / (2 * z_near);
M(1,1) = (top - bottom) / (2 * z_near);
M(1,3) = (top + bottom) / (2 * z_near);
M(2,3) = -1.0;
M(3,2) = 1.0 / d;
M(3,3) = c / d;
#undef M
}
void
@ -1036,65 +1121,61 @@ cogl_ortho (float left,
float z_far)
{
CoglMatrix ortho;
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
cogl_matrix_init_identity (&ortho);
cogl_matrix_ortho (&ortho, left, right, bottom, top, z_near, z_far);
_cogl_matrix_stack_set (ctx->projection_stack, &ortho);
/* Calculate and store the inverse of the matrix */
memset (ctx->inverse_projection, 0, sizeof (float) * 16);
#define M(row,col) ctx->inverse_projection[col*4+row]
M(0,0) = 1.0 / ortho.xx;
M(0,3) = -ortho.xw;
M(1,1) = 1.0 / ortho.yy;
M(1,3) = -ortho.yw;
M(2,2) = 1.0 / ortho.zz;
M(2,3) = -ortho.zw;
M(3,3) = 1.0;
#undef M
_cogl_matrix_stack_set (projection_stack, &ortho);
}
void
cogl_get_modelview_matrix (CoglMatrix *matrix)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_get (ctx->modelview_stack, matrix);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_get (modelview_stack, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
cogl_set_modelview_matrix (CoglMatrix *matrix)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_set (ctx->modelview_stack, matrix);
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_set (modelview_stack, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
cogl_get_projection_matrix (CoglMatrix *matrix)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_get (ctx->projection_stack, matrix);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_get (projection_stack, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
cogl_set_projection_matrix (CoglMatrix *matrix)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_set (ctx->projection_stack, matrix);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (_cogl_get_draw_buffer ());
_cogl_matrix_stack_set (projection_stack, matrix);
/* FIXME: Update the inverse projection matrix!! Presumably use
* of clip planes must currently be broken if this API is used. */
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
void
_cogl_flush_matrix_stacks (void)
CoglClipStackState *
_cogl_get_clip_state (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_matrix_stack_flush_to_gl (ctx->projection_stack,
COGL_MATRIX_PROJECTION);
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack,
COGL_MATRIX_MODELVIEW);
CoglHandle draw_buffer;
draw_buffer = _cogl_get_draw_buffer ();
return _cogl_draw_buffer_get_clip_state (draw_buffer);
}

View File

@ -219,6 +219,8 @@ void _cogl_setup_viewport (guint width,
float z_near,
float z_far);
#ifndef COGL_DISABLE_DEPRECATED
/**
* cogl_viewport:
* @width: Width of the viewport
@ -229,7 +231,25 @@ void _cogl_setup_viewport (guint width,
* Since: 0.8.2
*/
void cogl_viewport (guint width,
guint height);
guint height) G_GNUC_DEPRECATED;
#endif
/**
* cogl_set_viewport:
* @x: viewport X offset
* @x: viewport Y offset
* @width: Width of the viewport
* @height: Height of the viewport
*
* Replace the current viewport with the given values.
*
* Since: 1.2
*/
void cogl_set_viewport (int x,
int y,
int width,
int height);
/**
* cogl_push_matrix:
@ -867,6 +887,10 @@ void cogl_flush_gl_state (int flags);
/* private */
void _cogl_set_indirect_context (gboolean indirect);
void _cogl_set_viewport (int x, int y, int width, int height);
void
_cogl_onscreen_clutter_backend_set_size (int width, int height);
G_END_DECLS

View File

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

View File

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

View File

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

View File

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

View File

@ -1,325 +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) );
/* Some implementation require a clear before drawing
to an fbo. Luckily it is affected by scissor test. */
/* FIXME: test where exactly this is needed end whether
a glClear with 0 argument is enough */
GE( glPushAttrib (GL_SCISSOR_BIT) );
GE( glScissor (0,0,0,0) );
GE( glEnable (GL_SCISSOR_TEST) );
GE( glClear (GL_COLOR_BUFFER_BIT) );
GE( glPopAttrib () );
}
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

@ -30,6 +30,8 @@
#include "cogl-context.h"
#include "cogl-clip-stack.h"
#include "cogl-material-private.h"
#include "cogl-clip-stack.h"
#include "cogl-draw-buffer-private.h"
#include <string.h>
#include <gmodule.h>
@ -74,7 +76,7 @@ _cogl_path_add_node (gboolean new_sub_path,
}
void
_cogl_path_stroke_nodes ()
_cogl_path_stroke_nodes (void)
{
guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@ -82,6 +84,13 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
@ -90,7 +99,6 @@ _cogl_path_stroke_nodes ()
options.disable_layers = (guint32)~0;
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_flush_matrix_stacks ();
while (path_start < ctx->path_nodes->len)
{
@ -127,20 +135,33 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path,
gboolean merge)
{
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
int i;
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
int i;
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't track changes to the stencil buffer in the journal
* so we need to flush any batched geometry first */
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (draw_buffer, 0);
/* Just setup a simple material that doesn't use texturing... */
prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
@ -161,7 +182,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
}
else
{
GE( glClear (GL_STENCIL_BUFFER_BIT) );
cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
GE( glStencilMask (1) );
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
}
@ -179,8 +200,6 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
}
ctx->n_texcoord_arrays_enabled = 0;
_cogl_flush_matrix_stacks ();
while (path_start < path_size)
{
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@ -194,8 +213,17 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
significant bit */
GE( glStencilMask (merge ? 6 : 3) );
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
glRectf (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
/* Make sure the rectangle hits the stencil buffer before
* directly changing other GL state. */
_cogl_journal_flush ();
/* NB: The journal flushing may trash the modelview state and
* enable flags */
_cogl_matrix_stack_flush_to_gl (modelview_stack,
COGL_MATRIX_MODELVIEW);
cogl_enable (enable_flags);
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
}
@ -216,19 +244,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
/* Decrement all of the bits twice so that only pixels where the
value is 3 will remain */
_cogl_matrix_stack_push (ctx->projection_stack);
_cogl_matrix_stack_load_identity (ctx->projection_stack);
_cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_flush_to_gl (projection_stack,
COGL_MATRIX_PROJECTION);
_cogl_matrix_stack_push (ctx->modelview_stack);
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (modelview_stack,
COGL_MATRIX_MODELVIEW);
_cogl_flush_matrix_stacks ();
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
/* Make sure these rectangles hit the stencil buffer before we
* restore the stencil op/func. */
_cogl_journal_flush ();
glRectf (-1.0, -1.0, 1.0, 1.0);
glRectf (-1.0, -1.0, 1.0, 1.0);
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack);
_cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (projection_stack);
}
GE( glStencilMask (~(GLuint) 0) );
@ -244,8 +277,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
}
void
_cogl_path_fill_nodes ()
_cogl_path_fill_nodes (void)
{
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
float bounds_x;
float bounds_y;
float bounds_w;
@ -253,6 +288,11 @@ _cogl_path_fill_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
_cogl_path_get_bounds (ctx->path_nodes_min, ctx->path_nodes_max,
&bounds_x, &bounds_y, &bounds_w, &bounds_h);
@ -261,12 +301,13 @@ _cogl_path_fill_nodes ()
ctx->path_nodes->len,
&g_array_index (ctx->path_nodes,
CoglPathNode, 0),
ctx->clip.stencil_used);
clip_state->stencil_used);
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
/* The stencil buffer now contains garbage so the clip area needs to
be rebuilt */
ctx->clip.stack_dirty = TRUE;
_cogl_clip_stack_state_dirty (clip_state);
}

View File

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

View File

@ -32,6 +32,12 @@
#include "cogl-internal.h"
#include "cogl-context.h"
typedef struct _CoglGLSymbolTableEntry
{
const char *name;
void *ptr;
} CoglGLSymbolTableEntry;
gboolean
cogl_check_extension (const gchar *name, const gchar *ext)
{
@ -57,6 +63,26 @@ cogl_check_extension (const gchar *name, const gchar *ext)
return FALSE;
}
gboolean
_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table,
const char *suffix)
{
int i;
gboolean status = TRUE;
for (i = 0; symbol_table[i].name; i++)
{
char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix);
*((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name);
g_free (full_name);
if (!*((CoglFuncPtr *)symbol_table[i].ptr))
{
status = FALSE;
break;
}
}
return status;
}
#ifdef HAVE_CLUTTER_OSX
static gboolean
really_enable_npot (void)
@ -90,6 +116,9 @@ _cogl_features_init (void)
const gchar *gl_extensions;
GLint max_clip_planes = 0;
GLint num_stencil_bits = 0;
gboolean fbo_ARB = FALSE;
gboolean fbo_EXT = FALSE;
const char *suffix;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -284,64 +313,35 @@ _cogl_features_init (void)
flags |= COGL_FEATURE_SHADERS_GLSL;
}
if (cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions) ||
cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions))
fbo_ARB = cogl_check_extension ("GL_ARB_framebuffer_object", gl_extensions);
if (fbo_ARB)
suffix = "";
else
{
ctx->drv.pf_glGenRenderbuffersEXT =
(COGL_PFNGLGENRENDERBUFFERSEXTPROC)
cogl_get_proc_address ("glGenRenderbuffersEXT");
fbo_EXT = cogl_check_extension ("GL_EXT_framebuffer_object", gl_extensions);
if (fbo_EXT)
suffix = "EXT";
}
ctx->drv.pf_glDeleteRenderbuffersEXT =
(COGL_PFNGLDELETERENDERBUFFERSEXTPROC)
cogl_get_proc_address ("glDeleteRenderbuffersEXT");
if (fbo_ARB || fbo_EXT)
{
CoglGLSymbolTableEntry symbol_table[] = {
{"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers},
{"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers},
{"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer},
{"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage},
{"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers},
{"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer},
{"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D},
{"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer},
{"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus},
{"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers},
{"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap},
{NULL, NULL}
};
ctx->drv.pf_glBindRenderbufferEXT =
(COGL_PFNGLBINDRENDERBUFFEREXTPROC)
cogl_get_proc_address ("glBindRenderbufferEXT");
ctx->drv.pf_glRenderbufferStorageEXT =
(COGL_PFNGLRENDERBUFFERSTORAGEEXTPROC)
cogl_get_proc_address ("glRenderbufferStorageEXT");
ctx->drv.pf_glGenFramebuffersEXT =
(COGL_PFNGLGENFRAMEBUFFERSEXTPROC)
cogl_get_proc_address ("glGenFramebuffersEXT");
ctx->drv.pf_glBindFramebufferEXT =
(COGL_PFNGLBINDFRAMEBUFFEREXTPROC)
cogl_get_proc_address ("glBindFramebufferEXT");
ctx->drv.pf_glFramebufferTexture2DEXT =
(COGL_PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
cogl_get_proc_address ("glFramebufferTexture2DEXT");
ctx->drv.pf_glFramebufferRenderbufferEXT =
(COGL_PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
cogl_get_proc_address ("glFramebufferRenderbufferEXT");
ctx->drv.pf_glCheckFramebufferStatusEXT =
(COGL_PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
cogl_get_proc_address ("glCheckFramebufferStatusEXT");
ctx->drv.pf_glDeleteFramebuffersEXT =
(COGL_PFNGLDELETEFRAMEBUFFERSEXTPROC)
cogl_get_proc_address ("glDeleteFramebuffersEXT");
ctx->drv.pf_glGenerateMipmapEXT =
(COGL_PFNGLGENERATEMIPMAPEXTPROC)
cogl_get_proc_address ("glGenerateMipmapEXT");
if (ctx->drv.pf_glGenRenderbuffersEXT &&
ctx->drv.pf_glBindRenderbufferEXT &&
ctx->drv.pf_glRenderbufferStorageEXT &&
ctx->drv.pf_glGenFramebuffersEXT &&
ctx->drv.pf_glBindFramebufferEXT &&
ctx->drv.pf_glFramebufferTexture2DEXT &&
ctx->drv.pf_glFramebufferRenderbufferEXT &&
ctx->drv.pf_glCheckFramebufferStatusEXT &&
ctx->drv.pf_glDeleteFramebuffersEXT &&
ctx->drv.pf_glGenerateMipmapEXT)
flags |= COGL_FEATURE_OFFSCREEN;
if (_cogl_resolve_gl_symbols (symbol_table, suffix))
flags |= COGL_FEATURE_OFFSCREEN;
}
if (cogl_check_extension ("GL_EXT_framebuffer_blit", gl_extensions))

View File

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

View File

@ -31,6 +31,16 @@
void
_cogl_create_context_driver (CoglContext *context)
{
context->drv.pf_glGenRenderbuffers = NULL;
context->drv.pf_glBindRenderbuffer = NULL;
context->drv.pf_glRenderbufferStorage = NULL;
context->drv.pf_glGenFramebuffers = NULL;
context->drv.pf_glBindFramebuffer = NULL;
context->drv.pf_glFramebufferTexture2D = NULL;
context->drv.pf_glFramebufferRenderbuffer = NULL;
context->drv.pf_glCheckFramebufferStatus = NULL;
context->drv.pf_glDeleteFramebuffers = NULL;
/* Init the GLES2 wrapper */
#ifdef HAVE_COGL_GLES2
cogl_gles2_wrapper_init (&context->drv.gles2);

View File

@ -24,17 +24,26 @@
#ifndef __COGL_CONTEXT_DRIVER_H
#define __COGL_CONTEXT_DRIVER_H
#include "cogl.h"
#include "cogl-gles2-wrapper.h"
typedef struct _CoglContextDriver
{
COGL_PFNGLGENRENDERBUFFERSPROC pf_glGenRenderbuffers;
COGL_PFNGLDELETERENDERBUFFERSPROC pf_glDeleteRenderbuffers;
COGL_PFNGLBINDRENDERBUFFERPROC pf_glBindRenderbuffer;
COGL_PFNGLRENDERBUFFERSTORAGEPROC pf_glRenderbufferStorage;
COGL_PFNGLGENFRAMEBUFFERSPROC pf_glGenFramebuffers;
COGL_PFNGLBINDFRAMEBUFFERPROC pf_glBindFramebuffer;
COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC pf_glFramebufferTexture2D;
COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC pf_glFramebufferRenderbuffer;
COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC pf_glCheckFramebufferStatus;
COGL_PFNGLDELETEFRAMEBUFFERSPROC pf_glDeleteFramebuffers;
COGL_PFNGLGENERATEMIPMAPPROC pf_glGenerateMipmap;
#ifdef HAVE_COGL_GLES2
CoglGles2Wrapper gles2;
/* Viewport store for FBOs. Needed because glPushAttrib() isn't
supported */
GLint viewport_store[4];
#endif
} CoglContextDriver;

View File

@ -633,6 +633,76 @@ G_BEGIN_DECLS
#define CGL_SHININESS 0x1601
#endif
/* Extension function prototypes */
#ifndef APIENTRY
#define APIENTRY
#endif
#ifndef APIENTRYP
#define APIENTRYP APIENTRY *
#endif
typedef void
(APIENTRYP COGL_PFNGLGENRENDERBUFFERSPROC)
(GLsizei n,
GLuint *renderbuffers);
typedef void
(APIENTRYP COGL_PFNGLBINDRENDERBUFFERPROC)
(GLenum target,
GLuint renderbuffer);
typedef void
(APIENTRYP COGL_PFNGLRENDERBUFFERSTORAGEPROC)
(GLenum target,
GLenum internalformat,
GLsizei width,
GLsizei height);
typedef void
(APIENTRYP COGL_PFNGLGENFRAMEBUFFERSPROC)
(GLsizei n,
GLuint *framebuffers);
typedef void
(APIENTRYP COGL_PFNGLBINDFRAMEBUFFERPROC)
(GLenum target,
GLuint framebuffer);
typedef void
(APIENTRYP COGL_PFNGLFRAMEBUFFERTEXTURE2DPROC)
(GLenum target,
GLenum attachment,
GLenum textarget,
GLuint texture,
GLint level);
typedef void
(APIENTRYP COGL_PFNGLFRAMEBUFFERRENDERBUFFERPROC)
(GLenum target,
GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer);
typedef GLenum
(APIENTRYP COGL_PFNGLCHECKFRAMEBUFFERSTATUSPROC)
(GLenum target);
typedef void
(APIENTRYP COGL_PFNGLDELETEFRAMEBUFFERSPROC)
(GLsizei n,
const GLuint *framebuffers);
typedef void
(APIENTRYP COGL_PFNGLDELETERENDERBUFFERSPROC)
(GLsizei n,
const GLuint *renderbuffers);
typedef void
(APIENTRYP COGL_PFNGLGENERATEMIPMAPPROC)
(GLenum target);
G_END_DECLS
#endif

View File

@ -1,339 +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);
g_assert (ctx->draw_buffer_stack != NULL);
draw_buffer = ctx->draw_buffer_stack->data;
if (target == COGL_OFFSCREEN_BUFFER)
{
GLboolean scissor_enabled;
GLint scissor_box[4];
/* 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 */
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);
/* Bind offscreen framebuffer object */
GE( glBindFramebuffer (GL_FRAMEBUFFER, fbo->gl_handle) );
GE( glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE) );
/* Some implementation require a clear before drawing
to an fbo. Luckily it is affected by scissor test. */
/* FIXME: test where exactly this is needed end whether
a glClear with 0 argument is enough */
scissor_enabled = glIsEnabled (GL_SCISSOR_TEST);
GE( glGetIntegerv (GL_SCISSOR_BOX, scissor_box) );
GE( glScissor (0, 0, 0, 0) );
GE( glEnable (GL_SCISSOR_TEST) );
GE( glClear (GL_COLOR_BUFFER_BIT) );
if (!scissor_enabled)
glDisable (GL_SCISSOR_TEST);
glScissor (scissor_box[0], scissor_box[1],
scissor_box[2], scissor_box[3]);
}
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-clip-stack.h"
#include "cogl-material-private.h"
#include "cogl-clip-stack.h"
#include "cogl-draw-buffer-private.h"
#include "cogl-clip-stack.h"
#include <string.h>
#include <gmodule.h>
@ -72,7 +75,7 @@ _cogl_path_add_node (gboolean new_sub_path,
}
void
_cogl_path_stroke_nodes ()
_cogl_path_stroke_nodes (void)
{
guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
@ -80,13 +83,21 @@ _cogl_path_stroke_nodes ()
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
/* disable all texture layers */
options.disable_layers = (guint32)~0;
_cogl_material_flush_gl_state (ctx->source_material,&options);
_cogl_flush_matrix_stacks();
_cogl_material_flush_gl_state (ctx->source_material, &options);
while (path_start < ctx->path_nodes->len)
{
@ -129,18 +140,38 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path,
gboolean merge)
{
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
int i;
CoglHandle draw_buffer = _cogl_get_draw_buffer ();
CoglMatrixStack *modelview_stack =
_cogl_draw_buffer_get_modelview_stack (draw_buffer);
CoglMatrixStack *projection_stack =
_cogl_draw_buffer_get_projection_stack (draw_buffer);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We don't track changes to the stencil buffer in the journal
* so we need to flush any batched geometry first */
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (draw_buffer, 0);
/* Just setup a simple material that doesn't use texturing... */
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
_cogl_material_flush_gl_state (ctx->source_material, NULL);
enable_flags |=
_cogl_material_get_cogl_enable_flags (ctx->source_material);
@ -156,7 +187,7 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
}
else
{
GE( glClear (GL_STENCIL_BUFFER_BIT) );
cogl_clear (NULL, COGL_BUFFER_BIT_STENCIL);
GE( glStencilMask (1) );
GE( glStencilFunc (GL_LEQUAL, 0x1, 0x3) );
}
@ -167,7 +198,13 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (FALSE) );
_cogl_matrix_stack_flush_to_gl (ctx->modelview_stack, COGL_MATRIX_MODELVIEW);
for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
}
ctx->n_texcoord_arrays_enabled = 0;
while (path_start < path_size)
{
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@ -183,6 +220,14 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
/* Make sure the rectangle hits the stencil buffer before
* directly changing other GL state. */
_cogl_journal_flush ();
/* NB: The journal flushing may trash the modelview state and
* enable flags */
_cogl_matrix_stack_flush_to_gl (modelview_stack,
COGL_MATRIX_MODELVIEW);
cogl_enable (enable_flags);
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
}
@ -204,17 +249,24 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
/* Decrement all of the bits twice so that only pixels where the
value is 3 will remain */
_cogl_matrix_stack_push (ctx->projection_stack);
_cogl_matrix_stack_load_identity (ctx->projection_stack);
_cogl_matrix_stack_push (projection_stack);
_cogl_matrix_stack_load_identity (projection_stack);
_cogl_matrix_stack_flush_to_gl (projection_stack,
COGL_MATRIX_PROJECTION);
_cogl_matrix_stack_push (ctx->modelview_stack);
_cogl_matrix_stack_load_identity (ctx->modelview_stack);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_matrix_stack_flush_to_gl (modelview_stack,
COGL_MATRIX_MODELVIEW);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
/* Make sure these rectangles hit the stencil buffer before we
* restore the stencil op/func. */
_cogl_journal_flush ();
_cogl_matrix_stack_pop (ctx->modelview_stack);
_cogl_matrix_stack_pop (ctx->projection_stack);
_cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (projection_stack);
}
GE( glStencilMask (~(GLuint) 0) );
@ -250,6 +302,21 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* We are going to use GL to draw directly so make sure any
* previously batched geometry gets to GL before we start...
*/
_cogl_journal_flush ();
/* NB: _cogl_draw_buffer_flush_state may disrupt various state (such
* as the material state) when flushing the clip stack, so should
* always be done first when preparing to draw. */
_cogl_draw_buffer_flush_state (_cogl_get_draw_buffer (), 0);
_cogl_material_flush_gl_state (ctx->source_material, NULL);
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
/* clear scanline intersection lists */
for (i=0; i < bounds_h; i++)
scanlines[i]=NULL;
@ -386,8 +453,6 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
}
/* render triangles */
cogl_enable (COGL_ENABLE_VERTEX_ARRAY
| (ctx->color_alpha < 255 ? COGL_ENABLE_BLEND : 0));
GE ( glVertexPointer (2, GL_FLOAT, 0, coords ) );
GE ( glDrawArrays (GL_TRIANGLES, 0, spans * 2 * 3));
g_free (coords);
@ -395,7 +460,7 @@ _cogl_path_fill_nodes_scanlines (CoglPathNode *path,
}
void
_cogl_path_fill_nodes ()
_cogl_path_fill_nodes (void)
{
float bounds_x;
float bounds_y;
@ -409,19 +474,27 @@ _cogl_path_fill_nodes ()
if (cogl_features_available (COGL_FEATURE_STENCIL_BUFFER))
{
CoglHandle draw_buffer;
CoglClipStackState *clip_state;
_cogl_journal_flush ();
draw_buffer = _cogl_get_draw_buffer ();
clip_state = _cogl_draw_buffer_get_clip_state (draw_buffer);
_cogl_add_path_to_stencil_buffer (ctx->path_nodes_min,
ctx->path_nodes_max,
ctx->path_nodes->len,
&g_array_index (ctx->path_nodes,
CoglPathNode, 0),
ctx->clip.stencil_used);
clip_state->stencil_used);
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
/* The stencil buffer now contains garbage so the clip area needs to
be rebuilt */
ctx->clip.stack_dirty = TRUE;
_cogl_clip_stack_state_dirty (clip_state);
}
else
{

View File

@ -31,6 +31,56 @@
#include "cogl-internal.h"
#include "cogl-context.h"
typedef struct _CoglGLSymbolTableEntry
{
const char *name;
void *ptr;
} CoglGLSymbolTableEntry;
gboolean
cogl_check_extension (const gchar *name, const gchar *ext)
{
gchar *end;
gint name_len, n;
if (name == NULL || ext == NULL)
return FALSE;
end = (gchar*)(ext + strlen(ext));
name_len = strlen(name);
while (ext < end)
{
n = strcspn(ext, " ");
if ((name_len == n) && (!strncmp(name, ext, n)))
return TRUE;
ext += (n + 1);
}
return FALSE;
}
gboolean
_cogl_resolve_gl_symbols (CoglGLSymbolTableEntry *symbol_table,
const char *suffix)
{
int i;
gboolean status = TRUE;
for (i = 0; symbol_table[i].name; i++)
{
char *full_name = g_strdup_printf ("%s%s", symbol_table[i].name, suffix);
*((CoglFuncPtr *)symbol_table[i].ptr) = cogl_get_proc_address (full_name);
g_free (full_name);
if (!*((CoglFuncPtr *)symbol_table[i].ptr))
{
status = FALSE;
break;
}
}
return status;
}
void
@ -39,9 +89,34 @@ _cogl_features_init (void)
CoglFeatureFlags flags = 0;
int max_clip_planes = 0;
GLint num_stencil_bits = 0;
const char *gl_extensions;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
gl_extensions = (const char*) glGetString (GL_EXTENSIONS);
if (cogl_check_extension ("GL_OES_framebuffer_object", gl_extensions))
{
g_assert (0);
CoglGLSymbolTableEntry symbol_table[] = {
{"glGenRenderbuffers", &ctx->drv.pf_glGenRenderbuffers},
{"glDeleteRenderbuffers", &ctx->drv.pf_glDeleteRenderbuffers},
{"glBindRenderbuffer", &ctx->drv.pf_glBindRenderbuffer},
{"glRenderbufferStorage", &ctx->drv.pf_glRenderbufferStorage},
{"glGenFramebuffers", &ctx->drv.pf_glGenFramebuffers},
{"glBindFramebuffer", &ctx->drv.pf_glBindFramebuffer},
{"glFramebufferTexture2D", &ctx->drv.pf_glFramebufferTexture2D},
{"glFramebufferRenderbuffer", &ctx->drv.pf_glFramebufferRenderbuffer},
{"glCheckFramebufferStatus", &ctx->drv.pf_glCheckFramebufferStatus},
{"glDeleteFramebuffers", &ctx->drv.pf_glDeleteFramebuffers},
{"glGenerateMipmap", &ctx->drv.pf_glGenerateMipmap},
{NULL, NULL}
};
if (_cogl_resolve_gl_symbols (symbol_table, "OES"))
flags |= COGL_FEATURE_OFFSCREEN;
}
GE( glGetIntegerv (GL_STENCIL_BITS, &num_stencil_bits) );
/* We need at least three stencil bits to combine clips */
if (num_stencil_bits > 2)