Re-design the matrix stack using a graph of ops

This re-designs the matrix stack so we now keep track of each separate
operation such as rotating, scaling, translating and multiplying as
immutable, ref-counted nodes in a graph.

Being a "graph" here means that different transformations composed of
a sequence of linked operation nodes may share nodes.

The first node in a matrix-stack is always a LOAD_IDENTITY operation.

As an example consider if an application where to draw three rectangles
A, B and C something like this:

cogl_framebuffer_scale (fb, 2, 2, 2);
cogl_framebuffer_push_matrix(fb);

  cogl_framebuffer_translate (fb, 10, 0, 0);

  cogl_framebuffer_push_matrix(fb);

    cogl_framebuffer_rotate (fb, 45, 0, 0, 1);
    cogl_framebuffer_draw_rectangle (...); /* A */

  cogl_framebuffer_pop_matrix(fb);

  cogl_framebuffer_draw_rectangle (...); /* B */

cogl_framebuffer_pop_matrix(fb);

cogl_framebuffer_push_matrix(fb);
  cogl_framebuffer_set_modelview_matrix (fb, &mv);
  cogl_framebuffer_draw_rectangle (...); /* C */
cogl_framebuffer_pop_matrix(fb);

That would result in a graph of nodes like this:

LOAD_IDENTITY
      |
    SCALE
    /     \
SAVE       LOAD
  |           |
TRANSLATE    RECTANGLE(C)
  |     \
SAVE    RECTANGLE(B)
  |
ROTATE
  |
RECTANGLE(A)

Each push adds a SAVE operation which serves as a marker to rewind too
when a corresponding pop is issued and also each SAVE node may also
store a cached matrix representing the composition of all its ancestor
nodes. This means if we repeatedly need to resolve a real CoglMatrix
for a given node then we don't need to repeat the composition.

Some advantages of this design are:
- A single pointer to any node in the graph can now represent a
  complete, immutable transformation that can be logged for example
  into a journal. Previously we were storing a full CoglMatrix in
  each journal entry which is 16 floats for the matrix itself as well
  as space for flags and another 16 floats for possibly storing a
  cache of the inverse. This means that we significantly reduce
  the size of the journal when drawing lots of primitives and we also
  avoid copying over 128 bytes per entry.
- It becomes much cheaper to check for equality. In cases where some
  (unlikely) false negatives are allowed simply comparing the pointers
  of two matrix stack graph entries is enough. Previously we would use
  memcmp() to compare matrices.
- It becomes easier to do comparisons of transformations. By looking
  for the common ancestry between nodes we can determine the operations
  that differentiate the transforms and use those to gain a high level
  understanding of the differences. For example we use this in the
  journal to be able to efficiently determine when two rectangle
  transforms only differ by some translation so that we can perform
  software clipping.

Reviewed-by: Neil Roberts <neil@linux.intel.com>

(cherry picked from commit f75aee93f6b293ca7a7babbd8fcc326ee6bf7aef)
This commit is contained in:
Robert Bragg 2012-02-20 15:59:48 +00:00
parent 882ff5612b
commit e3d6bc36d3
23 changed files with 1495 additions and 813 deletions

View File

@ -674,7 +674,10 @@ _cogl_flush_attributes_state (CoglFramebuffer *framebuffer,
_cogl_pipeline_apply_legacy_state (pipeline); _cogl_pipeline_apply_legacy_state (pipeline);
} }
_cogl_pipeline_flush_gl_state (pipeline, skip_gl_color, n_tex_coord_attribs); _cogl_pipeline_flush_gl_state (pipeline,
framebuffer,
skip_gl_color,
n_tex_coord_attribs);
_cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_builtin_attributes_tmp);
_cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp); _cogl_bitmask_clear_all (&ctx->enable_texcoord_attributes_tmp);

View File

