Merge branch 'cogl-journal-batching'

[cogl] Improve ability to break out into raw OpenGL via begin/end mechanism
Adds a cogl_flush() to give developers breaking into raw GL a fighting chance
[cogl-material] Be more carefull about flushing in cogl_material_remove_layer
Revert "[rectangle] Avoid modifying materials mid scene"
Revert "[actor] Avoid modifying materials mid-scene to improve journal batching"
[cogl-vertex-buffer] Disable unused client tex coord arrays
[cogl] disable all client tex coord arrays in _cogl_add_path_to_stencil_buffer
[cogl] flush matrices in _cogl_add_path_to_stencil_buffer
[journal] Don't resize a singlton VBO; create and destroy a VBO each flush
[cogl] avoid using the journal in _cogl_add_path_to_stencil_buffer
[pango-display-list] Use the Cogl journal for short runs of text
[material] _cogl_material_equal: catch the simplest case of matching handles
[material] avoid flushing the journal when just changing the color
[cogl journal] Perform software modelview transform on logged quads.
[Cogl journal] use G_UNLIKLEY around runtime debugging conditions
[cogl journal] Adds a --cogl-debug=batching option to trace batching
[Cogl journal] Adds a --cogl-debug=journal option for tracing the journal
[cogl] Adds a debug option for disabling use of VBOs --cogl-debug=disable-vbos
[cogl] Force Cogl to always use the client side matrix stack
[cogl-debug] Adds a "client-side-matrices" Cogl debug option
[cogl-color] Adds a cogl_color_equal() function
[cogl material] optimize logging of material colors in the journal
[rectangle] Avoid modifying materials mid scene
[actor] Avoid modifying materials mid-scene to improve journal batching
[journal] Always pad our vertex data as if at least 2 layers are enabled
[cogl] Improving Cogl journal to minimize driver overheads + GPU state changes

The Cogl journal is a mechanism Cogl uses to batch geometry resulting from
any of the cogl_rectangle* functions before sending it to OpenGL.  This aims
to improve the Cogl journal so that it can reduce the number of state
changes and draw calls we issue to the OpenGL driver and hopfully improve
performance.

Previously each call to any of the cogl_rectangle* functions would imply an
immediate GL draw call, as well as a corresponding modelview change;
material state changes and gl{Vertex,Color,TexCoord}Pointer calls.  Now
though we have tried to open the scope for batching up as much as possible
so we only have to flush the geometry either before calling glXSwapBuffers,
or when we change state that isn't tracked by the journal.

As a basic example, it's now possible for us to batch typical picking
renders into a single draw call for the whole scene.

Some key points about this change:
- We now perform transformations of quads in software (except for long runs of
  text which continue to use VBOs)
    * It might seem surprising at first, but when you consider that so many
      Clutter actors are little more than textured quads and each actor
      typically implies a modelview matrix change; the costs involved in
      setting up the GPU with the new modelview can easily out weigh the cost
      of simply transforming 4 vertices.
- We always use Cogl's own client side matrix API now.
    * We found the performance of querying the OpenGL driver for matrix state
      was often worse than using the client matrix code, and also - discussing
      with Mesa developers - agreed that since khronos has essentially
      deprecated the GL matrix API (by removing it from OpenGL 3 and
      OpenGL-ES 2) it was appropriate to take full responsibility for all our
      matrix manipulation.
- Developers should avoid modifying materials mid-scene.
    * With the exception of material color changes, if you try and modify a
      material that is referenced in the journal we will currently force a
      journal flush. Note: you can assume that re-setting the same value for
      a material property won't require a flush though.
- Several new --cogl-debug options have been added
    * "disable-batching" can be used to identify bugs in the way that the
      journal does its batching; of could this shouldn't ever be needed :-)
    * "disable-vbos" can be used to test the VBO fallback paths where we
      simply use malloc()'d buffers instead.
    * "batching" lets you get an overview of how the journal is batching
      your geometry and may help you identify ways to improve your
      application performance.
    * "journal" lets you trace all the geometry as it gets logged in the
      journal, and all the geometry as its flushed from the journal.
      Obviously an inconsistency can identify a bug, but the numbers may
      help you verify application logic too.
    * "disable-software-transform" as implied will instead use the driver
      /GPU to transform quads by the modelview matrix.
    Although committed separately a --clutter-debug=nop-picking option was
    also added that lets you remove picking from the equation, which can
    sometimes help make problem analysis more deterministic.
This commit is contained in:
Robert Bragg 2009-06-30 17:17:30 +01:00
commit fce406f1b8
33 changed files with 1473 additions and 335 deletions

View File

