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_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_texcoord_attributes_tmp);

View File

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

View File

@ -28,6 +28,7 @@
#include "cogl-matrix.h"
#include "cogl-primitive.h"
#include "cogl-framebuffer.h"
#include "cogl-matrix-stack.h"
/* 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
@ -112,13 +113,13 @@ struct _CoglClipStack
struct _CoglClipStackRect
{
CoglClipStack _parent_data;
CoglClipStack _parent_data;
/* The rectangle for this clip */
float x0;
float y0;
float x1;
float y1;
float x0;
float y0;
float x1;
float y1;
/* If this is true then the clip for this rectangle is entirely
described by the scissor bounds. This implies that the rectangle
@ -128,15 +129,15 @@ struct _CoglClipStackRect
modelview matrix is that same as when a rectangle is added to the
journal. In that case we can use the original clip coordinates
and modify the rectangle instead. */
CoglBool can_be_scissor;
CoglBool can_be_scissor;
/* The matrix that was current when the clip was set */
CoglMatrix matrix;
CoglMatrixEntry *matrix_entry;
};
struct _CoglClipStackWindowRect
{
CoglClipStack _parent_data;
CoglClipStack _parent_data;
/* The window rect clip doesn't need any specific data because it
just adds to the scissor clip */
@ -144,12 +145,12 @@ struct _CoglClipStackWindowRect
struct _CoglClipStackPath
{
CoglClipStack _parent_data;
CoglClipStack _parent_data;
/* The matrix that was current when the clip was set */
CoglMatrix matrix;
CoglMatrixEntry *matrix_entry;
CoglPath *path;
CoglPath *path;
};
struct _CoglClipStackPrimitive
@ -157,7 +158,7 @@ struct _CoglClipStackPrimitive
CoglClipStack _parent_data;
/* The matrix that was current when the clip was set */
CoglMatrix matrix;
CoglMatrixEntry *matrix_entry;
CoglPrimitive *primitive;
@ -180,12 +181,16 @@ _cogl_clip_stack_push_rectangle (CoglClipStack *stack,
float y_1,
float x_2,
float y_2,
const CoglMatrix *modelview_matrix);
CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack *
_cogl_clip_stack_push_from_path (CoglClipStack *stack,
CoglPath *path,
const CoglMatrix *modelview_matrix);
CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack *
_cogl_clip_stack_push_primitive (CoglClipStack *stack,
@ -194,7 +199,9 @@ _cogl_clip_stack_push_primitive (CoglClipStack *stack,
float bounds_y1,
float bounds_x2,
float bounds_y2,
const CoglMatrix *modelview_matrix);
CoglMatrixEntry *modelview_entry,
CoglMatrixEntry *projection_entry,
const float *viewport);
CoglClipStack *
_cogl_clip_stack_pop (CoglClipStack *stack);

View File

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

View File

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

View File

@ -185,3 +185,8 @@ OPT (CLIPPING,
"clipping",
N_("Trace 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 },
{ "bitmap", COGL_DEBUG_BITMAP },
{ "clipping", COGL_DEBUG_CLIPPING },
{ "winsys", COGL_DEBUG_WINSYS }
{ "winsys", COGL_DEBUG_WINSYS },
{ "performance", COGL_DEBUG_PERFORMANCE }
};
static const int n_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_CLIPPING,
COGL_DEBUG_WINSYS,
COGL_DEBUG_PERFORMANCE,
COGL_DEBUG_N_FLAGS
} 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
_cogl_framebuffer_flush_modelview_state (CoglFramebuffer *framebuffer)
{
_cogl_context_set_current_modelview (framebuffer->context,
framebuffer->modelview_stack);
CoglMatrixEntry *modelview_entry =
_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
_cogl_framebuffer_flush_projection_state (CoglFramebuffer *framebuffer)
{
_cogl_context_set_current_projection (framebuffer->context,
framebuffer->projection_stack);
CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_entry (framebuffer);
_cogl_context_set_current_projection_entry (framebuffer->context,
projection_entry);
}
static void
@ -2647,9 +2667,9 @@ void
cogl_framebuffer_get_modelview_matrix (CoglFramebuffer *framebuffer,
CoglMatrix *matrix)
{
CoglMatrixStack *modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
_cogl_matrix_stack_get (modelview_stack, matrix);
CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
_cogl_matrix_entry_get (modelview_entry, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
@ -2672,9 +2692,9 @@ void
cogl_framebuffer_get_projection_matrix (CoglFramebuffer *framebuffer,
CoglMatrix *matrix)
{
CoglMatrixStack *projection_stack =
_cogl_framebuffer_get_projection_stack (framebuffer);
_cogl_matrix_stack_get (projection_stack, matrix);
CoglMatrixEntry *projection_entry =
_cogl_framebuffer_get_projection_entry (framebuffer);
_cogl_matrix_entry_get (projection_entry, matrix);
_COGL_MATRIX_DEBUG_PRINT (matrix);
}
@ -2724,14 +2744,25 @@ cogl_framebuffer_push_rectangle_clip (CoglFramebuffer *framebuffer,
float y_2)
{
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix;
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
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 =
_cogl_clip_stack_push_rectangle (clip_state->stacks->data,
x_1, y_1, x_2, y_2,
&modelview_matrix);
modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |=
@ -2743,14 +2774,25 @@ cogl_framebuffer_push_path_clip (CoglFramebuffer *framebuffer,
CoglPath *path)
{
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix;
cogl_framebuffer_get_modelview_matrix (framebuffer, &modelview_matrix);
CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
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 =
_cogl_clip_stack_push_from_path (clip_state->stacks->data,
path,
&modelview_matrix);
modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |=
@ -2766,16 +2808,27 @@ cogl_framebuffer_push_primitive_clip (CoglFramebuffer *framebuffer,
float bounds_y2)
{
CoglClipState *clip_state = _cogl_framebuffer_get_clip_state (framebuffer);
CoglMatrix modelview_matrix;
cogl_get_modelview_matrix (&modelview_matrix);
CoglMatrixEntry *modelview_entry =
_cogl_framebuffer_get_modelview_entry (framebuffer);
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 =
_cogl_clip_stack_push_primitive (clip_state->stacks->data,
primitive,
bounds_x1, bounds_y1,
bounds_x2, bounds_y2,
&modelview_matrix);
modelview_entry,
projection_entry,
viewport);
if (framebuffer->context->current_draw_buffer == framebuffer)
framebuffer->context->current_draw_buffer_changes |=

View File

@ -67,13 +67,10 @@ typedef struct _CoglJournalEntry
{
CoglPipeline *pipeline;
int n_layers;
CoglMatrix model_view;
CoglMatrixEntry *modelview_entry;
CoglClipStack *clip_stack;
/* Offset into ctx->logged_vertices */
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;
CoglJournal *

View File

@ -107,9 +107,6 @@ typedef struct _CoglJournalFlushState
CoglIndices *indices;
size_t indices_type_size;
CoglMatrixStack *modelview_stack;
CoglMatrixStack *projection_stack;
CoglPipeline *pipeline;
} CoglJournalFlushState;
@ -297,11 +294,8 @@ _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
g_print ("BATCHING: modelview batch len = %d\n", batch_len);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
{
_cogl_matrix_stack_set (state->modelview_stack,
&batch_start->model_view);
_cogl_context_set_current_modelview (ctx, state->modelview_stack);
}
_cogl_context_set_current_modelview_entry (ctx,
batch_start->modelview_entry);
attributes = (CoglAttribute **)state->attributes->data;
@ -413,21 +407,7 @@ compare_entry_modelviews (CoglJournalEntry *entry0,
CoglJournalEntry *entry1)
{
/* Batch together quads with the same model view matrix */
/* 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;
return entry0->modelview_entry == entry1->modelview_entry;
}
/* 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)
{
CoglJournalFlushState *state = data;
CoglFramebuffer *framebuffer = state->journal->framebuffer;
CoglContext *ctx = framebuffer->context;
CoglMatrixStack *projection_stack;
COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries,
"Journal Flush", /* parent */
@ -710,15 +693,13 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
"pipeline + entries",
0 /* no application private data */);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
COGL_TIMER_START (_cogl_uprof_context,
time_flush_clip_stack_pipeline_entries);
if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
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
* 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. */
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
* no further model transform is applied by loading the identity
* 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))))
{
_cogl_matrix_stack_load_identity (state->modelview_stack);
_cogl_context_set_current_modelview (ctx, state->modelview_stack);
}
_cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
/* Setting up the clip state can sometimes also flush the projection
matrix so we should flush it again. This will be a no-op if the
clip code didn't modify the projection */
_cogl_context_set_current_projection (ctx, state->projection_stack);
/* Setting up the clip state can sometimes also update the current
* projection matrix entry so we should update it again. This will have
* no affect if the clip code didn't modify the projection */
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_len,
@ -749,97 +729,10 @@ _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
_cogl_journal_flush_vbo_offsets_and_entries, /* callback */
data);
_cogl_matrix_stack_pop (state->modelview_stack);
COGL_TIMER_STOP (_cogl_uprof_context,
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
{
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;
CoglClipStackRect *clip_rect;
float tx, ty;
float tx, ty, tz;
CoglMatrixEntry *modelview_entry;
clip_rect = (CoglClipStackRect *) clip_entry;
if (!calculate_translation (&clip_rect->matrix,
&journal_entry->model_view,
&tx, &ty))
modelview_entry = journal_entry->modelview_entry;
if (!_cogl_matrix_entry_calculate_translation (clip_rect->matrix_entry,
modelview_entry,
&tx, &ty, &tz))
return FALSE;
if (clip_rect->x0 < clip_rect->x1)
@ -1212,6 +1107,7 @@ upload_vertices (CoglJournal *journal,
else
{
float v[8];
CoglMatrix modelview;
v[0] = vin[0];
v[1] = vin[1];
@ -1222,7 +1118,8 @@ upload_vertices (CoglJournal *journal,
v[6] = vin[array_stride];
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 */
sizeof (float) * 2, /* stride_in */
v, /* points_in */
@ -1269,6 +1166,7 @@ _cogl_journal_discard (CoglJournal *journal)
CoglJournalEntry *entry =
&g_array_index (journal->entries, CoglJournalEntry, i);
_cogl_pipeline_journal_unref (entry->pipeline);
_cogl_matrix_entry_unref (entry->modelview_entry);
_cogl_clip_stack_unref (entry->clip_stack);
}
@ -1357,25 +1255,27 @@ _cogl_journal_all_entries_within_bounds (CoglJournal *journal,
void
_cogl_journal_flush (CoglJournal *journal)
{
CoglFramebuffer *framebuffer;
CoglContext *ctx;
CoglJournalFlushState state;
int i;
CoglMatrixStack *modelview_stack;
int i;
COGL_STATIC_TIMER (flush_timer,
"Mainloop", /* parent */
"Journal Flush",
"The time spent flushing the Cogl journal",
0 /* no application private data */);
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (journal->entries->len == 0)
return;
framebuffer = journal->framebuffer;
ctx = framebuffer->context;
/* The entries in this journal may depend on images in other
* framebuffers which may require that we flush the journals
* associated with those framebuffers before we can flush
* 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
* 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
state manually */
_cogl_framebuffer_flush_state (journal->framebuffer,
journal->framebuffer,
_cogl_framebuffer_flush_state (framebuffer,
framebuffer,
COGL_FRAMEBUFFER_STATE_ALL &
~(COGL_FRAMEBUFFER_STATE_MODELVIEW |
COGL_FRAMEBUFFER_STATE_CLIP));
@ -1396,12 +1296,6 @@ _cogl_journal_flush (CoglJournal *journal)
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))
{
/* 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;
CoglClipStack *clip_stack;
CoglPipelineFlushOptions flush_options;
CoglMatrixStack *modelview_stack;
COGL_STATIC_TIMER (log_timer,
"Mainloop", /* parent */
"Journal Log",
@ -1599,8 +1494,9 @@ _cogl_journal_log_quad (CoglJournal *journal,
if (G_UNLIKELY (final_pipeline != pipeline))
cogl_object_unref (final_pipeline);
cogl_framebuffer_get_modelview_matrix (framebuffer,
&entry->model_view);
modelview_stack =
_cogl_framebuffer_get_modelview_stack (framebuffer);
entry->modelview_entry = _cogl_matrix_entry_ref (modelview_stack->last_entry);
_cogl_pipeline_foreach_layer_internal (pipeline,
add_framebuffer_deps_cb,
@ -1622,6 +1518,7 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers);
CoglMatrixStack *projection_stack;
CoglMatrix projection;
CoglMatrix modelview;
int i;
float viewport[4];
@ -1649,7 +1546,8 @@ entry_to_screen_polygon (CoglFramebuffer *framebuffer,
* _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 */
sizeof (float) * 4, /* stride_in */
poly, /* points_in */

View File

@ -41,6 +41,13 @@ G_BEGIN_DECLS
void
_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
#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
*
* Copyright (C) 2009,2010 Intel Corporation.
* Copyright (C) 2009,2010,2012 Intel Corporation.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -29,29 +29,114 @@
#ifndef __COGL_MATRIX_STACK_H
#define __COGL_MATRIX_STACK_H
#include "cogl-object-private.h"
#include "cogl-matrix.h"
#include "cogl-context.h"
#include "cogl-framebuffer.h"
typedef struct _CoglMatrixStack CoglMatrixStack;
typedef struct
typedef enum _CoglMatrixOp
{
CoglMatrixStack *stack;
unsigned int age;
COGL_MATRIX_OP_LOAD_IDENTITY,
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 flipped;
} CoglMatrixStackCache;
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);
} CoglMatrixEntryCache;
CoglMatrixStack *
_cogl_matrix_stack_new (void);
@ -62,6 +147,9 @@ _cogl_matrix_stack_push (CoglMatrixStack *stack);
void
_cogl_matrix_stack_pop (CoglMatrixStack *stack);
void
_cogl_matrix_entry_identity_init (CoglMatrixEntry *entry);
void
_cogl_matrix_stack_load_identity (CoglMatrixStack *stack);
@ -99,53 +187,89 @@ _cogl_matrix_stack_perspective (CoglMatrixStack *stack,
float z_near,
float z_far);
void
_cogl_matrix_stack_ortho (CoglMatrixStack *stack,
float left,
float right,
float bottom,
float top,
float z_near,
float z_far);
_cogl_matrix_stack_orthographic (CoglMatrixStack *stack,
float x_1,
float y_1,
float x_2,
float y_2,
float near,
float far);
CoglBool
_cogl_matrix_stack_get_inverse (CoglMatrixStack *stack,
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,
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
_cogl_matrix_stack_set (CoglMatrixStack *stack,
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
_cogl_matrix_stack_flush_to_gl_builtins (CoglContext *ctx,
CoglMatrixStack *stack,
_cogl_matrix_entry_print (CoglMatrixEntry *entry);
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,
CoglFramebuffer *framebuffer,
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);
void
_cogl_matrix_entry_cache_init (CoglMatrixEntryCache *cache);
CoglBool
_cogl_matrix_stack_equal (CoglMatrixStack *stack0,
CoglMatrixStack *stack1);
_cogl_matrix_entry_cache_maybe_update (CoglMatrixEntryCache *cache,
CoglMatrixEntry *entry,
CoglBool flip);
void
_cogl_matrix_stack_init_cache (CoglMatrixStackCache *cache);
CoglBool
_cogl_matrix_stack_check_and_update_cache (CoglMatrixStack *stack,
CoglMatrixStackCache *cache,
CoglBool flip);
void
_cogl_matrix_stack_destroy_cache (CoglMatrixStackCache *cache);
_cogl_matrix_entry_cache_destroy (CoglMatrixEntryCache *cache);
CoglBool
_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.
*/
static void
print_matrix_floats (const float m[16])
print_matrix_floats (const char *prefix, const float m[16])
{
int 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
_cogl_matrix_print (const CoglMatrix *matrix)
{
if (!(matrix->flags & MAT_DIRTY_TYPE))
{
_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");
_cogl_matrix_prefix_print ("", matrix);
}
/*
@ -1659,6 +1666,15 @@ cogl_matrix_init_from_array (CoglMatrix *matrix, const float *array)
_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
_cogl_matrix_init_from_quaternion (CoglMatrix *matrix,
CoglQuaternion *quaternion)

View File

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

View File

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

View File

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

View File

@ -37,24 +37,28 @@
#include "cogl-context.h"
#include "cogl-context-private.h"
#include "cogl-framebuffer-private.h"
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)
return;
if (ctx->current_projection_stack)
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
ctx->current_projection_stack,
if (ctx->current_projection_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_projection_entry,
COGL_MATRIX_PROJECTION,
framebuffer,
FALSE /* enable flip */);
if (ctx->current_modelview_stack)
_cogl_matrix_stack_flush_to_gl_builtins (ctx,
ctx->current_modelview_stack,
if (ctx->current_modelview_entry)
_cogl_matrix_entry_flush_to_gl_builtins (ctx,
ctx->current_modelview_entry,
COGL_MATRIX_MODELVIEW,
framebuffer,
FALSE /* enable flip */);
}

View File

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

View File

@ -33,6 +33,7 @@
#include "cogl-pipeline-private.h"
#include "cogl-pipeline-state-private.h"
#include "cogl-pipeline-opengl-private.h"
#include "cogl-framebuffer-private.h"
#ifdef COGL_PIPELINE_VERTEND_FIXED
@ -80,26 +81,29 @@ _cogl_pipeline_vertend_fixed_start (CoglPipeline *pipeline,
static CoglBool
_cogl_pipeline_vertend_fixed_add_layer (CoglPipeline *pipeline,
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);
CoglTextureUnit *unit = _cogl_get_texture_unit (unit_index);
_COGL_GET_CONTEXT (ctx, FALSE);
if (layers_difference & COGL_PIPELINE_LAYER_STATE_USER_MATRIX)
{
CoglPipelineLayerState state = COGL_PIPELINE_LAYER_STATE_USER_MATRIX;
CoglPipelineLayer *authority =
_cogl_pipeline_layer_get_authority (layer, state);
CoglMatrixEntry *matrix_entry;
_cogl_matrix_stack_set (unit->matrix_stack,
&authority->big_state->matrix);
_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,
framebuffer,
FALSE /* enable flip */);
}

View File

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

View File

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