@ -46,6 +46,7 @@
#include "cogl-primitive-private.h" #include "cogl-primitive-private.h"
#include "cogl1-context.h" #include "cogl1-context.h"
#include "cogl-offscreen.h" #include "cogl-offscreen.h"
#include "cogl-matrix-stack.h"
#ifndef GL_CLIP_PLANE0 #ifndef GL_CLIP_PLANE0
#define GL_CLIP_PLANE0 0x3000 #define GL_CLIP_PLANE0 0x3000
@ -113,9 +114,10 @@ set_clip_plane (CoglFramebuffer *framebuffer,
/* Clip planes can only be used when a fixed function backend is in /* Clip planes can only be used when a fixed function backend is in
use so we know we can directly push this matrix to the builtin use so we know we can directly push this matrix to the builtin
state */ state */
_cogl_matrix_stack_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
modelview_stack, modelview_stack->last_entry,
COGL_MATRIX_MODELVIEW, COGL_MATRIX_MODELVIEW,
framebuffer,
FALSE /* don't disable flip */); FALSE /* don't disable flip */);
planef[0] = 0; planef[0] = 0;
@ -147,13 +149,12 @@ set_clip_plane (CoglFramebuffer *framebuffer,
static void static void
set_clip_planes (CoglFramebuffer *framebuffer, set_clip_planes (CoglFramebuffer *framebuffer,
CoglMatrixEntry *modelview_entry,
float x_1, float x_1,
float y_1, float y_1,
float x_2, float x_2,
float y_2) float y_2)
{ {
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
CoglMatrix modelview_matrix; CoglMatrix modelview_matrix;
CoglMatrixStack *projection_stack = CoglMatrixStack *projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer); _cogl_framebuffer_get_projection_stack (framebuffer);
@ -167,7 +168,7 @@ set_clip_planes (CoglFramebuffer *framebuffer,
float vertex_br[4] = { x_2, y_2, 0, 1.0 }; float vertex_br[4] = { x_2, y_2, 0, 1.0 };
_cogl_matrix_stack_get (projection_stack, &projection_matrix); _cogl_matrix_stack_get (projection_stack, &projection_matrix);
_cogl_matrix_stack_get (modelview_stack, &modelview_matrix); _cogl_matrix_entry_get (modelview_entry, &modelview_matrix);
cogl_matrix_multiply (&modelview_projection, cogl_matrix_multiply (&modelview_projection,
&projection_matrix, &projection_matrix,
@ -207,23 +208,24 @@ set_clip_planes (CoglFramebuffer *framebuffer,
static void static void
add_stencil_clip_rectangle (CoglFramebuffer *framebuffer, add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
CoglMatrixEntry *modelview_entry,
float x_1, float x_1,
float y_1, float y_1,
float x_2, float x_2,
float y_2, float y_2,
CoglBool first) CoglBool first)
{ {
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
CoglMatrixStack *projection_stack = CoglMatrixStack *projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer); _cogl_framebuffer_get_projection_stack (framebuffer);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
/* This can be called from the journal code which doesn't flush /* NB: This can be called while flushing the journal so we need
the matrix stacks between calls so we need to ensure they're * to be very conservative with what state we change.
flushed now */ */
_cogl_context_set_current_projection (ctx, projection_stack);
_cogl_context_set_current_modelview (ctx, modelview_stack); _cogl_context_set_current_projection_entry (ctx,
projection_stack->last_entry);
_cogl_context_set_current_modelview_entry (ctx, modelview_entry);
if (first) if (first)
{ {
@ -256,21 +258,12 @@ add_stencil_clip_rectangle (CoglFramebuffer *framebuffer,
rectangle are set will be valid */ rectangle are set will be valid */
GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) ); GE( ctx, glStencilOp (GL_DECR, GL_DECR, GL_DECR) );
_cogl_matrix_stack_push (projection_stack); _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
_cogl_matrix_stack_load_identity (projection_stack); _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_context_set_current_projection (ctx, projection_stack);
_cogl_context_set_current_modelview (ctx, modelview_stack);
_cogl_rectangle_immediate (framebuffer, _cogl_rectangle_immediate (framebuffer,
ctx->stencil_pipeline, ctx->stencil_pipeline,
-1.0, -1.0, 1.0, 1.0); -1.0, -1.0, 1.0, 1.0);
_cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (projection_stack);
} }
/* Restore the stencil mode */ /* Restore the stencil mode */
@ -285,6 +278,7 @@ typedef void (*SilhouettePaintCallback) (CoglFramebuffer *framebuffer,
static void static void
add_stencil_clip_silhouette (CoglFramebuffer *framebuffer, add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
SilhouettePaintCallback silhouette_callback, SilhouettePaintCallback silhouette_callback,
CoglMatrixEntry *modelview_entry,
float bounds_x1, float bounds_x1,
float bounds_y1, float bounds_y1,
float bounds_x2, float bounds_x2,
@ -293,19 +287,19 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
CoglBool need_clear, CoglBool need_clear,
void *user_data) void *user_data)
{ {
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
CoglMatrixStack *projection_stack = CoglMatrixStack *projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer); _cogl_framebuffer_get_projection_stack (framebuffer);
CoglContext *ctx = cogl_framebuffer_get_context (framebuffer); CoglContext *ctx = cogl_framebuffer_get_context (framebuffer);
/* This can be called from the clip stack code which doesn't flush /* NB: This can be called while flushing the journal so we need
the matrix stacks between calls so we need to ensure they're * to be very conservative with what state we change.
flushed now */ */
_cogl_context_set_current_projection (ctx, projection_stack);
_cogl_context_set_current_modelview (ctx, modelview_stack);
_cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, FALSE, 0); _cogl_context_set_current_projection_entry (ctx,
projection_stack->last_entry);
_cogl_context_set_current_modelview_entry (ctx, modelview_entry);
_cogl_pipeline_flush_gl_state (ctx->stencil_pipeline, framebuffer, FALSE, 0);
GE( ctx, glEnable (GL_STENCIL_TEST) ); GE( ctx, glEnable (GL_STENCIL_TEST) );
@ -360,19 +354,13 @@ add_stencil_clip_silhouette (CoglFramebuffer *framebuffer,
/* Decrement all of the bits twice so that only pixels where the /* Decrement all of the bits twice so that only pixels where the
value is 3 will remain */ value is 3 will remain */
_cogl_matrix_stack_push (projection_stack); _cogl_context_set_current_projection_entry (ctx, &ctx->identity_entry);
_cogl_matrix_stack_load_identity (projection_stack); _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_load_identity (modelview_stack);
_cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
-1.0, -1.0, 1.0, 1.0); -1.0, -1.0, 1.0, 1.0);
_cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline, _cogl_rectangle_immediate (framebuffer, ctx->stencil_pipeline,
-1.0, -1.0, 1.0, 1.0); -1.0, -1.0, 1.0, 1.0);
_cogl_matrix_stack_pop (modelview_stack);
_cogl_matrix_stack_pop (projection_stack);
} }
GE (ctx, glStencilMask (~(GLuint) 0)); GE (ctx, glStencilMask (~(GLuint) 0));
@ -400,6 +388,7 @@ paint_path_silhouette (CoglFramebuffer *framebuffer,
static void static void
add_stencil_clip_path (CoglFramebuffer *framebuffer, add_stencil_clip_path (CoglFramebuffer *framebuffer,
CoglMatrixEntry *modelview_entry,
CoglPath *path, CoglPath *path,
CoglBool merge, CoglBool merge,
CoglBool need_clear) CoglBool need_clear)
@ -407,6 +396,7 @@ add_stencil_clip_path (CoglFramebuffer *framebuffer,
CoglPathData *data = path->data; CoglPathData *data = path->data;
add_stencil_clip_silhouette (framebuffer, add_stencil_clip_silhouette (framebuffer,
paint_path_silhouette, paint_path_silhouette,
modelview_entry,
data->path_nodes_min.x, data->path_nodes_min.x,
data->path_nodes_min.y, data->path_nodes_min.y,
data->path_nodes_max.x, data->path_nodes_max.x,
@ -432,6 +422,7 @@ paint_primitive_silhouette (CoglFramebuffer *framebuffer,
static void static void
add_stencil_clip_primitive (CoglFramebuffer *framebuffer, add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
CoglMatrixEntry *modelview_entry,
CoglPrimitive *primitive, CoglPrimitive *primitive,
float bounds_x1, float bounds_x1,
float bounds_y1, float bounds_y1,
@ -442,6 +433,7 @@ add_stencil_clip_primitive (CoglFramebuffer *framebuffer,
{ {
add_stencil_clip_silhouette (framebuffer, add_stencil_clip_silhouette (framebuffer,
paint_primitive_silhouette, paint_primitive_silhouette,
modelview_entry,
bounds_x1, bounds_x1,
bounds_y1, bounds_y1,
bounds_x2, bounds_x2,
@ -500,32 +492,49 @@ _cogl_clip_stack_push_entry (CoglClipStack *clip_stack,
return entry; return entry;
} }
static void
get_transformed_corners (float x_1,
float y_1,
float x_2,
float y_2,
CoglMatrix *modelview,
CoglMatrix *projection,
const float *viewport,
float *transformed_corners)
{
int i;
transformed_corners[0] = x_1;
transformed_corners[1] = y_1;
transformed_corners[2] = x_2;
transformed_corners[3] = y_1;
transformed_corners[4] = x_2;
transformed_corners[5] = y_2;
transformed_corners[6] = x_1;
transformed_corners[7] = y_2;
/* Project the coordinates to window space coordinates */
for (i = 0; i < 4; i++)
{
float *v = transformed_corners + i * 2;
_cogl_transform_point (modelview, projection, viewport, v, v + 1);
}
}
/* Sets the window-space bounds of the entry based on the projected /* Sets the window-space bounds of the entry based on the projected
coordinates of the given rectangle */ coordinates of the given rectangle */
static void static void
_cogl_clip_stack_entry_set_bounds (CoglClipStack *entry, _cogl_clip_stack_entry_set_bounds (CoglClipStack *entry,
float x_1, float *transformed_corners)
float y_1,
float x_2,
float y_2,
const CoglMatrix *modelview)
{ {
CoglMatrix projection;
float viewport[4];
float verts[4 * 2] = { x_1, y_1, x_2, y_1, x_2, y_2, x_1, y_2 };
float min_x = G_MAXFLOAT, min_y = G_MAXFLOAT; float min_x = G_MAXFLOAT, min_y = G_MAXFLOAT;
float max_x = -G_MAXFLOAT, max_y = -G_MAXFLOAT; float max_x = -G_MAXFLOAT, max_y = -G_MAXFLOAT;
int i; int i;
cogl_get_projection_matrix (&projection);
cogl_get_viewport (viewport);
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++)
{ {
float *v = verts + i * 2; float *v = transformed_corners + i * 2;
/* Project the coordinates to window space coordinates */
_cogl_transform_point (modelview, &projection, viewport, v, v + 1);
if (v[0] > max_x) if (v[0] > max_x)
max_x = v[0]; max_x = v[0];
@ -570,11 +579,28 @@ _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
float y_1, float y_1,
float x_2, float x_2,
float y_2, float y_2,
const CoglMatrix *modelview_matrix) CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport)
{ {
CoglClipStackRect *entry; CoglClipStackRect *entry;
CoglMatrix matrix_p; CoglMatrix modelview;
float v[4]; CoglMatrix projection;
CoglMatrix modelview_projection;
/* Corners of the given rectangle in an clockwise order:
* (0, 1) (2, 3)
*
*
*
* (6, 7) (4, 5)
*/
float rect[] = {
x_1, y_1,
x_2, y_1,
x_2, y_2,
x_1, y_2
};
/* Make a new entry */ /* Make a new entry */
entry = _cogl_clip_stack_push_entry (stack, entry = _cogl_clip_stack_push_entry (stack,
@ -586,34 +612,46 @@ _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
entry->x1 = x_2; entry->x1 = x_2;
entry->y1 = y_2; entry->y1 = y_2;
entry->matrix = *modelview_matrix; entry->matrix_entry = _cogl_matrix_entry_ref (modelview_entry);
/* If the modelview meets these constraints then a transformed rectangle _cogl_matrix_entry_get (modelview_entry, &modelview);
* should still be a rectangle when it reaches screen coordinates. _cogl_matrix_entry_get (projection_entry, &projection);
cogl_matrix_multiply (&modelview_projection,
&projection,
&modelview);
/* Technically we could avoid the viewport transform at this point
* if we want to make this a bit faster. */
_cogl_transform_point (&modelview, &projection, viewport, &rect[0], &rect[1]);
_cogl_transform_point (&modelview, &projection, viewport, &rect[2], &rect[3]);
_cogl_transform_point (&modelview, &projection, viewport, &rect[4], &rect[5]);
_cogl_transform_point (&modelview, &projection, viewport, &rect[6], &rect[7]);
/* If the fully transformed rectangle isn't still axis aligned we
* can't handle it using a scissor.
* *
* FIXME: we are are making certain assumptions about the projection * We don't use an epsilon here since we only really aim to catch
* matrix a.t.m and should really be looking at the combined modelview * simple cases where the transform doesn't leave the rectangle screen
* and projection matrix. * aligned and don't mind some false positives.
* FIXME: we don't consider rotations that are a multiple of 90 degrees
* which could be quite common.
*/ */
if (modelview_matrix->xy != 0 || modelview_matrix->xz != 0 || if (rect[0] != rect[6] ||
modelview_matrix->yx != 0 || modelview_matrix->yz != 0 || rect[1] != rect[3] ||
modelview_matrix->zx != 0 || modelview_matrix->zy != 0) rect[2] != rect[4] ||
rect[7] != rect[5])
{ {
entry->can_be_scissor = FALSE; entry->can_be_scissor = FALSE;
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
x_1, y_1, x_2, y_2, modelview_matrix); rect);
} }
else else
{ {
CoglClipStack *base_entry = (CoglClipStack *) entry; CoglClipStack *base_entry = (CoglClipStack *) entry;
x_1 = rect[0];
cogl_get_projection_matrix (&matrix_p); y_1 = rect[1];
cogl_get_viewport (v); x_2 = rect[4];
y_2 = rect[5];
_cogl_transform_point (modelview_matrix, &matrix_p, v, &x_1, &y_1);
_cogl_transform_point (modelview_matrix, &matrix_p, v, &x_2, &y_2);
/* Consider that the modelview matrix may flip the rectangle /* Consider that the modelview matrix may flip the rectangle
* along the x or y axis... */ * along the x or y axis... */
@ -637,7 +675,9 @@ _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
CoglClipStack * CoglClipStack *
_cogl_clip_stack_push_from_path (CoglClipStack *stack, _cogl_clip_stack_push_from_path (CoglClipStack *stack,
CoglPath *path, CoglPath *path,
const CoglMatrix *modelview_matrix) CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport)
{ {
float x_1, y_1, x_2, y_2; float x_1, y_1, x_2, y_2;
@ -650,10 +690,15 @@ _cogl_clip_stack_push_from_path (CoglClipStack *stack,
return _cogl_clip_stack_push_rectangle (stack, return _cogl_clip_stack_push_rectangle (stack,
x_1, y_1, x_1, y_1,
x_2, y_2, x_2, y_2,
modelview_matrix); modelview_entry,
projection_entry,
viewport);
else else
{ {
CoglClipStackPath *entry; CoglClipStackPath *entry;
CoglMatrix modelview;
CoglMatrix projection;
float transformed_corners[8];
entry = _cogl_clip_stack_push_entry (stack, entry = _cogl_clip_stack_push_entry (stack,
sizeof (CoglClipStackPath), sizeof (CoglClipStackPath),
@ -661,10 +706,18 @@ _cogl_clip_stack_push_from_path (CoglClipStack *stack,
entry->path = cogl_path_copy (path); entry->path = cogl_path_copy (path);
entry->matrix = *modelview_matrix; entry->matrix_entry = _cogl_matrix_entry_ref (modelview_entry);
_cogl_matrix_entry_get (modelview_entry, &modelview);
_cogl_matrix_entry_get (projection_entry, &projection);
get_transformed_corners (x_1, y_1, x_2, y_2,
&modelview,
&projection,
viewport,
transformed_corners);
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
x_1, y_1, x_2, y_2, modelview_matrix); transformed_corners);
return (CoglClipStack *) entry; return (CoglClipStack *) entry;
} }
@ -677,9 +730,14 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
float bounds_y1, float bounds_y1,
float bounds_x2, float bounds_x2,
float bounds_y2, float bounds_y2,
const CoglMatrix *modelview_matrix) CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport)
{ {
CoglClipStackPrimitive *entry; CoglClipStackPrimitive *entry;
CoglMatrix modelview;
CoglMatrix projection;
float transformed_corners[8];
entry = _cogl_clip_stack_push_entry (stack, entry = _cogl_clip_stack_push_entry (stack,
sizeof (CoglClipStackPrimitive), sizeof (CoglClipStackPrimitive),
@ -687,18 +745,26 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
entry->primitive = cogl_object_ref (primitive); entry->primitive = cogl_object_ref (primitive);
entry->matrix = *modelview_matrix; entry->matrix_entry = _cogl_matrix_entry_ref (modelview_entry);
entry->bounds_x1 = bounds_x1; entry->bounds_x1 = bounds_x1;
entry->bounds_y1 = bounds_y1; entry->bounds_y1 = bounds_y1;
entry->bounds_x2 = bounds_x2; entry->bounds_x2 = bounds_x2;
entry->bounds_y2 = bounds_y2; entry->bounds_y2 = bounds_y2;
_cogl_matrix_entry_get (modelview_entry, &modelview);
_cogl_matrix_entry_get (modelview_entry, &projection);
get_transformed_corners (bounds_x1, bounds_y1, bounds_x2, bounds_y2,
&modelview,
&projection,
viewport,
transformed_corners);
/* NB: this is referring to the bounds in window coordinates as opposed /* NB: this is referring to the bounds in window coordinates as opposed
* to the bounds above in primitive local coordinates. */ * to the bounds above in primitive local coordinates. */
_cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry, _cogl_clip_stack_entry_set_bounds ((CoglClipStack *) entry,
bounds_x1, bounds_y1, bounds_x2, bounds_y2, transformed_corners);
modelview_matrix);
return (CoglClipStack *) entry; return (CoglClipStack *) entry;
} }
@ -726,23 +792,33 @@ _cogl_clip_stack_unref (CoglClipStack *entry)
switch (entry->type) switch (entry->type)
{ {
case COGL_CLIP_STACK_RECT: case COGL_CLIP_STACK_RECT:
{
CoglClipStackRect *rect = (CoglClipStackRect *) entry;
_cogl_matrix_entry_unref (rect->matrix_entry);
g_slice_free1 (sizeof (CoglClipStackRect), entry); g_slice_free1 (sizeof (CoglClipStackRect), entry);
break; break;
}
case COGL_CLIP_STACK_WINDOW_RECT: case COGL_CLIP_STACK_WINDOW_RECT:
g_slice_free1 (sizeof (CoglClipStackWindowRect), entry); g_slice_free1 (sizeof (CoglClipStackWindowRect), entry);
break; break;
case COGL_CLIP_STACK_PATH: case COGL_CLIP_STACK_PATH:
cogl_object_unref (((CoglClipStackPath *) entry)->path); {
CoglClipStackPath *path_entry = (CoglClipStackPath *) entry;
_cogl_matrix_entry_unref (path_entry->matrix_entry);
cogl_object_unref (path_entry->path);
g_slice_free1 (sizeof (CoglClipStackPath), entry); g_slice_free1 (sizeof (CoglClipStackPath), entry);
break; break;
}
case COGL_CLIP_STACK_PRIMITIVE: case COGL_CLIP_STACK_PRIMITIVE:
cogl_object_unref (((CoglClipStackPrimitive *) entry)->primitive); {
CoglClipStackPrimitive *primitive_entry =
(CoglClipStackPrimitive *) entry;
_cogl_matrix_entry_unref (primitive_entry->matrix_entry);
cogl_object_unref (primitive_entry->primitive);
g_slice_free1 (sizeof (CoglClipStackPrimitive), entry); g_slice_free1 (sizeof (CoglClipStackPrimitive), entry);
break; break;
}
default: default:
g_assert_not_reached (); g_assert_not_reached ();
} }
@ -804,6 +880,7 @@ void
_cogl_clip_stack_flush (CoglClipStack *stack, _cogl_clip_stack_flush (CoglClipStack *stack,
CoglFramebuffer *framebuffer) CoglFramebuffer *framebuffer)
{ {
CoglContext *ctx = framebuffer->context;
int has_clip_planes; int has_clip_planes;
CoglBool using_clip_planes = FALSE; CoglBool using_clip_planes = FALSE;
CoglBool using_stencil_buffer = FALSE; CoglBool using_stencil_buffer = FALSE;
@ -811,12 +888,9 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
int scissor_y0; int scissor_y0;
int scissor_x1; int scissor_x1;
int scissor_y1; int scissor_y1;
CoglMatrixStack *modelview_stack;
CoglClipStack *entry; CoglClipStack *entry;
int scissor_y_start; int scissor_y_start;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* If we have already flushed this state then we don't need to do /* If we have already flushed this state then we don't need to do
anything */ anything */
if (ctx->current_clip_stack_valid) if (ctx->current_clip_stack_valid)
@ -830,9 +904,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
ctx->current_clip_stack_valid = TRUE; ctx->current_clip_stack_valid = TRUE;
ctx->current_clip_stack = _cogl_clip_stack_ref (stack); ctx->current_clip_stack = _cogl_clip_stack_ref (stack);
modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
has_clip_planes = has_clip_planes =
ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES; ctx->private_feature_flags & COGL_PRIVATE_FEATURE_FOUR_CLIP_PLANES;
@ -905,16 +976,12 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
COGL_NOTE (CLIPPING, "Adding stencil clip for path"); COGL_NOTE (CLIPPING, "Adding stencil clip for path");
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_set (modelview_stack, &path_entry->matrix);
add_stencil_clip_path (framebuffer, add_stencil_clip_path (framebuffer,
path_entry->matrix_entry,
path_entry->path, path_entry->path,
using_stencil_buffer, using_stencil_buffer,
TRUE); TRUE);
_cogl_matrix_stack_pop (modelview_stack);
using_stencil_buffer = TRUE; using_stencil_buffer = TRUE;
break; break;
} }
@ -925,10 +992,8 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
COGL_NOTE (CLIPPING, "Adding stencil clip for primitive"); COGL_NOTE (CLIPPING, "Adding stencil clip for primitive");
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_set (modelview_stack, &primitive_entry->matrix);
add_stencil_clip_primitive (framebuffer, add_stencil_clip_primitive (framebuffer,
primitive_entry->matrix_entry,
primitive_entry->primitive, primitive_entry->primitive,
primitive_entry->bounds_x1, primitive_entry->bounds_x1,
primitive_entry->bounds_y1, primitive_entry->bounds_y1,
@ -937,8 +1002,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
using_stencil_buffer, using_stencil_buffer,
TRUE); TRUE);
_cogl_matrix_stack_pop (modelview_stack);
using_stencil_buffer = TRUE; using_stencil_buffer = TRUE;
break; break;
} }
@ -950,9 +1013,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
rectangle was entirely described by its scissor bounds */ rectangle was entirely described by its scissor bounds */
if (!rect->can_be_scissor) if (!rect->can_be_scissor)
{ {
_cogl_matrix_stack_push (modelview_stack);
_cogl_matrix_stack_set (modelview_stack, &rect->matrix);
/* If we support clip planes and we haven't already used /* If we support clip planes and we haven't already used
them then use that instead */ them then use that instead */
if (has_clip_planes) if (has_clip_planes)
@ -961,6 +1021,7 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
"Adding clip planes clip for rectangle"); "Adding clip planes clip for rectangle");
set_clip_planes (framebuffer, set_clip_planes (framebuffer,
rect->matrix_entry,
rect->x0, rect->x0,
rect->y0, rect->y0,
rect->x1, rect->x1,
@ -974,6 +1035,7 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle"); COGL_NOTE (CLIPPING, "Adding stencil clip for rectangle");
add_stencil_clip_rectangle (framebuffer, add_stencil_clip_rectangle (framebuffer,
rect->matrix_entry,
rect->x0, rect->x0,
rect->y0, rect->y0,
rect->x1, rect->x1,
@ -981,8 +1043,6 @@ _cogl_clip_stack_flush (CoglClipStack *stack,
!using_stencil_buffer); !using_stencil_buffer);
using_stencil_buffer = TRUE; using_stencil_buffer = TRUE;
} }
_cogl_matrix_stack_pop (modelview_stack);
} }
break; break;
} }

View File

@ -28,6 +28,7 @@
#include "cogl-matrix.h" #include "cogl-matrix.h"
#include "cogl-primitive.h" #include "cogl-primitive.h"
#include "cogl-framebuffer.h" #include "cogl-framebuffer.h"
#include "cogl-matrix-stack.h"
/* The clip stack works like a GSList where only a pointer to the top /* The clip stack works like a GSList where only a pointer to the top
of the stack is stored. The empty clip stack is represented simply of the stack is stored. The empty clip stack is represented simply
@ -131,7 +132,7 @@ struct _CoglClipStackRect
CoglBool can_be_scissor; CoglBool can_be_scissor;
/* The matrix that was current when the clip was set */ /* The matrix that was current when the clip was set */
CoglMatrix matrix; CoglMatrixEntry *matrix_entry;
}; };
struct _CoglClipStackWindowRect struct _CoglClipStackWindowRect
@ -147,7 +148,7 @@ struct _CoglClipStackPath
CoglClipStack _parent_data; CoglClipStack _parent_data;
/* The matrix that was current when the clip was set */ /* The matrix that was current when the clip was set */
CoglMatrix matrix; CoglMatrixEntry *matrix_entry;
CoglPath *path; CoglPath *path;
}; };
@ -157,7 +158,7 @@ struct _CoglClipStackPrimitive
CoglClipStack _parent_data; CoglClipStack _parent_data;
/* The matrix that was current when the clip was set */ /* The matrix that was current when the clip was set */
CoglMatrix matrix; CoglMatrixEntry *matrix_entry;
CoglPrimitive *primitive; CoglPrimitive *primitive;
@ -180,12 +181,16 @@ _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
float y_1, float y_1,
float x_2, float x_2,
float y_2, float y_2,
const CoglMatrix *modelview_matrix); CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack * CoglClipStack *
_cogl_clip_stack_push_from_path (CoglClipStack *stack, _cogl_clip_stack_push_from_path (CoglClipStack *stack,
CoglPath *path, CoglPath *path,
const CoglMatrix *modelview_matrix); CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack * CoglClipStack *
_cogl_clip_stack_push_primitive (CoglClipStack *stack, _cogl_clip_stack_push_primitive (CoglClipStack *stack,
@ -194,7 +199,9 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
float bounds_y1, float bounds_y1,
float bounds_x2, float bounds_x2,
float bounds_y2, float bounds_y2,
const CoglMatrix *modelview_matrix); CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack * CoglClipStack *
_cogl_clip_stack_pop (CoglClipStack *stack); _cogl_clip_stack_pop (CoglClipStack *stack);

View File

@ -110,14 +110,17 @@ struct _CoglContext
calling it multiple times */ calling it multiple times */
CoglMatrixMode flushed_matrix_mode; CoglMatrixMode flushed_matrix_mode;
/* The matrix stack that should be used for the next render */ /* The matrix stack entries that should be flushed during the next
CoglMatrixStack *current_projection_stack; * pipeline state flush */
CoglMatrixStack *current_modelview_stack; CoglMatrixEntry *current_projection_entry;
CoglMatrixEntry *current_modelview_entry;
/* The last matrix stack with age that was flushed to the GL matrix CoglMatrixEntry identity_entry;
builtins */
CoglMatrixStackCache builtin_flushed_projection; /* A cache of the last (immutable) matrix stack entries that were
CoglMatrixStackCache builtin_flushed_modelview; * flushed to the GL matrix builtins */
CoglMatrixEntryCache builtin_flushed_projection;
CoglMatrixEntryCache builtin_flushed_modelview;
GArray *texture_units; GArray *texture_units;
int active_texture_unit; int active_texture_unit;
@ -336,11 +339,11 @@ if (ctxvar == NULL) return retval;
#define NO_RETVAL #define NO_RETVAL
void void
_cogl_context_set_current_projection (CoglContext *context, _cogl_context_set_current_projection_entry (CoglContext *context,
CoglMatrixStack *stack); CoglMatrixEntry *entry);
void void
_cogl_context_set_current_modelview (CoglContext *context, _cogl_context_set_current_modelview_entry (CoglContext *context,
CoglMatrixStack *stack); CoglMatrixEntry *entry);
#endif /* __COGL_CONTEXT_PRIVATE_H */ #endif /* __COGL_CONTEXT_PRIVATE_H */

View File

@ -395,10 +395,11 @@ cogl_context_new (CoglDisplay *display,
GE (context, glEnable (GL_ALPHA_TEST)); GE (context, glEnable (GL_ALPHA_TEST));
#endif #endif
_context->current_modelview_stack = NULL; _context->current_modelview_entry = NULL;
_context->current_projection_stack = NULL; _context->current_projection_entry = NULL;
_cogl_matrix_stack_init_cache (&_context->builtin_flushed_projection); _cogl_matrix_entry_identity_init (&_context->identity_entry);
_cogl_matrix_stack_init_cache (&_context->builtin_flushed_modelview); _cogl_matrix_entry_cache_init (&_context->builtin_flushed_projection);
_cogl_matrix_entry_cache_init (&_context->builtin_flushed_modelview);
default_texture_bitmap = default_texture_bitmap =
cogl_bitmap_new_for_data (_context, cogl_bitmap_new_for_data (_context,
@ -429,7 +430,6 @@ cogl_context_new (CoglDisplay *display,
cogl_object_unref (default_texture_bitmap); cogl_object_unref (default_texture_bitmap);
cogl_push_source (context->opaque_color_pipeline); cogl_push_source (context->opaque_color_pipeline);
_cogl_pipeline_flush_gl_state (context->opaque_color_pipeline, FALSE, 0);
context->atlases = NULL; context->atlases = NULL;
g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook)); g_hook_list_init (&context->atlas_reorganize_callbacks, sizeof (GHook));
@ -525,12 +525,12 @@ _cogl_context_free (CoglContext *context)
g_slist_free (context->texture_types); g_slist_free (context->texture_types);
g_slist_free (context->buffer_types); g_slist_free (context->buffer_types);
if (_context->current_modelview_stack) if (_context->current_modelview_entry)
cogl_object_unref (_context->current_modelview_stack); _cogl_matrix_entry_unref (_context->current_modelview_entry);
if (_context->current_projection_stack) if (_context->current_projection_entry)
cogl_object_unref (_context->current_projection_stack); _cogl_matrix_entry_unref (_context->current_projection_entry);
_cogl_matrix_stack_destroy_cache (&context->builtin_flushed_projection); _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_projection);
_cogl_matrix_stack_destroy_cache (&context->builtin_flushed_modelview); _cogl_matrix_entry_cache_destroy (&context->builtin_flushed_modelview);
cogl_pipeline_cache_free (context->pipeline_cache); cogl_pipeline_cache_free (context->pipeline_cache);
@ -597,21 +597,21 @@ _cogl_context_update_features (CoglContext *context,
} }
void void
_cogl_context_set_current_projection (CoglContext *context, _cogl_context_set_current_projection_entry (CoglContext *context,
CoglMatrixStack *stack) CoglMatrixEntry *entry)
{ {
cogl_object_ref (stack); _cogl_matrix_entry_ref (entry);
if (context->current_projection_stack) if (context->current_projection_entry)
cogl_object_unref (context->current_projection_stack); _cogl_matrix_entry_unref (context->current_projection_entry);
context->current_projection_stack = stack; context->current_projection_entry = entry;
} }
void void
_cogl_context_set_current_modelview (CoglContext *context, _cogl_context_set_current_modelview_entry (CoglContext *context,
CoglMatrixStack *stack) CoglMatrixEntry *entry)
{ {
cogl_object_ref (stack); _cogl_matrix_entry_ref (entry);
if (context->current_modelview_stack) if (context->current_modelview_entry)
cogl_object_unref (context->current_modelview_stack); _cogl_matrix_entry_unref (context->current_modelview_entry);
context->current_modelview_stack = stack; context->current_modelview_entry = entry;
} }

View File

@ -185,3 +185,8 @@ OPT (CLIPPING,
"clipping", "clipping",
N_("Trace clipping"), N_("Trace clipping"),
N_("Logs information about how Cogl is implementing clipping")) N_("Logs information about how Cogl is implementing clipping"))
OPT (PERFORMANCE,
N_("Cogl Tracing"),
"performance",
N_("Trace performance concerns"),
N_("Tries to highlight sub-optimal Cogl usage."))

View File

@ -56,7 +56,8 @@ static const GDebugKey cogl_log_debug_keys[] = {
{ "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP }, { "texture-pixmap", COGL_DEBUG_TEXTURE_PIXMAP },
{ "bitmap", COGL_DEBUG_BITMAP }, { "bitmap", COGL_DEBUG_BITMAP },
{ "clipping", COGL_DEBUG_CLIPPING }, { "clipping", COGL_DEBUG_CLIPPING },
{ "winsys", COGL_DEBUG_WINSYS } { "winsys", COGL_DEBUG_WINSYS },
{ "performance", COGL_DEBUG_PERFORMANCE }
}; };
static const int n_cogl_log_debug_keys = static const int n_cogl_log_debug_keys =
G_N_ELEMENTS (cogl_log_debug_keys); G_N_ELEMENTS (cogl_log_debug_keys);

View File

@ -67,6 +67,7 @@ typedef enum {
COGL_DEBUG_DISABLE_FAST_READ_PIXEL, COGL_DEBUG_DISABLE_FAST_READ_PIXEL,
COGL_DEBUG_CLIPPING, COGL_DEBUG_CLIPPING,
COGL_DEBUG_WINSYS, COGL_DEBUG_WINSYS,
COGL_DEBUG_PERFORMANCE,
COGL_DEBUG_N_FLAGS COGL_DEBUG_N_FLAGS
} CoglDebugFlags; } CoglDebugFlags;

View File

@ -1533,18 +1533,38 @@ _cogl_framebuffer_flush_dither_state (CoglFramebuffer *framebuffer)
} }
} }
static CoglMatrixEntry *
_cogl_framebuffer_get_modelview_entry (CoglFramebuffer *framebuffer)
{
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
return modelview_stack->last_entry;
}
static void static void
_cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer) _cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
{ {
_cogl_context_set_current_modelview (framebuffer->context, CoglMatrixEntry *modelview_entry =
framebuffer->modelview_stack); _cogl_framebuffer_get_modelview_entry (framebuffer);
_cogl_context_set_current_modelview_entry (framebuffer->context,
modelview_entry);
}
static CoglMatrixEntry *
_cogl_framebuffer_get_projection_entry (CoglFramebuffer *framebuffer)
{
CoglMatrixStack *projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer);
return projection_stack->last_entry;
} }
static void static void
_cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer) _cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
{ {
_cogl_context_set_current_projection (framebuffer->context, CoglMatrixEntry *projection_entry =
framebuffer->projection_stack); _cogl_framebuffer_get_projection_entry (framebuffer);
_cogl_context_set_current_projection_entry (framebuffer->context,
projection_entry);
} }
static void static void
@ -2647,9 +2667,9 @@ void
cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer, cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer,
CoglMatrix *matrix) CoglMatrix *matrix)
{ {
CoglMatrixStack *modelview_stack = CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_stack (framebuffer); _cogl_framebuffer_get_modelview_entry (framebuffer);
_cogl_matrix_stack_get (modelview_stack, matrix); _cogl_matrix_entry_get (modelview_entry, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix); _COGL_MATRIX_DEBUG_PRINT (matrix);
} }
@ -2672,9 +2692,9 @@ void
cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer, cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer,
CoglMatrix *matrix) CoglMatrix *matrix)
{ {
CoglMatrixStack *projection_stack = CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_stack (framebuffer); _cogl_framebuffer_get_projection_entry (framebuffer);
_cogl_matrix_stack_get (projection_stack, matrix); _cogl_matrix_entry_get (projection_entry, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix); _COGL_MATRIX_DEBUG_PRINT (matrix);
} }
@ -2724,14 +2744,25 @@ cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer,
float y_2) float y_2)
{ {
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer); CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix; CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix); CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_entry (framebuffer);
/* XXX: It would be nicer if we stored the private viewport as a
* vec4 so we could avoid this redundant copy. */
float viewport[] = {
framebuffer->viewport_x,
framebuffer->viewport_y,
framebuffer->viewport_width,
framebuffer->viewport_height
};
clip_state->stacks->data = clip_state->stacks->data =
_cogl_clip_stack_push_rectangle (clip_state->stacks->data, _cogl_clip_stack_push_rectangle (clip_state->stacks->data,
x_1, y_1, x_2, y_2, x_1, y_1, x_2, y_2,
&modelview_matrix); modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer) if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |= framebuffer->context->current_draw_buffer_changes |=
@ -2743,14 +2774,25 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
CoglPath *path) CoglPath *path)
{ {
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer); CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix; CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix); CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_entry (framebuffer);
/* XXX: It would be nicer if we stored the private viewport as a
* vec4 so we could avoid this redundant copy. */
float viewport[] = {
framebuffer->viewport_x,
framebuffer->viewport_y,
framebuffer->viewport_width,
framebuffer->viewport_height
};
clip_state->stacks->data = clip_state->stacks->data =
_cogl_clip_stack_push_from_path (clip_state->stacks->data, _cogl_clip_stack_push_from_path (clip_state->stacks->data,
path, path,
&modelview_matrix); modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer) if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |= framebuffer->context->current_draw_buffer_changes |=
@ -2766,16 +2808,27 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
float bounds_y2) float bounds_y2)
{ {
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer); CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix; CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
cogl_get_modelview_matrix (&modelview_matrix); CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_entry (framebuffer);
/* XXX: It would be nicer if we stored the private viewport as a
* vec4 so we could avoid this redundant copy. */
float viewport[] = {
framebuffer->viewport_x,
framebuffer->viewport_y,
framebuffer->viewport_width,
framebuffer->viewport_height
};
clip_state->stacks->data = clip_state->stacks->data =
_cogl_clip_stack_push_primitive (clip_state->stacks->data, _cogl_clip_stack_push_primitive (clip_state->stacks->data,
primitive, primitive,
bounds_x1, bounds_y1, bounds_x1, bounds_y1,
bounds_x2, bounds_y2, bounds_x2, bounds_y2,
&modelview_matrix); modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer) if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |= framebuffer->context->current_draw_buffer_changes |=

View File

@ -67,13 +67,10 @@ typedef struct _CoglJournalEntry
{ {
CoglPipeline *pipeline; CoglPipeline *pipeline;
int n_layers; int n_layers;
CoglMatrix model_view; CoglMatrixEntry *modelview_entry;
CoglClipStack *clip_stack; CoglClipStack *clip_stack;
/* Offset into ctx->logged_vertices */ /* Offset into ctx->logged_vertices */
size_t array_offset; size_t array_offset;
/* XXX: These entries are pretty big now considering the padding in
* CoglPipelineFlushOptions and CoglMatrix, so we might need to optimize this
* later. */
} CoglJournalEntry; } CoglJournalEntry;
CoglJournal * CoglJournal *

View File

@ -107,9 +107,6 @@ typedef struct _CoglJournalFlushState
CoglIndices *indices; CoglIndices *indices;
size_t indices_type_size; size_t indices_type_size;
CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack;
CoglPipeline *pipeline; CoglPipeline *pipeline;
} CoglJournalFlushState; } CoglJournalFlushState;
@ -297,11 +294,8 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
g_print ("BATCHING: modelview batch len = %d\n", batch_len); g_print ("BATCHING: modelview batch len = %d\n", batch_len);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))) if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{ _cogl_context_set_current_modelview_entry (ctx,
_cogl_matrix_stack_set (state->modelview_stack, batch_start->modelview_entry);
&batch_start->model_view);
_cogl_context_set_current_modelview (ctx, state->modelview_stack);
}
attributes = (CoglAttribute **)state->attributes->data; attributes = (CoglAttribute **)state->attributes->data;
@ -413,21 +407,7 @@ compare_entry_modelviews (CoglJournalEntry *entry0,
CoglJournalEntry *entry1) CoglJournalEntry *entry1)
{ {
/* Batch together quads with the same model view matrix */ /* Batch together quads with the same model view matrix */
return entry0->modelview_entry == entry1->modelview_entry;
/* FIXME: this is nasty, there are much nicer ways to track this
* (at the add_quad_vertices level) without resorting to a memcmp!
*
* E.g. If the cogl-current-matrix code maintained an "age" for
* the modelview matrix we could simply check in add_quad_vertices
* if the age has increased, and if so record the change as a
* boolean in the journal.
*/
if (memcmp (&entry0->model_view, &entry1->model_view,
sizeof (GLfloat) * 16) == 0)
return TRUE;
else
return FALSE;
} }
/* At this point we have a run of quads that we know have compatible /* At this point we have a run of quads that we know have compatible
@ -702,6 +682,9 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
void *data) void *data)
{ {
CoglJournalFlushState *state = data; CoglJournalFlushState *state = data;
CoglFramebuffer *framebuffer = state->journal->framebuffer;
CoglContext *ctx = framebuffer->context;
CoglMatrixStack *projection_stack;
COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries, COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries,
"Journal Flush", /* parent */ "Journal Flush", /* parent */
@ -710,15 +693,13 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
"pipeline + entries", "pipeline + entries",
0 /* no application private data */); 0 /* no application private data */);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
COGL_TIMER_START (_cogl_uprof_context, COGL_TIMER_START (_cogl_uprof_context,
time_flush_clip_stack_pipeline_entries); time_flush_clip_stack_pipeline_entries);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING))) if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
g_print ("BATCHING: clip stack batch len = %d\n", batch_len); g_print ("BATCHING: clip stack batch len = %d\n", batch_len);
_cogl_clip_stack_flush (batch_start->clip_stack, state->journal->framebuffer); _cogl_clip_stack_flush (batch_start->clip_stack, framebuffer);
/* XXX: Because we are manually flushing clip state here we need to /* XXX: Because we are manually flushing clip state here we need to
* make sure that the clip state gets updated the next time we flush * make sure that the clip state gets updated the next time we flush
@ -726,22 +707,21 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
* as changed. */ * as changed. */
ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP; ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
_cogl_matrix_stack_push (state->modelview_stack);
/* If we have transformed all our quads at log time then we ensure /* If we have transformed all our quads at log time then we ensure
* no further model transform is applied by loading the identity * no further model transform is applied by loading the identity
* matrix here. We need to do this after flushing the clip stack * matrix here. We need to do this after flushing the clip stack
* because the clip stack flushing code can modify the matrix */ * because the clip stack flushing code can modify the current
* modelview matrix entry */
if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))) if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))))
{ _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
_cogl_matrix_stack_load_identity (state->modelview_stack);
_cogl_context_set_current_modelview (ctx, state->modelview_stack);
}
/* Setting up the clip state can sometimes also flush the projection /* Setting up the clip state can sometimes also update the current
matrix so we should flush it again. This will be a no-op if the * projection matrix entry so we should update it again. This will have
clip code didn't modify the projection */ * no affect if the clip code didn't modify the projection */
_cogl_context_set_current_projection (ctx, state->projection_stack); projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer);
_cogl_context_set_current_projection_entry (ctx,
projection_stack->last_entry);
batch_and_call (batch_start, batch_and_call (batch_start,
batch_len, batch_len,
@ -749,97 +729,10 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */ _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
data); data);
_cogl_matrix_stack_pop (state->modelview_stack);
COGL_TIMER_STOP (_cogl_uprof_context, COGL_TIMER_STOP (_cogl_uprof_context,
time_flush_clip_stack_pipeline_entries); time_flush_clip_stack_pipeline_entries);
} }
static CoglBool
calculate_translation (const CoglMatrix *a,
const CoglMatrix *b,
float *tx_p,
float *ty_p)
{
float tx, ty;
int x, y;
/* Assuming we had the original matrix in this form:
*
* [ a, a, a, a ]
* [ a, a, a, a ]
* a = [ a, a, a, a ]
* [ a, a, a, a ]
*
* then a translation of that matrix would be a multiplication by a
* matrix of this form:
*
* [ 1, 0, 0, x ]
* [ 0, 1, 0, y ]
* t = [ 0, 0, 1, 0 ]
* [ 0, 0, 0, 1 ]
*
* That would give us a matrix of this form.
*
* [ a, a, a, a x + a y + a ]
* [ a, a, a, a x + a y + a ]
* b = a t = [ a, a, a, a x + a y + a ]
* [ a, a, a, a x + a y + a ]
*
* We can use the two equations from the top left of the matrix to
* work out the x and y translation given the two matrices:
*
* b = ax + ay + a
* b = ax + ay + a
*
* Rearranging gives us:
*
* a b - a a
* ----------------- + a - b
* a
* x = ---------------------------------
* a a
* ------- - a
* a
*
* b - ax - a
* y = ----------------
* a
*
* Once we've worked out what x and y would be if this was a valid
* translation then we can simply verify that the rest of the matrix
* matches up.
*/
/* The leftmost 3x4 part of the matrix shouldn't change by a
translation so we can just compare it directly */
for (y = 0; y < 4; y++)
for (x = 0; x < 3; x++)
if ((&a->xx)[x * 4 + y] != (&b->xx)[x * 4 + y])
return FALSE;
tx = (((a->xy * b->yw - a->yw * a->xy) / a->yy + a->xw - b->xw) /
((a->xy * a->yx) / a->yy - a->xx));
ty = (b->yw - a->yx * tx - a->yw) / a->yy;
#define APPROX_EQUAL(a, b) (fabsf ((a) - (b)) < 1e-6f)
/* Check whether the 4th column of the matrices match up to the
calculation */
if (!APPROX_EQUAL (b->xw, a->xx * tx + a->xy * ty + a->xw) ||
!APPROX_EQUAL (b->yw, a->yx * tx + a->yy * ty + a->yw) ||
!APPROX_EQUAL (b->zw, a->zx * tx + a->zy * ty + a->zw) ||
!APPROX_EQUAL (b->ww, a->wx * tx + a->wy * ty + a->ww))
return FALSE;
#undef APPROX_EQUAL
*tx_p = tx;
*ty_p = ty;
return TRUE;
}
typedef struct typedef struct
{ {
float x_1, y_1; float x_1, y_1;
@ -887,13 +780,15 @@ can_software_clip_entry (CoglJournalEntry *journal_entry,
{ {
float rect_x1, rect_y1, rect_x2, rect_y2; float rect_x1, rect_y1, rect_x2, rect_y2;
CoglClipStackRect *clip_rect; CoglClipStackRect *clip_rect;
float tx, ty; float tx, ty, tz;
CoglMatrixEntry *modelview_entry;
clip_rect = (CoglClipStackRect *) clip_entry; clip_rect = (CoglClipStackRect *) clip_entry;
if (!calculate_translation (&clip_rect->matrix, modelview_entry = journal_entry->modelview_entry;
&journal_entry->model_view, if (!_cogl_matrix_entry_calculate_translation (clip_rect->matrix_entry,
&tx, &ty)) modelview_entry,
&tx, &ty, &tz))
return FALSE; return FALSE;
if (clip_rect->x0 < clip_rect->x1) if (clip_rect->x0 < clip_rect->x1)
@ -1212,6 +1107,7 @@ upload_vertices (CoglJournal *journal,
else else
{ {
float v[8]; float v[8];
CoglMatrix modelview;
v[0] = vin[0]; v[0] = vin[0];
v[1] = vin[1]; v[1] = vin[1];
@ -1222,7 +1118,8 @@ upload_vertices (CoglJournal *journal,
v[6] = vin[array_stride]; v[6] = vin[array_stride];
v[7] = vin[1]; v[7] = vin[1];
cogl_matrix_transform_points (&entry->model_view, _cogl_matrix_entry_get (entry->modelview_entry, &modelview);
cogl_matrix_transform_points (&modelview,
2, /* n_components */ 2, /* n_components */
sizeof (float) * 2, /* stride_in */ sizeof (float) * 2, /* stride_in */
v, /* points_in */ v, /* points_in */
@ -1269,6 +1166,7 @@ _cogl_journal_discard (CoglJournal *journal)
CoglJournalEntry *entry = CoglJournalEntry *entry =
&g_array_index (journal->entries, CoglJournalEntry, i); &g_array_index (journal->entries, CoglJournalEntry, i);
_cogl_pipeline_journal_unref (entry->pipeline); _cogl_pipeline_journal_unref (entry->pipeline);
_cogl_matrix_entry_unref (entry->modelview_entry);
_cogl_clip_stack_unref (entry->clip_stack); _cogl_clip_stack_unref (entry->clip_stack);
} }
@ -1357,25 +1255,27 @@ _cogl_journal_all_entries_within_bounds (CoglJournal *journal,
void void
_cogl_journal_flush (CoglJournal *journal) _cogl_journal_flush (CoglJournal *journal)
{ {
CoglFramebuffer *framebuffer;
CoglContext *ctx;
CoglJournalFlushState state; CoglJournalFlushState state;
int i; int i;
CoglMatrixStack *modelview_stack;
COGL_STATIC_TIMER (flush_timer, COGL_STATIC_TIMER (flush_timer,
"Mainloop", /* parent */ "Mainloop", /* parent */
"Journal Flush", "Journal Flush",
"The time spent flushing the Cogl journal", "The time spent flushing the Cogl journal",
0 /* no application private data */); 0 /* no application private data */);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (journal->entries->len == 0) if (journal->entries->len == 0)
return; return;
framebuffer = journal->framebuffer;
ctx = framebuffer->context;
/* The entries in this journal may depend on images in other /* The entries in this journal may depend on images in other
* framebuffers which may require that we flush the journals * framebuffers which may require that we flush the journals
* associated with those framebuffers before we can flush * associated with those framebuffers before we can flush
* this journal... */ * this journal... */
_cogl_framebuffer_flush_dependency_journals (journal->framebuffer); _cogl_framebuffer_flush_dependency_journals (framebuffer);
/* Note: we start the timer after flushing dependency journals so /* Note: we start the timer after flushing dependency journals so
* that the timer isn't started recursively. */ * that the timer isn't started recursively. */
@ -1386,8 +1286,8 @@ _cogl_journal_flush (CoglJournal *journal)
/* NB: the journal deals with flushing the modelview stack and clip /* NB: the journal deals with flushing the modelview stack and clip
state manually */ state manually */
_cogl_framebuffer_flush_state (journal->framebuffer, _cogl_framebuffer_flush_state (framebuffer,
journal->framebuffer, framebuffer,
COGL_FRAMEBUFFER_STATE_ALL & COGL_FRAMEBUFFER_STATE_ALL &
~(COGL_FRAMEBUFFER_STATE_MODELVIEW | ~(COGL_FRAMEBUFFER_STATE_MODELVIEW |
COGL_FRAMEBUFFER_STATE_CLIP)); COGL_FRAMEBUFFER_STATE_CLIP));
@ -1396,12 +1296,6 @@ _cogl_journal_flush (CoglJournal *journal)
state.attributes = ctx->journal_flush_attributes_array; state.attributes = ctx->journal_flush_attributes_array;
modelview_stack =
_cogl_framebuffer_get_modelview_stack (journal->framebuffer);
state.modelview_stack = modelview_stack;
state.projection_stack =
_cogl_framebuffer_get_projection_stack (journal->framebuffer);
if (G_UNLIKELY ((COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_CLIP)) == 0)) if (G_UNLIKELY ((COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_CLIP)) == 0))
{ {
/* We do an initial walk of the journal to analyse the clip stack /* We do an initial walk of the journal to analyse the clip stack
@ -1502,6 +1396,7 @@ _cogl_journal_log_quad (CoglJournal *journal,
CoglPipeline *final_pipeline; CoglPipeline *final_pipeline;
CoglClipStack *clip_stack; CoglClipStack *clip_stack;
CoglPipelineFlushOptions flush_options; CoglPipelineFlushOptions flush_options;
CoglMatrixStack *modelview_stack;
COGL_STATIC_TIMER (log_timer, COGL_STATIC_TIMER (log_timer,
"Mainloop", /* parent */ "Mainloop", /* parent */
"Journal Log", "Journal Log",
@ -1599,8 +1494,9 @@ _cogl_journal_log_quad (CoglJournal *journal,
if (G_UNLIKELY (final_pipeline != pipeline)) if (G_UNLIKELY (final_pipeline != pipeline))
cogl_object_unref (final_pipeline); cogl_object_unref (final_pipeline);
cogl_framebuffer_get_modelview_matrix (framebuffer, modelview_stack =
&entry->model_view); _cogl_framebuffer_get_modelview_stack (framebuffer);
entry->modelview_entry = _cogl_matrix_entry_ref (modelview_stack->last_entry);
_cogl_pipeline_foreach_layer_internal (pipeline, _cogl_pipeline_foreach_layer_internal (pipeline,
add_framebuffer_deps_cb, add_framebuffer_deps_cb,
@ -1622,6 +1518,7 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers); GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers);
CoglMatrixStack *projection_stack; CoglMatrixStack *projection_stack;
CoglMatrix projection; CoglMatrix projection;
CoglMatrix modelview;
int i; int i;
float viewport[4]; float viewport[4];
@ -1649,7 +1546,8 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
* _cogl_transform_points utility... * _cogl_transform_points utility...
*/ */
cogl_matrix_transform_points (&entry->model_view, _cogl_matrix_entry_get (entry->modelview_entry, &modelview);
cogl_matrix_transform_points (&modelview,
2, /* n_components */ 2, /* n_components */
sizeof (float) * 4, /* stride_in */ sizeof (float) * 4, /* stride_in */
poly, /* points_in */ poly, /* points_in */

View File

@ -41,6 +41,13 @@ G_BEGIN_DECLS
void void
_cogl_matrix_print (const CoglMatrix *matrix); _cogl_matrix_print (const CoglMatrix *matrix);
void
_cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix);
void
_cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix,
const CoglMatrix *src);
G_END_DECLS G_END_DECLS
#endif /* __COGL_MATRIX_PRIVATE_H */ #endif /* __COGL_MATRIX_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
* *
* An object oriented GL/GLES Abstraction/Utility Layer * An object oriented GL/GLES Abstraction/Utility Layer
* *
* Copyright (C) 2009,2010 Intel Corporation. * Copyright (C) 2009,2010,2012 Intel Corporation.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -29,29 +29,114 @@
#ifndef __COGL_MATRIX_STACK_H #ifndef __COGL_MATRIX_STACK_H
#define __COGL_MATRIX_STACK_H #define __COGL_MATRIX_STACK_H
#include "cogl-object-private.h"
#include "cogl-matrix.h" #include "cogl-matrix.h"
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-framebuffer.h"
typedef struct _CoglMatrixStack CoglMatrixStack; typedef enum _CoglMatrixOp
typedef struct
{ {
CoglMatrixStack *stack; COGL_MATRIX_OP_LOAD_IDENTITY,
unsigned int age; COGL_MATRIX_OP_TRANSLATE,
COGL_MATRIX_OP_ROTATE,
COGL_MATRIX_OP_SCALE,
COGL_MATRIX_OP_MULTIPLY,
COGL_MATRIX_OP_LOAD,
COGL_MATRIX_OP_SAVE,
} CoglMatrixOp;
typedef struct _CoglMatrixEntry CoglMatrixEntry;
struct _CoglMatrixEntry
{
CoglMatrixOp op;
CoglMatrixEntry *parent;
unsigned int ref_count;
/* used for performance tracing */
int composite_gets;
};
typedef struct _CoglMatrixEntryTranslate
{
CoglMatrixEntry _parent_data;
float x;
float y;
float z;
} CoglMatrixEntryTranslate;
typedef struct _CoglMatrixEntryRotate
{
CoglMatrixEntry _parent_data;
float angle;
float x;
float y;
float z;
} CoglMatrixEntryRotate;
typedef struct _CoglMatrixEntryScale
{
CoglMatrixEntry _parent_data;
float x;
float y;
float z;
} CoglMatrixEntryScale;
typedef struct _CoglMatrixEntryMultiply
{
CoglMatrixEntry _parent_data;
CoglMatrix *matrix;
} CoglMatrixEntryMultiply;
typedef struct _CoglMatrixEntryLoad
{
CoglMatrixEntry _parent_data;
CoglMatrix *matrix;
} CoglMatrixEntryLoad;
typedef struct _CoglMatrixEntrySave
{
CoglMatrixEntry _parent_data;
CoglBool cache_valid;
CoglMatrix *cache;
} CoglMatrixEntrySave;
typedef union _CoglMatrixEntryFull
{
CoglMatrixEntry any;
CoglMatrixEntryTranslate translate;
CoglMatrixEntryRotate rotae;
CoglMatrixEntryScale scale;
CoglMatrixEntryMultiply multiply;
CoglMatrixEntryLoad load;
CoglMatrixEntrySave save;
} CoglMatrixEntryFull;
typedef struct _CoglMatrixStack
{
CoglObject _parent;
CoglMatrixEntry *last_entry;
} CoglMatrixStack;
typedef struct _CoglMatrixEntryCache
{
CoglMatrixEntry *entry;
CoglBool flushed_identity; CoglBool flushed_identity;
CoglBool flipped; CoglBool flipped;
} CoglMatrixStackCache; } CoglMatrixEntryCache;
typedef enum {
COGL_MATRIX_MODELVIEW,
COGL_MATRIX_PROJECTION,
COGL_MATRIX_TEXTURE
} CoglMatrixMode;
typedef void (* CoglMatrixStackFlushFunc) (CoglContext *context,
CoglBool is_identity,
const CoglMatrix *matrix,
void *user_data);
CoglMatrixStack * CoglMatrixStack *
_cogl_matrix_stack_new (void); _cogl_matrix_stack_new (void);
@ -62,6 +147,9 @@ _cogl_matrix_stack_push (CoglMatrixStack *stack);
void void
_cogl_matrix_stack_pop (CoglMatrixStack *stack); _cogl_matrix_stack_pop (CoglMatrixStack *stack);
void
_cogl_matrix_entry_identity_init (CoglMatrixEntry *entry);
void void
_cogl_matrix_stack_load_identity (CoglMatrixStack *stack); _cogl_matrix_stack_load_identity (CoglMatrixStack *stack);
@ -99,53 +187,89 @@ _cogl_matrix_stack_perspective (CoglMatrixStack *stack,
float z_near, float z_near,
float z_far); float z_far);
void void
_cogl_matrix_stack_ortho (CoglMatrixStack *stack, _cogl_matrix_stack_orthographic (CoglMatrixStack *stack,
float left, float x_1,
float right, float y_1,
float bottom, float x_2,
float top, float y_2,
float z_near, float near,
float z_far); float far);
CoglBool CoglBool
_cogl_matrix_stack_get_inverse (CoglMatrixStack *stack, _cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
CoglMatrix *inverse); CoglMatrix *inverse);
void
/* NB: This function only *sometimes* returns a pointer to a matrix if
* the matrix returned didn't need to be composed of multiple
* operations */
CoglMatrix *
_cogl_matrix_stack_get (CoglMatrixStack *stack, _cogl_matrix_stack_get (CoglMatrixStack *stack,
CoglMatrix *matrix); CoglMatrix *matrix);
/* NB: This function only *sometimes* returns a pointer to a matrix if
* the matrix returned didn't need to be composed of multiple
* operations */
CoglMatrix *
_cogl_matrix_entry_get (CoglMatrixEntry *entry,
CoglMatrix *matrix);
void void
_cogl_matrix_stack_set (CoglMatrixStack *stack, _cogl_matrix_stack_set (CoglMatrixStack *stack,
const CoglMatrix *matrix); const CoglMatrix *matrix);
CoglBool
_cogl_matrix_entry_calculate_translation (CoglMatrixEntry *entry0,
CoglMatrixEntry *entry1,
float *x,
float *y,
float *z);
/* If this returns TRUE then the entry is definitely the identity
* matrix. If it returns FALSE it may or may not be the identity
* matrix but no expensive comparison is performed to verify it. */
CoglBool
_cogl_matrix_entry_has_identity_flag (CoglMatrixEntry *entry);
CoglBool
_cogl_matrix_entry_fast_equal (CoglMatrixEntry *entry0,
CoglMatrixEntry *entry1);
CoglBool
_cogl_matrix_entry_equal (CoglMatrixEntry *entry0,
CoglMatrixEntry *entry1);
void void
_cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx, _cogl_matrix_entry_print (CoglMatrixEntry *entry);
CoglMatrixStack *stack,
CoglMatrixEntry *
_cogl_matrix_entry_ref (CoglMatrixEntry *entry);
void
_cogl_matrix_entry_unref (CoglMatrixEntry *entry);
typedef enum {
COGL_MATRIX_MODELVIEW,
COGL_MATRIX_PROJECTION,
COGL_MATRIX_TEXTURE
} CoglMatrixMode;
void
_cogl_matrix_entry_flush_to_gl_builtins (CoglContext *ctx,
CoglMatrixEntry *entry,
CoglMatrixMode mode, CoglMatrixMode mode,
CoglFramebuffer *framebuffer,
CoglBool disable_flip); CoglBool disable_flip);
unsigned int
_cogl_matrix_stack_get_age (CoglMatrixStack *stack);
/* If this returns TRUE then the top of the matrix is definitely the
identity matrix. If it returns FALSE it may or may not be the
identity matrix but no expensive comparison is performed to verify
it. */
CoglBool
_cogl_matrix_stack_has_identity_flag (CoglMatrixStack *stack);
CoglBool
_cogl_matrix_stack_equal (CoglMatrixStack *stack0,
CoglMatrixStack *stack1);
void void
_cogl_matrix_stack_init_cache (CoglMatrixStackCache *cache); _cogl_matrix_entry_cache_init (CoglMatrixEntryCache *cache);
CoglBool CoglBool
_cogl_matrix_stack_check_and_update_cache (CoglMatrixStack *stack, _cogl_matrix_entry_cache_maybe_update (CoglMatrixEntryCache *cache,
CoglMatrixStackCache *cache, CoglMatrixEntry *entry,
CoglBool flip); CoglBool flip);
void void
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache); _cogl_matrix_entry_cache_destroy (CoglMatrixEntryCache *cache);
CoglBool CoglBool
_cogl_is_matrix_stack (void *object); _cogl_is_matrix_stack (void *object);

View File

@ -360,11 +360,38 @@ _cogl_matrix_multiply_array (CoglMatrix *result, const float *array)
* Called by _cogl_matrix_print() to print a matrix or its inverse. * Called by _cogl_matrix_print() to print a matrix or its inverse.
*/ */
static void static void
print_matrix_floats (const float m[16]) print_matrix_floats (const char *prefix, const float m[16])
{ {
int i; int i;
for (i = 0;i < 4; i++) for (i = 0;i < 4; i++)
g_print ("\t%f %f %f %f\n", m[i], m[4+i], m[8+i], m[12+i] ); g_print ("%s\t%f %f %f %f\n", prefix, m[i], m[4+i], m[8+i], m[12+i] );
}
void
_cogl_matrix_prefix_print (const char *prefix, const CoglMatrix *matrix)
{
if (!(matrix->flags & MAT_DIRTY_TYPE))
{
_COGL_RETURN_IF_FAIL (matrix->type < COGL_MATRIX_N_TYPES);
g_print ("%sMatrix type: %s, flags: %x\n",
prefix, types[matrix->type], (int)matrix->flags);
}
else
g_print ("%sMatrix type: DIRTY, flags: %x\n",
prefix, (int)matrix->flags);
print_matrix_floats (prefix, (float *)matrix);
g_print ("%sInverse: \n", prefix);
if (!(matrix->flags & MAT_DIRTY_INVERSE))
{
float prod[16];
print_matrix_floats (prefix, matrix->inv);
matrix_multiply4x4 (prod, (float *)matrix, matrix->inv);
g_print ("%sMat * Inverse:\n", prefix);
print_matrix_floats (prefix, prod);
}
else
g_print ("%s - not available\n", prefix);
} }
/* /*
@ -373,27 +400,7 @@ print_matrix_floats (const float m[16])
void void
_cogl_matrix_print (const CoglMatrix *matrix) _cogl_matrix_print (const CoglMatrix *matrix)
{ {
if (!(matrix->flags & MAT_DIRTY_TYPE)) _cogl_matrix_prefix_print ("", matrix);
{
_COGL_RETURN_IF_FAIL (matrix->type < COGL_MATRIX_N_TYPES);
g_print ("Matrix type: %s, flags: %x\n",
types[matrix->type], (int)matrix->flags);
}
else
g_print ("Matrix type: DIRTY, flags: %x\n", (int)matrix->flags);
print_matrix_floats ((float *)matrix);
g_print ("Inverse: \n");
if (!(matrix->flags & MAT_DIRTY_INVERSE))
{
float prod[16];
print_matrix_floats (matrix->inv);
matrix_multiply4x4 (prod, (float *)matrix, matrix->inv);
g_print ("Mat * Inverse:\n");
print_matrix_floats (prod);
}
else
g_print (" - not available\n");
} }
/* /*
@ -1659,6 +1666,15 @@ cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
_COGL_MATRIX_DEBUG_PRINT (matrix); _COGL_MATRIX_DEBUG_PRINT (matrix);
} }
void
_cogl_matrix_init_from_matrix_without_inverse (CoglMatrix *matrix,
const CoglMatrix *src)
{
memcpy (matrix, src, 16 * sizeof (float));
matrix->type = src->type;
matrix->flags = src->flags | MAT_DIRTY_INVERSE;
}
static void static void
_cogl_matrix_init_from_quaternion (CoglMatrix *matrix, _cogl_matrix_init_from_quaternion (CoglMatrix *matrix,
CoglQuaternion *quaternion) CoglQuaternion *quaternion)

View File

@ -143,6 +143,7 @@ _cogl_delete_gl_texture (GLuint gl_texture);
void void
_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer,
CoglBool skip_gl_state, CoglBool skip_gl_state,
int n_tex_coord_attribs); int n_tex_coord_attribs);

View File

@ -1056,8 +1056,6 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
CoglPipeline *pipeline = state->pipeline; CoglPipeline *pipeline = state->pipeline;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer); int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
_COGL_GET_CONTEXT (ctx, FALSE);
/* Either generate per layer code snippets or setup the /* Either generate per layer code snippets or setup the
* fixed function glTexEnv for each layer... */ * fixed function glTexEnv for each layer... */
if (G_LIKELY (fragend->add_layer (pipeline, if (G_LIKELY (fragend->add_layer (pipeline,
@ -1075,6 +1073,7 @@ fragend_add_layer_cb (CoglPipelineLayer *layer,
typedef struct typedef struct
{ {
CoglFramebuffer *framebuffer;
const CoglPipelineVertend *vertend; const CoglPipelineVertend *vertend;
CoglPipeline *pipeline; CoglPipeline *pipeline;
unsigned long *layer_differences; unsigned long *layer_differences;
@ -1092,13 +1091,12 @@ vertend_add_layer_cb (CoglPipelineLayer *layer,
CoglPipeline *pipeline = state->pipeline; CoglPipeline *pipeline = state->pipeline;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer); int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
_COGL_GET_CONTEXT (ctx, FALSE);
/* Either enerate per layer code snippets or setup the /* Either enerate per layer code snippets or setup the
* fixed function matrix uniforms for each layer... */ * fixed function matrix uniforms for each layer... */
if (G_LIKELY (vertend->add_layer (pipeline, if (G_LIKELY (vertend->add_layer (pipeline,
layer, layer,
state->layer_differences[unit_index]))) state->layer_differences[unit_index],
state->framebuffer)))
state->added_layer = TRUE; state->added_layer = TRUE;
else else
{ {
@ -1161,6 +1159,7 @@ vertend_add_layer_cb (CoglPipelineLayer *layer,
*/ */
void void
_cogl_pipeline_flush_gl_state (CoglPipeline *pipeline, _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer,
CoglBool skip_gl_color, CoglBool skip_gl_color,
int n_tex_coord_attribs) int n_tex_coord_attribs)
{ {
@ -1330,6 +1329,7 @@ _cogl_pipeline_flush_gl_state (CoglPipeline *pipeline,
n_tex_coord_attribs))) n_tex_coord_attribs)))
continue; continue;
state.framebuffer = framebuffer;
state.vertend = vertend; state.vertend = vertend;
state.pipeline = pipeline; state.pipeline = pipeline;
state.layer_differences = layer_differences; state.layer_differences = layer_differences;
@ -1407,7 +1407,7 @@ done:
matrices */ matrices */
for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++) for (i = 0; i < COGL_PIPELINE_N_PROGENDS; i++)
if (_cogl_pipeline_progends[i]->pre_paint) if (_cogl_pipeline_progends[i]->pre_paint)
_cogl_pipeline_progends[i]->pre_paint (pipeline); _cogl_pipeline_progends[i]->pre_paint (pipeline, framebuffer);
/* Handle the fact that OpenGL associates texture filter and wrap /* Handle the fact that OpenGL associates texture filter and wrap
* modes with the texture objects not the texture units... */ * modes with the texture objects not the texture units... */

View File

@ -39,6 +39,7 @@
#include "cogl-boxed-value.h" #include "cogl-boxed-value.h"
#include "cogl-pipeline-snippet-private.h" #include "cogl-pipeline-snippet-private.h"
#include "cogl-pipeline-state.h" #include "cogl-pipeline-state.h"
#include "cogl-framebuffer.h"
#include <glib.h> #include <glib.h>
@ -583,7 +584,8 @@ typedef struct _CoglPipelineVertend
int n_tex_coord_attribs); int n_tex_coord_attribs);
CoglBool (*add_layer) (CoglPipeline *pipeline, CoglBool (*add_layer) (CoglPipeline *pipeline,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
unsigned long layers_difference); unsigned long layers_difference,
CoglFramebuffer *framebuffer);
CoglBool (*end) (CoglPipeline *pipeline, CoglBool (*end) (CoglPipeline *pipeline,
unsigned long pipelines_difference); unsigned long pipelines_difference);
@ -609,7 +611,7 @@ typedef struct
/* This is called after all of the other functions whenever the /* This is called after all of the other functions whenever the
pipeline is flushed, even if the pipeline hasn't changed since pipeline is flushed, even if the pipeline hasn't changed since
the last flush */ the last flush */
void (* pre_paint) (CoglPipeline *pipeline); void (* pre_paint) (CoglPipeline *pipeline, CoglFramebuffer *framebuffer);
} CoglPipelineProgend; } CoglPipelineProgend;
typedef enum typedef enum

View File

@ -37,24 +37,28 @@
#include "cogl-context.h" #include "cogl-context.h"
#include "cogl-context-private.h" #include "cogl-context-private.h"
#include "cogl-framebuffer-private.h"
static void static void
_cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline) _cogl_pipeline_progend_fixed_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer)
{ {
_COGL_GET_CONTEXT (ctx, NO_RETVAL); CoglContext *ctx = framebuffer->context;
if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED) if (pipeline->vertend != COGL_PIPELINE_VERTEND_FIXED)
return; return;
if (ctx->current_projection_stack) if (ctx->current_projection_entry)
_cogl_matrix_stack_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_projection_stack, ctx->current_projection_entry,
COGL_MATRIX_PROJECTION, COGL_MATRIX_PROJECTION,
framebuffer,
FALSE /* enable flip */); FALSE /* enable flip */);
if (ctx->current_modelview_stack) if (ctx->current_modelview_entry)
_cogl_matrix_stack_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_modelview_stack, ctx->current_modelview_entry,
COGL_MATRIX_MODELVIEW, COGL_MATRIX_MODELVIEW,
framebuffer,
FALSE /* enable flip */); FALSE /* enable flip */);
} }

View File

@ -123,8 +123,8 @@ typedef struct
GLint projection_uniform; GLint projection_uniform;
GLint mvp_uniform; GLint mvp_uniform;
CoglMatrixStackCache projection_cache; CoglMatrixEntryCache projection_cache;
CoglMatrixStackCache modelview_cache; CoglMatrixEntryCache modelview_cache;
#endif #endif
/* We need to track the last pipeline that the program was used with /* We need to track the last pipeline that the program was used with
@ -231,10 +231,10 @@ clear_attribute_cache (CoglPipelineProgramState *program_state)
static void static void
clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state) clear_flushed_matrix_stacks (CoglPipelineProgramState *program_state)
{ {
_cogl_matrix_stack_destroy_cache (&program_state->projection_cache); _cogl_matrix_entry_cache_destroy (&program_state->projection_cache);
_cogl_matrix_stack_init_cache (&program_state->projection_cache); _cogl_matrix_entry_cache_init (&program_state->projection_cache);
_cogl_matrix_stack_destroy_cache (&program_state->modelview_cache); _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache);
_cogl_matrix_stack_init_cache (&program_state->modelview_cache); _cogl_matrix_entry_cache_init (&program_state->modelview_cache);
} }
#endif /* HAVE_COGL_GLES2 */ #endif /* HAVE_COGL_GLES2 */
@ -252,8 +252,8 @@ program_state_new (int n_layers)
program_state->uniform_locations = NULL; program_state->uniform_locations = NULL;
program_state->attribute_locations = NULL; program_state->attribute_locations = NULL;
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
_cogl_matrix_stack_init_cache (&program_state->modelview_cache); _cogl_matrix_entry_cache_init (&program_state->modelview_cache);
_cogl_matrix_stack_init_cache (&program_state->projection_cache); _cogl_matrix_entry_cache_init (&program_state->projection_cache);
#endif #endif
return program_state; return program_state;
@ -281,8 +281,8 @@ destroy_program_state (void *user_data,
#ifdef HAVE_COGL_GLES2 #ifdef HAVE_COGL_GLES2
if (ctx->driver == COGL_DRIVER_GLES2) if (ctx->driver == COGL_DRIVER_GLES2)
{ {
_cogl_matrix_stack_destroy_cache (&program_state->projection_cache); _cogl_matrix_entry_cache_destroy (&program_state->projection_cache);
_cogl_matrix_stack_destroy_cache (&program_state->modelview_cache); _cogl_matrix_entry_cache_destroy (&program_state->modelview_cache);
} }
#endif #endif
@ -929,11 +929,12 @@ _cogl_pipeline_progend_glsl_layer_pre_change_notify (
} }
static void static void
_cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline) _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline,
CoglFramebuffer *framebuffer)
{ {
CoglBool needs_flip; CoglBool needs_flip;
CoglMatrixStack *projection_stack; CoglMatrixEntry *projection_entry;
CoglMatrixStack *modelview_stack; CoglMatrixEntry *modelview_entry;
CoglPipelineProgramState *program_state; CoglPipelineProgramState *program_state;
_COGL_GET_CONTEXT (ctx, NO_RETVAL); _COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -943,13 +944,13 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
program_state = get_program_state (pipeline); program_state = get_program_state (pipeline);
projection_stack = ctx->current_projection_stack; projection_entry = ctx->current_projection_entry;
modelview_stack = ctx->current_modelview_stack; modelview_entry = ctx->current_modelview_entry;
/* An initial pipeline is flushed while creating the context. At /* An initial pipeline is flushed while creating the context. At
this point there are no matrices selected so we can't do this point there are no matrices selected so we can't do
anything */ anything */
if (modelview_stack == NULL || projection_stack == NULL) if (modelview_entry == NULL || projection_entry == NULL)
return; return;
needs_flip = cogl_is_offscreen (ctx->current_draw_buffer); needs_flip = cogl_is_offscreen (ctx->current_draw_buffer);
@ -964,17 +965,15 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
CoglMatrix modelview, projection; CoglMatrix modelview, projection;
projection_changed = projection_changed =
_cogl_matrix_stack_check_and_update_cache (projection_stack, _cogl_matrix_entry_cache_maybe_update (&program_state->projection_cache,
&program_state-> projection_entry,
projection_cache, (needs_flip &&
needs_flip && program_state->flip_uniform ==
program_state-> -1));
flip_uniform == -1);
modelview_changed = modelview_changed =
_cogl_matrix_stack_check_and_update_cache (modelview_stack, _cogl_matrix_entry_cache_maybe_update (&program_state->modelview_cache,
&program_state-> modelview_entry,
modelview_cache,
/* never flip modelview */ /* never flip modelview */
FALSE); FALSE);
@ -991,19 +990,19 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
} }
if (need_modelview) if (need_modelview)
_cogl_matrix_stack_get (modelview_stack, &modelview); _cogl_matrix_entry_get (modelview_entry, &modelview);
if (need_projection) if (need_projection)
{ {
if (needs_flip && program_state->flip_uniform == -1) if (needs_flip && program_state->flip_uniform == -1)
{ {
CoglMatrix tmp_matrix; CoglMatrix tmp_matrix;
_cogl_matrix_stack_get (projection_stack, &tmp_matrix); _cogl_matrix_entry_get (projection_entry, &tmp_matrix);
cogl_matrix_multiply (&projection, cogl_matrix_multiply (&projection,
&ctx->y_flip_matrix, &ctx->y_flip_matrix,
&tmp_matrix); &tmp_matrix);
} }
else else
_cogl_matrix_stack_get (projection_stack, &projection); _cogl_matrix_entry_get (projection_entry, &projection);
} }
if (projection_changed && program_state->projection_uniform != -1) if (projection_changed && program_state->projection_uniform != -1)
@ -1023,7 +1022,7 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
/* The journal usually uses an identity matrix for the /* The journal usually uses an identity matrix for the
modelview so we can optimise this common case by modelview so we can optimise this common case by
avoiding the matrix multiplication */ avoiding the matrix multiplication */
if (_cogl_matrix_stack_has_identity_flag (modelview_stack)) if (_cogl_matrix_entry_has_identity_flag (modelview_entry))
{ {
GE (ctx, GE (ctx,
glUniformMatrix4fv (program_state->mvp_uniform, glUniformMatrix4fv (program_state->mvp_uniform,
@ -1056,13 +1055,15 @@ _cogl_pipeline_progend_glsl_pre_paint (CoglPipeline *pipeline)
geometry via the matrix and use the flip vertex instead */ geometry via the matrix and use the flip vertex instead */
disable_flip = program_state->flip_uniform != -1; disable_flip = program_state->flip_uniform != -1;
_cogl_matrix_stack_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
projection_stack, projection_entry,
COGL_MATRIX_PROJECTION, COGL_MATRIX_PROJECTION,
framebuffer,
disable_flip); disable_flip);
_cogl_matrix_stack_flush_to_gl_builtins (ctx, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
modelview_stack, modelview_entry,
COGL_MATRIX_MODELVIEW, COGL_MATRIX_MODELVIEW,
framebuffer,
disable_flip); disable_flip);
} }

View File

@ -33,6 +33,7 @@
#include "cogl-pipeline-private.h" #include "cogl-pipeline-private.h"
#include "cogl-pipeline-state-private.h" #include "cogl-pipeline-state-private.h"
#include "cogl-pipeline-opengl-private.h" #include "cogl-pipeline-opengl-private.h"
#include "cogl-framebuffer-private.h"
#ifdef COGL_PIPELINE_VERTEND_FIXED #ifdef COGL_PIPELINE_VERTEND_FIXED
@ -80,26 +81,29 @@ _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
static CoglBool static CoglBool
_cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline, _cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
unsigned long layers_difference) unsigned long layers_difference,
CoglFramebuffer *framebuffer)
{ {
CoglContext *ctx = framebuffer->context;
int unit_index = _cogl_pipeline_layer_get_unit_index (layer); int unit_index = _cogl_pipeline_layer_get_unit_index (layer);
CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index); CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index);
_COGL_GET_CONTEXT (ctx, FALSE);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX) if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{ {
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX; CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
CoglPipelineLayer *authority = CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state); _cogl_pipeline_layer_get_authority (layer, state);
CoglMatrixEntry *matrix_entry;
_cogl_matrix_stack_set (unit->matrix_stack, _cogl_matrix_stack_set (unit->matrix_stack,
&authority->big_state->matrix); &authority->big_state->matrix);
_cogl_set_active_texture_unit (unit_index); _cogl_set_active_texture_unit (unit_index);
_cogl_matrix_stack_flush_to_gl_builtins (ctx, unit->matrix_stack, matrix_entry = unit->matrix_stack->last_entry;
_cogl_matrix_entry_flush_to_gl_builtins (ctx, matrix_entry,
COGL_MATRIX_TEXTURE, COGL_MATRIX_TEXTURE,
framebuffer,
FALSE /* enable flip */); FALSE /* enable flip */);
} }

