[journal] Always pad our vertex data as if at least 2 layers are enabled

The number of material layers enabled when logging a quad in the journal
determines the stride of the corresponding vertex data (since we need a set
of texture coordinates for each layer.) By padding data in the case where we
have only one layer we can avoid a change in stride if we are mixing single
and double layer primitives in a scene (e.g.  relevent for a composite
manager that may use 2 layers for all shaped windows) Avoiding stride
changes means we can minimize calls to gl{Vertex,Color}Pointer when flushing
the journal.

Since we need to update the texcoord pointers when the actual number of
layers changes, this adds another batch_and_call() stage to deal with
glTexCoordPointer and enabling/disabling the client arrays.
This commit is contained in:
Robert Bragg 2009-06-10 13:59:45 +01:00
parent 2b9478a665
commit 2f367cc802

View File

@ -61,11 +61,16 @@
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
*
* So for a given number of layers this gets the stride in
* 32bit words:
* Where n_layers corresponds to the number of material layers enabled
*
* To avoid frequent changes in the stride of our vertex data we always pad
* n_layers to be >= 2
*
* So for a given number of layers this gets the stride in 32bit words:
*/
#define MIN_LAYER_PADING 2
#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
(2 + 1 + 2 * (N_LAYERS))
(2 + 1 + 2 * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
@ -76,6 +81,7 @@ typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
typedef struct _CoglJournalFlushState
{
size_t stride;
/* Note: this is a pointer to handle fallbacks. It normally holds a VBO
* offset, but when the driver doesn't support VBOs then this points into
* our GArray of logged vertices. */
@ -303,43 +309,35 @@ compare_entry_materials (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
return FALSE;
}
/* At this point we know the stride has changed from the previous batch
* of journal entries */
/* Since the stride may not reflect the number of texture layers in use
* (due to padding) we deal with texture coordinate offsets separately
* from vertex and color offsets... */
static void
_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
gint batch_len,
void *data)
_cogl_journal_flush_texcoord_vbo_offsets_and_entries (
CoglJournalEntry *batch_start,
gint batch_len,
void *data)
{
CoglJournalFlushState *state = data;
size_t stride;
int i;
int prev_n_texcoord_arrays_enabled;
#ifndef HAVE_COGL_GL
int needed_indices = batch_len * 6;
CoglHandle indices_handle;
CoglVertexBufferIndices *indices;
#endif
CoglJournalFlushState *state = data;
int prev_n_texcoord_arrays_enabled;
int i;
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* XXX NB:
* Our vertex data is arranged as follows:
* 4 vertices per quad: 2 GLfloats per position,
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
*/
stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
stride *= sizeof (GLfloat);
GE (glVertexPointer (2, GL_FLOAT, stride, (void *)state->vbo_offset));
GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
(void *)(state->vbo_offset + 8)));
for (i = 0; i < batch_start->n_layers; i++)
{
GE (glClientActiveTexture (GL_TEXTURE0 + i));
GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
GE (glTexCoordPointer (2, GL_FLOAT, stride,
/* XXX NB:
* Our journal's vertex data is arranged as follows:
* 4 vertices per quad:
* 2 GLfloats per position
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
* (though n_layers may be padded; see definition of
* GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
*/
GE (glTexCoordPointer (2, GL_FLOAT, state->stride,
(void *)(state->vbo_offset + 12 + 8 * i)));
}
prev_n_texcoord_arrays_enabled =
@ -351,6 +349,56 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
}
batch_and_call (batch_start,
batch_len,
compare_entry_materials,
_cogl_journal_flush_material_and_entries,
data);
}
static gboolean
compare_entry_n_layers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
{
if (entry0->n_layers == entry1->n_layers)
return TRUE;
else
return FALSE;
}
/* At this point we know the stride has changed from the previous batch
* of journal entries */
static void
_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
gint batch_len,
void *data)
{
CoglJournalFlushState *state = data;
size_t stride;
#ifndef HAVE_COGL_GL
int needed_indices = batch_len * 6;
CoglHandle indices_handle;
CoglVertexBufferIndices *indices;
#endif
_COGL_GET_CONTEXT (ctx, NO_RETVAL);
/* XXX NB:
* Our journal's vertex data is arranged as follows:
* 4 vertices per quad:
* 2 GLfloats per position
* 4 RGBA GLubytes,
* 2 GLfloats per tex coord * n_layers
* (though n_layers may be padded; see definition of
* GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
*/
stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
stride *= sizeof (GLfloat);
state->stride = stride;
GE (glVertexPointer (2, GL_FLOAT, stride, (void *)state->vbo_offset));
GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
(void *)(state->vbo_offset + 8)));
#ifndef HAVE_COGL_GL
indices_handle = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
@ -384,8 +432,8 @@ _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
batch_and_call (batch_start,
batch_len,
compare_entry_materials,
_cogl_journal_flush_material_and_entries,
compare_entry_n_layers,
_cogl_journal_flush_texcoord_vbo_offsets_and_entries,
data);
#ifndef HAVE_COGL_GL
@ -402,9 +450,9 @@ compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
/* Currently the only thing that affects the stride for our vertex arrays
* is the number of material layers. We need to update our VBO offsets
* whenever the stride changes. */
/* TODO: We should be padding the n_layers == 1 case as if it were
* n_layers == 2 so we can reduce the need to split batches. */
if (entry0->n_layers == entry1->n_layers)
if (entry0->n_layers == entry1->n_layers ||
(entry0->n_layers <= MIN_LAYER_PADING &&
entry1->n_layers <= MIN_LAYER_PADING))
return TRUE;
else
return FALSE;