@ -409,6 +409,9 @@ _clutter_do_pick (ClutterStage *stage,
/* Calls should work under both GL and GLES, note GLES needs RGBA */
glGetIntegerv(GL_VIEWPORT, viewport);
/* Make sure Cogl flushes any batched geometry to the GPU driver */
cogl_flush ();
/* Read the color of the screen co-ords pixel */
glReadPixels (x, viewport[3] - y -1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixel);

View File

@ -240,6 +240,22 @@ float cogl_color_get_alpha (const CoglColor *color);
*/
void cogl_color_premultiply (CoglColor *color);
/**
* cogl_color_equal:
* @v1: a #CoglColor
* @v2: a #CoglColor
*
* Compares two #CoglColor<!-- -->s and checks if they are the same.
*
* This function can be passed to g_hash_table_new() as the @key_equal_func
* parameter, when using #CoglColor<!-- -->s as keys in a #GHashTable.
*
* Return value: %TRUE if the two colors are the same.
*
* Since: 1.0
*/
gboolean cogl_color_equal (gconstpointer v1, gconstpointer v2);
G_END_DECLS
#endif /* __COGL_COLOR_H__ */

View File

@ -29,16 +29,22 @@
G_BEGIN_DECLS
typedef enum {
COGL_DEBUG_MISC = 1 << 0,
COGL_DEBUG_TEXTURE = 1 << 1,
COGL_DEBUG_MATERIAL = 1 << 2,
COGL_DEBUG_SHADER = 1 << 3,
COGL_DEBUG_OFFSCREEN = 1 << 4,
COGL_DEBUG_DRAW = 1 << 5,
COGL_DEBUG_PANGO = 1 << 6,
COGL_DEBUG_RECTANGLES = 1 << 7,
COGL_DEBUG_HANDLE = 1 << 8,
COGL_DEBUG_BLEND_STRINGS = 1 << 9
COGL_DEBUG_MISC = 1 << 0,
COGL_DEBUG_TEXTURE = 1 << 1,
COGL_DEBUG_MATERIAL = 1 << 2,
COGL_DEBUG_SHADER = 1 << 3,
COGL_DEBUG_OFFSCREEN = 1 << 4,
COGL_DEBUG_DRAW = 1 << 5,
COGL_DEBUG_PANGO = 1 << 6,
COGL_DEBUG_RECTANGLES = 1 << 7,
COGL_DEBUG_HANDLE = 1 << 8,
COGL_DEBUG_BLEND_STRINGS = 1 << 9,
COGL_DEBUG_DISABLE_BATCHING = 1 << 10,
COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES = 1 << 11,
COGL_DEBUG_DISABLE_VBOS = 1 << 12,
COGL_DEBUG_JOURNAL = 1 << 13,
COGL_DEBUG_BATCHING = 1 << 14,
COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM = 1 << 15
} CoglDebugFlags;
#ifdef COGL_ENABLE_DEBUG

View File

@ -673,6 +673,16 @@ void cogl_material_set_layer_matrix (CoglHandle material,
*/
const GList *cogl_material_get_layers (CoglHandle material);
/**
* cogl_material_get_n_layers:
* @material: A CoglMaterial object
*
* Returns: The number of layers defined for the given material
*
* Since: 1.0
*/
int cogl_material_get_n_layers (CoglHandle material);
/**
* CoglMaterialLayerType:
* @COGL_MATERIAL_LAYER_TYPE_TEXTURE: The layer represents a
@ -713,15 +723,6 @@ CoglMaterialLayerType cogl_material_layer_get_type (CoglHandle layer_handle);
* likely return COGL_INVALID_HANDLE if you try to get the texture.
* Considering this, you can call cogl_material_layer_get_type first,
* to check it is of type COGL_MATERIAL_LAYER_TYPE_TEXTURE.
*
* Note: It is possible for a layer object of type
* COGL_MATERIAL_LAYER_TYPE_TEXTURE to be realized before a texture
* object has been associated with the layer. For example this happens
* if you setup layer combining for a given layer index before calling
* cogl_material_set_layer for that index.
*
* Returns: A CoglHandle to the layers texture object or COGL_INVALID_HANDLE
* if a texture has not been set yet.
*/
CoglHandle cogl_material_layer_get_texture (CoglHandle layer_handle);

View File

@ -724,6 +724,113 @@ void cogl_read_pixels (int x,
CoglPixelFormat format,
guint8 *pixels);
/**
* cogl_flush:
*
* This function should only need to be called in exceptional circumstances.
*
* As an optimization Cogl drawing functions may batch up primitives
* internally, so if you are trying to use raw GL outside of Cogl you stand a
* better chance of being successful if you ask Cogl to flush any batched
* geometry before making your state changes.
*
* It only ensure that the underlying driver is issued all the commands
* necessary to draw the batched primitives. It provides no guarantees about
* when the driver will complete the rendering.
*
* This provides no guarantees about the GL state upon returning and to avoid
* confusing Cogl you should aim to restore any changes you make before
* resuming use of Cogl.
*
* If you are making state changes with the intention of affecting Cogl drawing
* primitives you are 100% on your own since you stand a good chance of
* conflicting with Cogl internals. For example clutter-gst which currently
* uses direct GL calls to bind ARBfp programs will very likely break when Cogl
* starts to use ARBfb programs itself for the material API.
*
* Since: 1.0
*/
void cogl_flush (void);
/**
* cogl_begin_gl:
*
* We do not advise nor reliably support the interleaving of raw GL drawing and
* Cogl drawing functions, but if you insist, cogl_begin_gl() and cogl_end_gl()
* provide a simple mechanism that may at least give you a fighting chance of
* succeeding.
*
* Note: this doesn't help you modify the behaviour of Cogl drawing functions
* through the modification of GL state; that will never be reliably supported,
* but if you are trying to do something like:
* <programlisting>
* {
* - setup some OpenGL state.
* - draw using OpenGL (e.g. glDrawArrays() )
* - reset modified OpenGL state.
* - continue using Cogl to draw
* }
* </programlisting>
* You should surround blocks of drawing using raw GL with cogl_begin_gl()
* and cogl_end_gl():
* <programlisting>
* {
* cogl_begin_gl ();
* - setup some OpenGL state.
* - draw using OpenGL (e.g. glDrawArrays() )
* - reset modified OpenGL state.
* cogl_end_gl ();
* - continue using Cogl to draw
* }
* </programlisting>
*
* Don't ever try and do:
* <programlisting>
* {
* - setup some OpenGL state.
* - use Cogl to draw
* - reset modified OpenGL state.
* }
* </programlisting>
* When the internals of Cogl evolves, this is very liable to break.
*
* This function will flush all batched primitives, and subsequently flush
* all internal Cogl state to OpenGL as if it were going to draw something
* itself.
*
* The result is that the OpenGL modelview matrix will be setup; the state
* corresponding to the current source material will be set up and other world
* state such as backface culling, depth and fogging enabledness will be sent
* to OpenGL.
*
* Note: no special material state is flushed, so if you want Cogl to setup a
* simplified material state it is your responsibility to set a simple source
* material before calling cogl_begin_gl. E.g. by calling
* cogl_set_source_color4ub().
*
* Note: It is your responsibility to restore any OpenGL state that you modify
* to how it was after calling cogl_begin_gl() if you don't do this then the
* result of further Cogl calls is undefined.
*
* Note: You can not nest begin/end blocks.
*
* Again we would like to stress, we do not advise the use of this API and if
* possible we would prefer to improve Cogl than have developers require raw
* OpenGL.
*
* Since: 1.0
*/
void cogl_begin_gl (void);
/**
* cogl_end_gl:
*
* This is the counterpart to cogl_begin_gl() used to delimit blocks of drawing
* code using raw OpenGL. Please refer to cogl_begin_gl() for full details.
*
* Since: 1.0
*/
void cogl_end_gl (void);
/*
* Internal API available only to Clutter.

View File

@ -324,6 +324,10 @@ _cogl_clip_stack_rebuild (void)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* The current primitive journal does not support tracking changes to the
* clip stack... */
_cogl_journal_flush ();
stack = (CoglClipStack *) ctx->clip.stacks->data;
ctx->clip.stack_dirty = FALSE;

View File

@ -25,6 +25,8 @@
#include "config.h"
#endif
#include <string.h>
#include "cogl.h"
#include "cogl-color.h"
#include "cogl-fixed.h"
@ -184,3 +186,16 @@ cogl_set_source_color4f (float red,
cogl_color_set_from_4f (&c, red, green, blue, alpha);
cogl_set_source_color (&c);
}
gboolean
cogl_color_equal (gconstpointer v1, gconstpointer v2)
{
const guint32 *c1 = v1, *c2 = v2;
g_return_val_if_fail (v1 != NULL, FALSE);
g_return_val_if_fail (v2 != NULL, FALSE);
/* XXX: We don't compare the padding */
return *c1 == *c2 ? TRUE : FALSE;
}

View File

@ -320,7 +320,10 @@ _cogl_current_matrix_state_init (void)
ctx->matrix_mode = COGL_MATRIX_MODELVIEW;
ctx->modelview_stack = NULL;
if (ctx->indirect)
#if 0
if (ctx->indirect ||
cogl_debug_flags & COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES)
#endif
{
ctx->modelview_stack =
_cogl_matrix_stack_new ();

View File

@ -40,7 +40,13 @@ static const GDebugKey cogl_debug_keys[] = {
{ "pango", COGL_DEBUG_PANGO },
{ "rectangles", COGL_DEBUG_RECTANGLES },
{ "handle", COGL_DEBUG_HANDLE },
{ "blend-strings", COGL_DEBUG_BLEND_STRINGS }
{ "blend-strings", COGL_DEBUG_BLEND_STRINGS },
{ "disable-batching", COGL_DEBUG_DISABLE_BATCHING },
{ "client-side-matrices", COGL_DEBUG_FORCE_CLIENT_SIDE_MATRICES },
{ "disable-vbos", COGL_DEBUG_DISABLE_VBOS },
{ "journal", COGL_DEBUG_JOURNAL },
{ "batching", COGL_DEBUG_BATCHING },
{ "disable-software-transform", COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM }
};
static const gint n_cogl_debug_keys = G_N_ELEMENTS (cogl_debug_keys);

View File

@ -36,6 +36,16 @@
typedef struct _CoglMaterial CoglMaterial;
typedef struct _CoglMaterialLayer CoglMaterialLayer;
typedef enum _CoglMaterialEqualFlags
{
/* Return FALSE if any component of either material isn't set to its
* default value. (Note: if the materials have corresponding flush
* options indicating that e.g. the material color won't be flushed then
* this will not assert a default color value.) */
COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS = 1L<<0,
} CoglMaterialEqualFlags;
/* XXX: I don't think gtk-doc supports having private enums so these aren't
* bundled in with CoglMaterialLayerFlags */
typedef enum _CoglMaterialLayerPrivFlags
@ -90,22 +100,24 @@ struct _CoglMaterialLayer
typedef enum _CoglMaterialFlags
{
COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<0,
COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<1,
COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<2,
COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<3,
COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<4,
COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC = 1L<<5
COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING = 1L<<0,
COGL_MATERIAL_FLAG_DEFAULT_COLOR = 1L<<1,
COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL = 1L<<2,
COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC = 1L<<3,
COGL_MATERIAL_FLAG_ENABLE_BLEND = 1L<<4,
COGL_MATERIAL_FLAG_DEFAULT_BLEND = 1L<<5
} CoglMaterialFlags;
struct _CoglMaterial
{
CoglHandleObject _parent;
gulong journal_ref_count;
gulong flags;
/* If no lighting is enabled; this is the basic material color */
GLfloat unlit[4];
GLubyte unlit[4];
/* Standard OpenGL lighting model attributes */
GLfloat ambient[4];
@ -130,6 +142,7 @@ struct _CoglMaterial
GLint blend_dst_factor_rgb;
GList *layers;
guint n_layers;
};
/*
@ -183,39 +196,60 @@ typedef enum _CoglMaterialLayerFlags
gulong _cogl_material_layer_get_flags (CoglHandle layer_handle);
/*
* CoglMaterialFlushOption:
* @COGL_MATERIAL_FLUSH_FALLBACK_MASK: Follow this by a guin32 mask
* of the layers that can't be supported with the user supplied texture
* and need to be replaced with fallback textures. (1 = fallback, and the
* least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_DISABLE_MASK: Follow this by a guint32 mask
* of the layers that you want to completly disable texturing for
* (1 = fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: Follow this by a GLuint OpenGL texture
* name to override the texture used for layer 0 of the material. This is
* intended for dealing with sliced textures where you will need to point
* to each of the texture slices in turn when drawing your geometry.
* Passing a value of 0 is the same as not passing the option at all.
* CoglMaterialFlushFlag:
* @COGL_MATERIAL_FLUSH_FALLBACK_MASK: The fallback_layers member is set to
* a guint32 mask of the layers that can't be supported with the user
* supplied texture and need to be replaced with fallback textures. (1 =
* fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_DISABLE_MASK: The disable_layers member is set to
* a guint32 mask of the layers that you want to completly disable
* texturing for (1 = fallback, and the least significant bit = layer 0)
* @COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE: The layer0_override_texture member is
* set to a GLuint OpenGL texture name to override the texture used for
* layer 0 of the material. This is intended for dealing with sliced
* textures where you will need to point to each of the texture slices in
* turn when drawing your geometry. Passing a value of 0 is the same as
* not passing the option at all.
* @COGL_MATERIAL_FLUSH_SKIP_GL_COLOR: When flushing the GL state for the
* material don't call glColor.
*/
typedef enum _CoglMaterialFlushOption
typedef enum _CoglMaterialFlushFlag
{
COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE,
} CoglMaterialFlushOption;
COGL_MATERIAL_FLUSH_FALLBACK_MASK = 1L<<0,
COGL_MATERIAL_FLUSH_DISABLE_MASK = 1L<<1,
COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE = 1L<<2,
COGL_MATERIAL_FLUSH_SKIP_GL_COLOR = 1L<<3
} CoglMaterialFlushFlag;
/*
* cogl_material_flush_gl_state:
* @material: A CoglMaterial object
* @...: A NULL terminated list of (CoglMaterialFlushOption, data) pairs
* CoglMaterialFlushOptions:
*
* This function commits the state of the specified CoglMaterial - including
* the texture state for all the layers - to the OpenGL[ES] driver.
*
* Since 1.0
*/
typedef struct _CoglMaterialFlushOptions
{
CoglMaterialFlushFlag flags;
guint32 fallback_layers;
guint32 disable_layers;
GLuint layer0_override_texture;
} CoglMaterialFlushOptions;
void _cogl_material_get_colorubv (CoglHandle handle,
guint8 *color);
void _cogl_material_flush_gl_state (CoglHandle material,
...) G_GNUC_NULL_TERMINATED;
CoglMaterialFlushOptions *options);
gboolean _cogl_material_equal (CoglHandle material0_handle,
CoglMaterialFlushOptions *material0_flush_options,
CoglHandle material1_handle,
CoglMaterialFlushOptions *material1_flush_options,
CoglMaterialEqualFlags flags);
CoglHandle _cogl_material_journal_ref (CoglHandle material_handle);
void _cogl_material_journal_unref (CoglHandle material_handle);
#endif /* __COGL_MATERIAL_PRIVATE_H */

View File

@ -76,14 +76,14 @@ cogl_material_new (void)
{
/* Create new - blank - material */
CoglMaterial *material = g_new0 (CoglMaterial, 1);
GLfloat *unlit = material->unlit;
GLubyte *unlit = material->unlit;
GLfloat *ambient = material->ambient;
GLfloat *diffuse = material->diffuse;
GLfloat *specular = material->specular;
GLfloat *emission = material->emission;
/* Use the same defaults as the GL spec... */
unlit[0] = 1.0; unlit[1] = 1.0; unlit[2] = 1.0; unlit[3] = 1.0;
unlit[0] = 0xff; unlit[1] = 0xff; unlit[2] = 0xff; unlit[3] = 0xff;
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR;
/* Use the same defaults as the GL spec... */
@ -111,9 +111,10 @@ cogl_material_new (void)
#endif
material->blend_src_factor_rgb = GL_ONE;
material->blend_dst_factor_rgb = GL_ONE_MINUS_SRC_ALPHA;
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_BLEND;
material->layers = NULL;
material->n_layers = 0;
return _cogl_material_handle_new (material);
}
@ -130,15 +131,24 @@ _cogl_material_free (CoglMaterial *material)
g_free (material);
}
static void
handle_automatic_blend_enable (CoglMaterial *material)
static gboolean
_cogl_material_needs_blending_enabled (CoglMaterial *material,
GLubyte *override_color)
{
GList *tmp;
/* XXX: If we expose manual control over ENABLE_BLEND, we'll add
* a flag to know when it's user configured, so we don't trash it */
material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND;
/* XXX: Uncomment this to disable all blending */
#if 0
return;
#endif
if ((override_color && override_color[3] != 0xff) ||
material->unlit[3] != 0xff)
return TRUE;
for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{
CoglMaterialLayer *layer = tmp->data;
@ -149,13 +159,46 @@ handle_automatic_blend_enable (CoglMaterial *material)
continue;
if (cogl_texture_get_format (layer->texture) & COGL_A_BIT)
material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND;
return TRUE;
}
if (material->unlit[3] != 1.0)
return FALSE;
}
static void
handle_automatic_blend_enable (CoglMaterial *material)
{
material->flags &= ~COGL_MATERIAL_FLAG_ENABLE_BLEND;
if (_cogl_material_needs_blending_enabled (material, NULL))
material->flags |= COGL_MATERIAL_FLAG_ENABLE_BLEND;
}
/* If primitives have been logged in the journal referencing the current
* state of this material we need to flush the journal before we can
* modify it... */
static void
_cogl_material_pre_change_notify (CoglMaterial *material,
gboolean only_color_change,
GLubyte *new_color)
{
/* XXX: We don't usually need to flush the journal just due to color changes
* since material colors are logged in the journals vertex buffer. The
* exception is when the change in color enables or disables the need for
* blending. */
if (only_color_change)
{
gboolean will_need_blending =
_cogl_material_needs_blending_enabled (material, new_color);
if (will_need_blending ==
(material->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND) ? TRUE : FALSE)
return;
}
if (material->journal_ref_count)
_cogl_journal_flush ();
}
void
cogl_material_get_color (CoglHandle handle,
CoglColor *color)
@ -166,11 +209,20 @@ cogl_material_get_color (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
cogl_color_set_from_4f (color,
material->unlit[0],
material->unlit[1],
material->unlit[2],
material->unlit[3]);
cogl_color_set_from_4ub (color,
material->unlit[0],
material->unlit[1],
material->unlit[2],
material->unlit[3]);
}
/* This is used heavily by the cogl journal when logging quads */
void
_cogl_material_get_colorubv (CoglHandle handle,
guint8 *color)
{
CoglMaterial *material = _cogl_material_pointer_from_handle (handle);
memcpy (color, material->unlit, 4);
}
void
@ -178,26 +230,29 @@ cogl_material_set_color (CoglHandle handle,
const CoglColor *unlit_color)
{
CoglMaterial *material;
GLfloat unlit[4];
GLubyte unlit[4];
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
unlit[0] = cogl_color_get_red_float (unlit_color);
unlit[1] = cogl_color_get_green_float (unlit_color);
unlit[2] = cogl_color_get_blue_float (unlit_color);
unlit[3] = cogl_color_get_alpha_float (unlit_color);
unlit[0] = cogl_color_get_red_byte (unlit_color);
unlit[1] = cogl_color_get_green_byte (unlit_color);
unlit[2] = cogl_color_get_blue_byte (unlit_color);
unlit[3] = cogl_color_get_alpha_byte (unlit_color);
if (memcmp (unlit, material->unlit, sizeof (unlit)) == 0)
return;
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, TRUE, unlit);
memcpy (material->unlit, unlit, sizeof (unlit));
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_COLOR;
if (unlit[0] == 1.0 &&
unlit[1] == 1.0 &&
unlit[2] == 1.0 &&
unlit[3] == 1.0)
if (unlit[0] == 0xff &&
unlit[1] == 0xff &&
unlit[2] == 0xff &&
unlit[3] == 0xff)
material->flags |= COGL_MATERIAL_FLAG_DEFAULT_COLOR;
handle_automatic_blend_enable (material);
@ -255,6 +310,9 @@ cogl_material_set_ambient (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
ambient = material->ambient;
ambient[0] = cogl_color_get_red_float (ambient_color);
ambient[1] = cogl_color_get_green_float (ambient_color);
@ -292,6 +350,9 @@ cogl_material_set_diffuse (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
diffuse = material->diffuse;
diffuse[0] = cogl_color_get_red_float (diffuse_color);
diffuse[1] = cogl_color_get_green_float (diffuse_color);
@ -337,6 +398,9 @@ cogl_material_set_specular (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
specular = material->specular;
specular[0] = cogl_color_get_red_float (specular_color);
specular[1] = cogl_color_get_green_float (specular_color);
@ -372,6 +436,9 @@ cogl_material_set_shininess (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
material->shininess = (GLfloat)shininess * 128.0;
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL;
@ -405,6 +472,9 @@ cogl_material_set_emission (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
emission = material->emission;
emission[0] = cogl_color_get_red_float (emission_color);
emission[1] = cogl_color_get_green_float (emission_color);
@ -424,6 +494,10 @@ cogl_material_set_alpha_test_function (CoglHandle handle,
g_return_if_fail (cogl_is_material (handle));
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
material->alpha_func = alpha_func;
material->alpha_func_reference = (GLfloat)alpha_reference;
@ -571,6 +645,9 @@ cogl_material_set_blend (CoglHandle handle,
a = &statements[1];
}
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
#ifndef HAVE_COGL_GLES
setup_blend_state (rgb,
&material->blend_equation_rgb,
@ -587,7 +664,7 @@ cogl_material_set_blend (CoglHandle handle,
&material->blend_dst_factor_rgb);
#endif
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND;
return TRUE;
}
@ -604,13 +681,16 @@ cogl_material_set_blend_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
constant = material->blend_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
constant[2] = cogl_color_get_blue_float (constant_color);
constant[3] = cogl_color_get_alpha_float (constant_color);
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC;
material->flags &= ~COGL_MATERIAL_FLAG_DEFAULT_BLEND;
#endif
}
@ -644,6 +724,9 @@ _cogl_material_get_layer (CoglMaterial *material,
if (!create_if_not_found)
return NULL;
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
layer = g_new0 (CoglMaterialLayer, 1);
layer_handle = _cogl_material_layer_handle_new (layer);
@ -682,20 +765,23 @@ cogl_material_set_layer (CoglHandle material_handle,
{
CoglMaterial *material;
CoglMaterialLayer *layer;
int n_layers;
g_return_if_fail (cogl_is_material (material_handle));
g_return_if_fail (texture_handle == COGL_INVALID_HANDLE
|| cogl_is_texture (texture_handle));
material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material_handle, layer_index, TRUE);
if (texture_handle == layer->texture)
return;
n_layers = g_list_length (material->layers);
if (n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
material->n_layers = g_list_length (material->layers);
if (material->n_layers >= CGL_MAX_COMBINED_TEXTURE_IMAGE_UNITS)
{
if (!(material->flags & COGL_MATERIAL_FLAG_SHOWN_SAMPLER_WARNING))
{
@ -856,6 +942,9 @@ cogl_material_set_layer_combine (CoglHandle handle,
a = &statements[1];
}
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
setup_texture_combine_state (rgb,
&layer->texture_combine_rgb_func,
layer->texture_combine_rgb_src,
@ -886,6 +975,9 @@ cogl_material_set_layer_combine_constant (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
constant = layer->texture_combine_constant;
constant[0] = cogl_color_get_red_float (constant_color);
constant[1] = cogl_color_get_green_float (constant_color);
@ -909,6 +1001,9 @@ cogl_material_set_layer_matrix (CoglHandle material_handle,
material = _cogl_material_pointer_from_handle (material_handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
layer->matrix = *matrix;
layer->flags |= COGL_MATERIAL_LAYER_FLAG_DIRTY;
@ -931,18 +1026,29 @@ cogl_material_remove_layer (CoglHandle material_handle,
CoglMaterial *material;
CoglMaterialLayer *layer;
GList *tmp;
gboolean notified_change = FALSE;
g_return_if_fail (cogl_is_material (material_handle));
material = _cogl_material_pointer_from_handle (material_handle);
for (tmp = material->layers; tmp != NULL; tmp = tmp->next)
{
layer = tmp->data;
if (layer->index == layer_index)
{
CoglHandle handle = (CoglHandle) layer;
/* possibly flush primitives referencing the current state... */
if (!notified_change)
{
_cogl_material_pre_change_notify (material, FALSE, NULL);
notified_change = TRUE;
}
cogl_handle_unref (handle);
material->layers = g_list_remove (material->layers, layer);
material->n_layers--;
break;
}
}
@ -992,6 +1098,18 @@ cogl_material_get_layers (CoglHandle material_handle)
return material->layers;
}
int
cogl_material_get_n_layers (CoglHandle material_handle)
{
CoglMaterial *material;
g_return_val_if_fail (cogl_is_material (material_handle), 0);
material = _cogl_material_pointer_from_handle (material_handle);
return material->n_layers;
}
CoglMaterialLayerType
cogl_material_layer_get_type (CoglHandle layer_handle)
{
@ -1318,7 +1436,10 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
!gl_layer_info->disabled))
#endif
{
/* XXX: Debug: Comment this out to disable all texturing: */
#if 1
GE (glEnable (gl_target));
#endif
}
}
else
@ -1369,18 +1490,30 @@ _cogl_material_flush_layers_gl_state (CoglMaterial *material,
}
static void
_cogl_material_flush_base_gl_state (CoglMaterial *material)
_cogl_material_flush_base_gl_state (CoglMaterial *material,
gboolean skip_gl_color)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
/* XXX:
* Currently we only don't update state when the flags indicate that the
* current material uses the defaults, and the new material also uses the
* defaults, but we could do deeper comparisons of state. */
if (!skip_gl_color)
{
/* GLES doesn't have glColor4fv... */
GE (glColor4f (material->unlit[0],
material->unlit[1],
material->unlit[2],
material->unlit[3]));
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR) ||
/* Assume if we were previously told to skip the color, then
* the current color needs updating... */
ctx->current_material_flush_options.flags &
COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)
{
GE (glColor4ub (material->unlit[0],
material->unlit[1],
material->unlit[2],
material->unlit[3]));
}
}
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL
@ -1401,8 +1534,8 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
GE (glAlphaFunc (material->alpha_func, material->alpha_func_reference));
}
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND_FUNC))
if (!(ctx->current_material_flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND
&& material->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
{
#if defined (HAVE_COGL_GLES2)
gboolean have_blend_equation_seperate = TRUE;
@ -1441,32 +1574,33 @@ _cogl_material_flush_base_gl_state (CoglMaterial *material)
}
void
_cogl_material_flush_gl_state (CoglHandle handle, ...)
_cogl_material_flush_gl_state (CoglHandle handle,
CoglMaterialFlushOptions *options)
{
CoglMaterial *material;
va_list ap;
CoglMaterialFlushOption option;
guint32 fallback_layers = 0;
guint32 disable_layers = 0;
GLuint layer0_override_texture = 0;
CoglMaterial *material;
guint32 fallback_layers = 0;
guint32 disable_layers = 0;
GLuint layer0_override_texture = 0;
gboolean skip_gl_color = FALSE;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
material = _cogl_material_pointer_from_handle (handle);
_cogl_material_flush_base_gl_state (material);
va_start (ap, handle);
while ((option = va_arg (ap, CoglMaterialFlushOption)))
if (options)
{
if (option == COGL_MATERIAL_FLUSH_FALLBACK_MASK)
fallback_layers = va_arg (ap, guint32);
else if (option == COGL_MATERIAL_FLUSH_DISABLE_MASK)
disable_layers = va_arg (ap, guint32);
else if (option == COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
layer0_override_texture = va_arg (ap, GLuint);
if (options->flags & COGL_MATERIAL_FLUSH_FALLBACK_MASK)
fallback_layers = options->fallback_layers;
if (options->flags & COGL_MATERIAL_FLUSH_DISABLE_MASK)
disable_layers = options->disable_layers;
if (options->flags & COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE)
layer0_override_texture = options->layer0_override_texture;
if (options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)
skip_gl_color = TRUE;
}
va_end (ap);
_cogl_material_flush_base_gl_state (material,
skip_gl_color);
_cogl_material_flush_layers_gl_state (material,
fallback_layers,
@ -1483,6 +1617,162 @@ _cogl_material_flush_gl_state (CoglHandle handle, ...)
ctx->current_material = handle;
ctx->current_material_flags = material->flags;
if (options)
ctx->current_material_flush_options = *options;
else
memset (&ctx->current_material_flush_options,
0, sizeof (CoglMaterialFlushOptions));
}
gboolean
_cogl_material_equal (CoglHandle material0_handle,
CoglMaterialFlushOptions *material0_flush_options,
CoglHandle material1_handle,
CoglMaterialFlushOptions *material1_flush_options,
CoglMaterialEqualFlags flags)
{
CoglMaterial *material0;
CoglMaterial *material1;
GList *l0, *l1;
if (material0_handle == material1_handle &&
material0_flush_options->flags == material1_flush_options->flags)
return TRUE;
if (!(flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS))
{
g_critical ("FIXME: _cogl_material_equal doesn't yet support "
"deep comparisons of materials");
return FALSE;
}
/* Note: the following code is written with the assumption this
* constraint will go away*/
material0 = _cogl_material_pointer_from_handle (material0_handle);
material1 = _cogl_material_pointer_from_handle (material1_handle);
if (!((material0_flush_options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR &&
material1_flush_options->flags & COGL_MATERIAL_FLUSH_SKIP_GL_COLOR)))
{
if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR) !=
(material1->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
return FALSE;
else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
!(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_COLOR))
return FALSE;
else if (!memcmp (material0->unlit, material1->unlit,
sizeof (material0->unlit)))
return FALSE;
}
if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL) !=
(material1->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL))
return FALSE;
else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
!(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_GL_MATERIAL))
return FALSE;
#if 0
else if (!_deep_are_gl_materials_equal ())
return FALSE;
#endif
if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC) !=
(material1->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC))
return FALSE;
else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
!(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_ALPHA_FUNC))
return FALSE;
#if 0
else if (!_deep_are_alpha_funcs_equal ())
return FALSE;
#endif
if ((material0->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND) !=
(material1->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND))
return FALSE;
/* XXX: potentially blending could be "enabled" but the blend mode
* could be equivalent to being disabled. */
if (material0->flags & COGL_MATERIAL_FLAG_ENABLE_BLEND)
{
if ((material0->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND) !=
(material1->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
return FALSE;
else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
!(material0->flags & COGL_MATERIAL_FLAG_DEFAULT_BLEND))
return FALSE;
#if 0
else if (!_deep_is_blend_equal ())
return FALSE;
#endif
}
if (material0_flush_options->fallback_layers !=
material1_flush_options->fallback_layers ||
material0_flush_options->disable_layers !=
material1_flush_options->disable_layers)
return FALSE;
l0 = material0->layers;
l1 = material1->layers;
while (l0 && l1)
{
CoglMaterialLayer *layer0;
CoglMaterialLayer *layer1;
if ((l0 == NULL && l1 != NULL) ||
(l1 == NULL && l0 != NULL))
return FALSE;
layer0 = l0->data;
layer1 = l1->data;
if (layer0->texture != layer1->texture)
return FALSE;
if ((layer0->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE) !=
(layer1->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE))
return FALSE;
else if (flags & COGL_MATERIAL_EQUAL_FLAGS_ASSERT_ALL_DEFAULTS &&
!(layer0->flags & COGL_MATERIAL_LAYER_FLAG_DEFAULT_COMBINE))
return FALSE;
#if 0
else if (!_deep_are_layer_combines_equal ())
return FALSE;
#endif
l0 = l0->next;
l1 = l1->next;
}
if ((l0 == NULL && l1 != NULL) ||
(l1 == NULL && l0 != NULL))
return FALSE;
return TRUE;
}
/* While a material is referenced by the Cogl journal we can not allow
* modifications, so this gives us a mechanism to track journal
* references separately */
CoglHandle
_cogl_material_journal_ref (CoglHandle material_handle)
{
CoglMaterial *material =
material = _cogl_material_pointer_from_handle (material_handle);
material->journal_ref_count++;
cogl_handle_ref (material_handle);
return material_handle;
}
void
_cogl_material_journal_unref (CoglHandle material_handle)
{
CoglMaterial *material =
material = _cogl_material_pointer_from_handle (material_handle);
material->journal_ref_count--;
cogl_handle_unref (material_handle);
}
/* TODO: Should go in cogl.c, but that implies duplication which is also
@ -1558,6 +1848,9 @@ cogl_material_set_layer_filters (CoglHandle handle,
material = _cogl_material_pointer_from_handle (handle);
layer = _cogl_material_get_layer (material, layer_index, TRUE);
/* possibly flush primitives referencing the current state... */
_cogl_material_pre_change_notify (material, FALSE, NULL);
layer->min_filter = min_filter;
layer->mag_filter = mag_filter;
}

File diff suppressed because it is too large Load Diff

View File

@ -57,4 +57,6 @@ struct _CoglBezCubic
floatVec2 p4;
};
void _cogl_journal_flush (void);
#endif /* __COGL_PRIMITIVES_H */

View File

@ -137,6 +137,7 @@
#include "cogl-vertex-buffer-private.h"
#include "cogl-texture-private.h"
#include "cogl-material-private.h"
#include "cogl-primitives.h"
#define PAD_FOR_ALIGNMENT(VAR, TYPE_SIZE) \
(VAR = TYPE_SIZE + ((VAR - 1) & ~(TYPE_SIZE - 1)))
@ -1500,9 +1501,10 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
gulong enable_flags = 0;
guint max_texcoord_attrib_unit = 0;
const GList *layers;
guint32 fallback_mask = 0;
guint32 disable_mask = ~0;
guint32 fallback_layers = 0;
guint32 disable_layers = ~0;
int i;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
@ -1573,7 +1575,7 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
pointer));
if (attribute->texture_unit > max_texcoord_attrib_unit)
max_texcoord_attrib_unit = attribute->texture_unit;
disable_mask &= ~(1 << attribute->texture_unit);
disable_layers &= ~(1 << attribute->texture_unit);
break;
case COGL_VERTEX_BUFFER_ATTRIB_FLAG_VERTEX_ARRAY:
enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
@ -1638,17 +1640,24 @@ enable_state_for_drawing_buffer (CoglVertexBuffer *buffer)
* vertices once for each layer, each time with a fiddled texture
* matrix.
*/
fallback_mask |= (1 << i);
fallback_layers |= (1 << i);
}
}
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_FALLBACK_MASK,
fallback_mask,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
disable_mask,
NULL);
for (i = max_texcoord_attrib_unit + 1; i < ctx->n_texcoord_arrays_enabled; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
}
ctx->n_texcoord_arrays_enabled = max_texcoord_attrib_unit + 1;
options.flags =
COGL_MATERIAL_FLUSH_FALLBACK_MASK |
COGL_MATERIAL_FLUSH_DISABLE_MASK;
options.fallback_layers = fallback_layers;
options.disable_layers = disable_layers;
_cogl_material_flush_gl_state (ctx->source_material, &options);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
@ -1730,6 +1739,9 @@ cogl_vertex_buffer_draw (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
cogl_clip_ensure ();
@ -1859,6 +1871,9 @@ cogl_vertex_buffer_draw_elements (CoglHandle handle,
if (!cogl_is_vertex_buffer (handle))
return;
_cogl_journal_flush ();
cogl_clip_ensure ();
buffer = _cogl_vertex_buffer_pointer_from_handle (handle);
if (!cogl_is_vertex_buffer_indices (indices_handle))

View File

@ -216,6 +216,9 @@ cogl_get_enable ()
void
cogl_set_depth_test_enabled (gboolean setting)
{
/* Currently the journal can't track changes to depth state... */
_cogl_journal_flush ();
if (setting)
{
glEnable (GL_DEPTH_TEST);
@ -236,6 +239,9 @@ cogl_set_backface_culling_enabled (gboolean setting)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* Currently the journal can't track changes to backface culling state... */
_cogl_journal_flush ();
ctx->enable_backface_culling = setting;
}
@ -388,9 +394,15 @@ _cogl_add_stencil_clip (float x_offset,
float height,
gboolean first)
{
CoglHandle current_source;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
_cogl_journal_flush ();
/* temporarily swap in our special stenciling material */
current_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
if (first)
{
@ -443,9 +455,17 @@ _cogl_add_stencil_clip (float x_offset,
_cogl_set_current_matrix (COGL_MATRIX_MODELVIEW);
}
/* make sure our rectangles hit the stencil buffer before we restore
* the stencil function / operation */
_cogl_journal_flush ();
/* Restore the stencil mode */
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
/* restore the original source material */
cogl_set_source (current_source);
cogl_handle_unref (current_source);
}
void
@ -554,6 +574,9 @@ cogl_get_features (void)
if (!ctx->features_cached)
_cogl_features_init ();
if (cogl_debug_flags & COGL_DEBUG_DISABLE_VBOS)
ctx->feature_flags &= ~COGL_FEATURE_VBOS;
return ctx->feature_flags;
}
@ -630,6 +653,9 @@ cogl_set_fog (const CoglColor *fog_color,
GLfloat fogColor[4];
GLenum gl_mode = GL_LINEAR;
/* The cogl journal doesn't currently track fog state changes */
_cogl_journal_flush ();
fogColor[0] = cogl_color_get_red_float (fog_color);
fogColor[1] = cogl_color_get_green_float (fog_color);
fogColor[2] = cogl_color_get_blue_float (fog_color);
@ -667,6 +693,9 @@ cogl_set_fog (const CoglColor *fog_color,
void
cogl_disable_fog (void)
{
/* Currently the journal can't track changes to fog state... */
_cogl_journal_flush ();
glDisable (GL_FOG);
}
@ -678,6 +707,12 @@ cogl_flush_gl_state (int flags)
}
#endif
void
cogl_flush (void)
{
_cogl_journal_flush ();
}
void
cogl_read_pixels (int x,
int y,
@ -711,6 +746,10 @@ cogl_read_pixels (int x,
glPixelStorei (GL_PACK_SKIP_ROWS, 0);
#endif /* HAVE_COGL_GL */
/* make sure any batched primitives get emitted to the GL driver before
* issuing our read pixels... */
cogl_flush ();
glReadPixels (x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
/* TODO: consider using the GL_MESA_pack_invert extension in the future
@ -732,3 +771,78 @@ cogl_read_pixels (int x,
}
}
void
cogl_begin_gl (void)
{
CoglMaterialFlushOptions options;
gulong enable_flags;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (ctx->in_begin_gl_block)
{
static gboolean shown = FALSE;
if (!shown)
g_warning ("You should not nest cogl_begin_gl/cogl_end_gl blocks");
shown = TRUE;
return;
}
ctx->in_begin_gl_block = TRUE;
/* Flush all batched primitives */
cogl_flush ();
/* Flush our clipping state to GL */
cogl_clip_ensure ();
/* Flush any client side matrix state */
_cogl_current_matrix_state_flush ();
/* Setup the state for the current material */
/* We considered flushing a specific, minimal material here to try and
* simplify the GL state, but decided to avoid special cases and second
* guessing what would be actually helpful.
*
* A user should instead call cogl_set_source_color4ub() before
* cogl_begin_gl() to simplify the state flushed.
*/
options.flags = 0;
_cogl_material_flush_gl_state (ctx->source_material, &options);
/* FIXME: This api is a bit yukky, ideally it will be removed if we
* re-work the cogl_enable mechanism */
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
if (ctx->enable_backface_culling)
enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
cogl_enable (enable_flags);
/* Disable all client texture coordinate arrays */
for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
}
ctx->n_texcoord_arrays_enabled = 0;
}
void
cogl_end_gl (void)
{
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
if (!ctx->in_begin_gl_block)
{
static gboolean shown = FALSE;
if (!shown)
g_warning ("cogl_end_gl is being called before cogl_begin_gl");
shown = TRUE;
return;
}
ctx->in_begin_gl_block = FALSE;
}

View File

@ -69,9 +69,13 @@ cogl_create_context ()
_context->journal = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
_context->logged_vertices = g_array_new (FALSE, FALSE, sizeof (GLfloat));
_context->journal_vbo = 0;
_context->journal_vbo_len = 0;
_context->current_material = NULL;
_context->current_material_flags = 0;
memset (&_context->current_material_flush_options,
0, sizeof (CoglMaterialFlushOptions));
_context->current_layers = g_array_new (FALSE, FALSE,
sizeof (CoglLayerInfo));
_context->n_texcoord_arrays_enabled = 0;
@ -86,6 +90,8 @@ cogl_create_context ()
_context->last_path = 0;
_context->stencil_material = cogl_material_new ();
_context->in_begin_gl_block = FALSE;
_context->pf_glGenRenderbuffersEXT = NULL;
_context->pf_glBindRenderbufferEXT = NULL;
_context->pf_glRenderbufferStorageEXT = NULL;

View File

@ -28,6 +28,7 @@
#include "cogl-clip-stack.h"
#include "cogl-matrix-stack.h"
#include "cogl-current-matrix.h"
#include "cogl-material-private.h"
typedef struct
{
@ -78,10 +79,13 @@ typedef struct
* can batch things together. */
GArray *journal;
GArray *logged_vertices;
GLuint journal_vbo;
size_t journal_vbo_len;
/* Some simple caching, to minimize state changes... */
CoglHandle current_material;
gulong current_material_flags;
CoglMaterialFlushOptions current_material_flush_options;
GArray *current_layers;
guint n_texcoord_arrays_enabled;
@ -106,6 +110,8 @@ typedef struct
guint quad_indices_short_len;
CoglHandle quad_indices_short;
gboolean in_begin_gl_block;
/* Relying on glext.h to define these */
COGL_PFNGLGENRENDERBUFFERSEXTPROC pf_glGenRenderbuffersEXT;
COGL_PFNGLDELETERENDERBUFFERSEXTPROC pf_glDeleteRenderbuffersEXT;

View File

@ -169,6 +169,8 @@ cogl_set_draw_buffer (CoglBufferTarget target, CoglHandle offscreen)
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
g_assert (ctx->draw_buffer_stack != NULL);
draw_buffer = ctx->draw_buffer_stack->data;

View File

@ -76,16 +76,18 @@ _cogl_path_stroke_nodes ()
{
guint path_start = 0;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglMaterialFlushOptions options;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
enable_flags |= _cogl_material_get_cogl_enable_flags (ctx->source_material);
cogl_enable (enable_flags);
_cogl_material_flush_gl_state (ctx->source_material,
COGL_MATERIAL_FLUSH_DISABLE_MASK,
(guint32)~0, /* disable all texture layers */
NULL);
options.flags = COGL_MATERIAL_FLUSH_DISABLE_MASK;
/* disable all texture layers */
options.disable_layers = (guint32)~0;
_cogl_material_flush_gl_state (ctx->source_material, &options);
_cogl_current_matrix_state_flush ();
while (path_start < ctx->path_nodes->len)
@ -123,18 +125,25 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
CoglPathNode *path,
gboolean merge)
{
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
guint path_start = 0;
guint sub_path_num = 0;
float bounds_x;
float bounds_y;
float bounds_w;
float bounds_h;
gulong enable_flags = COGL_ENABLE_VERTEX_ARRAY;
CoglHandle prev_source;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
_cogl_journal_flush ();
/* Just setup a simple material that doesn't use texturing... */
_cogl_material_flush_gl_state (ctx->stencil_material, NULL);
prev_source = cogl_handle_ref (ctx->source_material);
cogl_set_source (ctx->stencil_material);
_cogl_material_flush_gl_state (ctx->source_material, NULL);
enable_flags |=
_cogl_material_get_cogl_enable_flags (ctx->source_material);
@ -161,7 +170,15 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glColorMask (FALSE, FALSE, FALSE, FALSE) );
GE( glDepthMask (FALSE) );
for (i = 0; i < ctx->n_texcoord_arrays_enabled; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
}
ctx->n_texcoord_arrays_enabled = 0;
_cogl_current_matrix_state_flush ();
while (path_start < path_size)
{
GE( glVertexPointer (2, GL_FLOAT, sizeof (CoglPathNode),
@ -175,9 +192,8 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
significant bit */
GE( glStencilMask (merge ? 6 : 3) );
GE( glStencilOp (GL_ZERO, GL_REPLACE, GL_REPLACE) );
cogl_rectangle (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
glRectf (bounds_x, bounds_y,
bounds_x + bounds_w, bounds_y + bounds_h);
GE( glStencilOp (GL_INVERT, GL_INVERT, GL_INVERT) );
}
@ -210,8 +226,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
_cogl_current_matrix_push ();
_cogl_current_matrix_identity ();
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
cogl_rectangle (-1.0, -1.0, 1.0, 1.0);
_cogl_current_matrix_state_flush ();
glRectf (-1.0, -1.0, 1.0, 1.0);
glRectf (-1.0, -1.0, 1.0, 1.0);
_cogl_current_matrix_pop ();
@ -227,6 +245,10 @@ _cogl_add_path_to_stencil_buffer (floatVec2 nodes_min,
GE( glStencilFunc (GL_EQUAL, 0x1, 0x1) );
GE( glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP) );
/* restore the original material */
cogl_set_source (prev_source);
cogl_handle_unref (prev_source);
}
void

View File

@ -128,6 +128,11 @@ cogl_program_use (CoglHandle handle)
if (handle != COGL_INVALID_HANDLE && !cogl_is_program (handle))
return;
/* The Cogl journal doesn't currently cope with the use of
* shaders so we have to flush all priitives whenever the
* current shader changes... */
_cogl_journal_flush ();
if (handle == COGL_INVALID_HANDLE)
gl_handle = 0;
else

View File

@ -26,6 +26,7 @@
#include "cogl-bitmap-private.h"
#include "cogl-handle.h"
#include "cogl-material-private.h"
typedef struct _CoglTexture CoglTexture;
typedef struct _CoglTexSliceSpan CoglTexSliceSpan;
@ -99,10 +100,13 @@ struct _CoglTexture
* later flush the journal we aim to batch data, and gl draw calls. */
typedef struct _CoglJournalEntry
{
CoglHandle material;
gint n_layers;
guint32 fallback_mask;
GLuint layer0_override_texture;
CoglHandle material;
int n_layers;
CoglMaterialFlushOptions flush_options;
CoglMatrix model_view;
/* XXX: These entries are pretty big now considering the padding in
* CoglMaterialFlushOptions and CoglMatrix, so we might need to optimize this
* later. */
} CoglJournalEntry;
CoglTexture*

View File

@ -39,6 +39,7 @@
#include "cogl-material.h"
#include "cogl-context.h"
#include "cogl-handle.h"
#include "cogl-primitives.h"
#include <string.h>
#include <stdlib.h>
@ -60,8 +61,6 @@
#endif
extern void _cogl_journal_flush (void);
static void _cogl_texture_free (CoglTexture *tex);
COGL_HANDLE_DEFINE (Texture, texture);

View File

@ -1480,6 +1480,13 @@ cogl_wrap_glColor4f (GLclampf r, GLclampf g, GLclampf b, GLclampf a)
glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB, r, g, b, a);
}
void
cogl_wrap_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a)
{
glVertexAttrib4f (COGL_GLES2_WRAPPER_COLOR_ATTRIB,
r/255.0, g/255.0, b/255.0, a/255.0);
}
void
cogl_wrap_glClipPlanef (GLenum plane, GLfloat *equation)
{

View File

@ -340,6 +340,7 @@ void cogl_wrap_glDisableClientState (GLenum array);
void cogl_wrap_glAlphaFunc (GLenum func, GLclampf ref);
void cogl_wrap_glColor4f (GLclampf r, GLclampf g, GLclampf b, GLclampf a);
void cogl_wrap_glColor4ub (GLubyte r, GLubyte g, GLubyte b, GLubyte a);
void cogl_wrap_glClipPlanef (GLenum plane, GLfloat *equation);
@ -393,6 +394,7 @@ void _cogl_gles2_clear_cache_for_program (CoglHandle program);
#define glDisableClientState cogl_wrap_glDisableClientState
#define glAlphaFunc cogl_wrap_glAlphaFunc
#define glColor4f cogl_wrap_glColor4f
#define glColor4ub cogl_wrap_glColor4ub
#define glClipPlanef cogl_wrap_glClipPlanef
#define glGetIntegerv cogl_wrap_glGetIntegerv
#define glGetFloatv cogl_wrap_glGetFloatv

View File

@ -81,6 +81,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
eglWaitGL();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);

View File

@ -139,6 +139,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted as well */
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
/* Why this paint is done in backend as likely GL windowing system
* specific calls, like swapping buffers.

View File

@ -72,6 +72,7 @@ clutter_backend_egl_redraw (ClutterBackend *backend,
eglWaitNative (EGL_CORE_NATIVE_ENGINE);
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
eglWaitGL();
eglSwapBuffers (backend_egl->edpy, stage_egl->egl_surface);
}

View File

@ -498,6 +498,7 @@ clutter_backend_glx_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
if (stage_x11->xwin != None)
{

View File

@ -128,6 +128,7 @@ clutter_stage_osx_state_update (ClutterStageOSX *self,
- (void) drawRect: (NSRect) bounds
{
clutter_actor_paint (CLUTTER_ACTOR (self->stage_osx->wrapper));
cogl_flush ();
[[self openGLContext] flushBuffer];
}

View File

@ -138,8 +138,7 @@ _cogl_pango_display_list_add_texture (CoglPangoDisplayList *dl,
&& (node = dl->last_node->data)->type == COGL_PANGO_DISPLAY_LIST_TEXTURE
&& node->d.texture.texture == texture
&& (dl->color_override
? (node->color_override && !memcmp (&dl->color, &node->color,
sizeof (CoglColor)))
? (node->color_override && cogl_color_equal (&dl->color, &node->color))
: !node->color_override))
{
/* Get rid of the vertex buffer so that it will be recreated */
@ -245,6 +244,39 @@ _cogl_pango_display_list_render_texture (CoglHandle material,
cogl_material_set_color (material, &premult_color);
cogl_set_source (material);
/* For small runs of text like icon labels, we can get better performance
* going through the Cogl journal since text may then be batched together
* with other geometry. */
/* FIXME: 100 is a number I plucked out of thin air; it would be good
* to determine this empirically! */
if (node->d.texture.verts->len < 100)
{
int i;
for (i = 0; i < node->d.texture.verts->len; i += 4)
{
CoglPangoDisplayListVertex *v0 =
&g_array_index (node->d.texture.verts,
CoglPangoDisplayListVertex, i);
CoglPangoDisplayListVertex *v1 =
&g_array_index (node->d.texture.verts,
CoglPangoDisplayListVertex, i + 2);
cogl_rectangle_with_texture_coords (v0->x, v0->y, v1->x, v1->y,
v0->t_x, v0->t_y,
v1->t_x, v1->t_y);
}
return;
}
/* It's expensive to go through the Cogl journal for large runs
* of text in part because the journal transforms the quads in software
* to avoid changing the modelview matrix. So for larger runs of text
* we load the vertices into a VBO, and this has the added advantage
* that if the text doesn't change from frame to frame the VBO can
* be re-used avoiding the repeated cost of validating the data and
* mapping it into the GPU... */
if (node->d.texture.vertex_buffer == COGL_INVALID_HANDLE)
{
CoglHandle vb = cogl_vertex_buffer_new (node->d.texture.verts->len);

View File

@ -68,7 +68,8 @@ clutter_backend_sdl_redraw (ClutterBackend *backend,
ClutterStage *stage)
{
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
SDL_GL_SwapBuffers();
}

View File

@ -297,6 +297,7 @@ clutter_backend_win32_redraw (ClutterBackend *backend,
/* this will cause the stage implementation to be painted */
clutter_actor_paint (CLUTTER_ACTOR (stage));
cogl_flush ();
if (stage_win32->client_dc)
SwapBuffers (stage_win32->client_dc);

View File

@ -72,6 +72,11 @@ cogl_set_source_texture
CoglReadPixelsFlags
cogl_read_pixels
<SUBSECTION>
cogl_flush
cogl_begin_gl
cogl_end_gl
<SUBSECTION Standard>
COGL_TYPE_ATTRIBUTE_TYPE
COGL_TYPE_BUFFER_BIT