View File

@ -287,7 +287,8 @@ _cogl_pipeline_vertend_glsl_start (CoglPipeline *pipeline,
static CoglBool static CoglBool
_cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline, _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *layer, CoglPipelineLayer *layer,
unsigned long layers_difference) unsigned long layers_difference,
CoglFramebuffer *framebuffer)
{ {
CoglPipelineShaderState *shader_state; CoglPipelineShaderState *shader_state;
CoglPipelineSnippetData snippet_data; CoglPipelineSnippetData snippet_data;
@ -310,15 +311,18 @@ _cogl_pipeline_vertend_glsl_add_layer (CoglPipeline *pipeline,
CoglPipelineLayer *authority = CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state); _cogl_pipeline_layer_get_authority (layer, state);
CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index); CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index);
CoglMatrixEntry *matrix_entry;
_cogl_matrix_stack_set (unit->matrix_stack, _cogl_matrix_stack_set (unit->matrix_stack,
&authority->big_state->matrix); &authority->big_state->matrix);
_cogl_set_active_texture_unit (unit_index); _cogl_set_active_texture_unit (unit_index);
_cogl_matrix_stack_flush_to_gl_builtins (ctx, matrix_entry = unit->matrix_stack->last_entry;
unit->matrix_stack, _cogl_matrix_entry_flush_to_gl_builtins (ctx,
matrix_entry,
COGL_MATRIX_TEXTURE, COGL_MATRIX_TEXTURE,
framebuffer,
FALSE /* do flip */); FALSE /* do flip */);
} }
} }

View File

@ -441,6 +441,7 @@ cogl_begin_gl (void)
*/ */
pipeline = cogl_get_source (); pipeline = cogl_get_source ();
_cogl_pipeline_flush_gl_state (pipeline, _cogl_pipeline_flush_gl_state (pipeline,
cogl_get_draw_framebuffer (),
FALSE, FALSE,
cogl_pipeline_get_n_layers (pipeline)); cogl_pipeline_get_n_layers (pipeline));