~ubuntu-branches/ubuntu/vivid/clutter-1.0/vivid-proposed

« back to all changes in this revision

Viewing changes to clutter/cogl/cogl/cogl-journal.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort
  • Date: 2010-07-18 17:21:49 UTC
  • mfrom: (1.2.1 upstream) (4.1.3 experimental)
  • Revision ID: james.westby@ubuntu.com-20100718172149-j6s9u4chocaoykme
Tags: 1.2.12-1
* New upstream release.
* debian/libclutter-1.0-0.symbols,
  debian/rules:
  - Add a symbols file.
* debian/rules,
  debian/source/format:
  - Switch to source format 3.0 (quilt).
* debian/control.in:
  - Standards-Version is 3.9.0, no changes needed.
* Upload to unstable.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Cogl
 
3
 *
 
4
 * An object oriented GL/GLES Abstraction/Utility Layer
 
5
 *
 
6
 * Copyright (C) 2007,2008,2009 Intel Corporation.
 
7
 *
 
8
 * This library is free software; you can redistribute it and/or
 
9
 * modify it under the terms of the GNU Lesser General Public
 
10
 * License as published by the Free Software Foundation; either
 
11
 * version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 * This library is distributed in the hope that it will be useful,
 
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 * Lesser General Public License for more details.
 
17
 *
 
18
 * You should have received a copy of the GNU Lesser General Public
 
19
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
 
20
 *
 
21
 *
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include "config.h"
 
26
#endif
 
27
 
 
28
#include "cogl.h"
 
29
#include "cogl-internal.h"
 
30
#include "cogl-context.h"
 
31
#include "cogl-journal-private.h"
 
32
#include "cogl-texture-private.h"
 
33
#include "cogl-material-private.h"
 
34
#include "cogl-vertex-buffer-private.h"
 
35
#include "cogl-framebuffer-private.h"
 
36
#include "cogl-profile.h"
 
37
 
 
38
#include <string.h>
 
39
#include <gmodule.h>
 
40
#include <math.h>
 
41
 
 
42
#define _COGL_MAX_BEZ_RECURSE_DEPTH 16
 
43
 
 
44
#ifdef HAVE_COGL_GL
 
45
 
 
46
#define glGenBuffers ctx->drv.pf_glGenBuffers
 
47
#define glBindBuffer ctx->drv.pf_glBindBuffer
 
48
#define glBufferData ctx->drv.pf_glBufferData
 
49
#define glBufferSubData ctx->drv.pf_glBufferSubData
 
50
#define glDeleteBuffers ctx->drv.pf_glDeleteBuffers
 
51
#define glClientActiveTexture ctx->drv.pf_glClientActiveTexture
 
52
 
 
53
#elif defined (HAVE_COGL_GLES2)
 
54
 
 
55
#include "../gles/cogl-gles2-wrapper.h"
 
56
 
 
57
#endif
 
58
 
 
59
/* XXX NB:
 
60
 * Our journal's vertex data is arranged as follows:
 
61
 * 4 vertices per quad:
 
62
 *    2 or 3 GLfloats per position (3 when doing software transforms)
 
63
 *    4 RGBA GLubytes,
 
64
 *    2 GLfloats per tex coord * n_layers
 
65
 *
 
66
 * Where n_layers corresponds to the number of material layers enabled
 
67
 *
 
68
 * To avoid frequent changes in the stride of our vertex data we always pad
 
69
 * n_layers to be >= 2
 
70
 *
 
71
 * When we are transforming quads in software we need to also track the z
 
72
 * coordinate of transformed vertices.
 
73
 *
 
74
 * So for a given number of layers this gets the stride in 32bit words:
 
75
 */
 
76
#define SW_TRANSFORM      (!(cogl_debug_flags & \
 
77
                             COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
78
#define POS_STRIDE        (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
 
79
#define N_POS_COMPONENTS  POS_STRIDE
 
80
#define COLOR_STRIDE      1 /* number of 32bit words */
 
81
#define TEX_STRIDE        2 /* number of 32bit words */
 
82
#define MIN_LAYER_PADING  2
 
83
#define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
 
84
  (POS_STRIDE + COLOR_STRIDE + \
 
85
   TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
 
86
 
 
87
typedef CoglVertexBufferIndices  CoglJournalIndices;
 
88
 
 
89
typedef struct _CoglJournalFlushState
 
90
{
 
91
  gsize              stride;
 
92
  /* Note: this is a pointer to handle fallbacks. It normally holds a VBO
 
93
   * offset, but when the driver doesn't support VBOs then this points into
 
94
   * our GArray of logged vertices. */
 
95
  char *              vbo_offset;
 
96
  GLuint              vertex_offset;
 
97
#ifndef HAVE_COGL_GL
 
98
  CoglJournalIndices *indices;
 
99
  gsize              indices_type_size;
 
100
#endif
 
101
  CoglMatrixStack    *modelview_stack;
 
102
} CoglJournalFlushState;
 
103
 
 
104
typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
 
105
                                          int n_entries,
 
106
                                          void *data);
 
107
typedef gboolean (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
 
108
                                          CoglJournalEntry *entry1);
 
109
 
 
110
void
 
111
_cogl_journal_dump_quad_vertices (guint8 *data, int n_layers)
 
112
{
 
113
  gsize stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
 
114
  int i;
 
115
 
 
116
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
117
 
 
118
  g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; "
 
119
           "tex stride = %d; stride in bytes = %d\n",
 
120
           n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE,
 
121
           TEX_STRIDE, (int)stride * 4);
 
122
 
 
123
  for (i = 0; i < 4; i++)
 
124
    {
 
125
      float *v = (float *)data + (i * stride);
 
126
      guint8 *c = data + (POS_STRIDE * 4) + (i * stride * 4);
 
127
      int j;
 
128
 
 
129
      if (G_UNLIKELY (cogl_debug_flags &
 
130
                      COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
131
        g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
 
132
                 i, v[0], v[1], c[0], c[1], c[2], c[3]);
 
133
      else
 
134
        g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X",
 
135
                 i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]);
 
136
      for (j = 0; j < n_layers; j++)
 
137
        {
 
138
          float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j;
 
139
          g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
 
140
        }
 
141
      g_print ("\n");
 
142
    }
 
143
}
 
144
 
 
145
void
 
146
_cogl_journal_dump_quad_batch (guint8 *data, int n_layers, int n_quads)
 
147
{
 
148
  gsize byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
 
149
  int i;
 
150
 
 
151
  g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n",
 
152
           n_layers, n_quads);
 
153
  for (i = 0; i < n_quads; i++)
 
154
    _cogl_journal_dump_quad_vertices (data + byte_stride * 4 * i, n_layers);
 
155
}
 
156
 
 
157
static void
 
158
batch_and_call (CoglJournalEntry *entries,
 
159
                int n_entries,
 
160
                CoglJournalBatchTest can_batch_callback,
 
161
                CoglJournalBatchCallback batch_callback,
 
162
                void *data)
 
163
{
 
164
  int i;
 
165
  int batch_len = 1;
 
166
  CoglJournalEntry *batch_start = entries;
 
167
 
 
168
  if (n_entries < 1)
 
169
    return;
 
170
 
 
171
  for (i = 1; i < n_entries; i++)
 
172
    {
 
173
      CoglJournalEntry *entry0 = &entries[i - 1];
 
174
      CoglJournalEntry *entry1 = entry0 + 1;
 
175
 
 
176
      if (can_batch_callback (entry0, entry1))
 
177
        {
 
178
          batch_len++;
 
179
          continue;
 
180
        }
 
181
 
 
182
      batch_callback (batch_start, batch_len, data);
 
183
 
 
184
      batch_start = entry1;
 
185
      batch_len = 1;
 
186
    }
 
187
 
 
188
  /* The last batch... */
 
189
  batch_callback (batch_start, batch_len, data);
 
190
}
 
191
 
 
192
static void
 
193
_cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
 
194
                                           int               batch_len,
 
195
                                           void             *data)
 
196
{
 
197
  CoglJournalFlushState *state = data;
 
198
 
 
199
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
 
200
    g_print ("BATCHING:    modelview batch len = %d\n", batch_len);
 
201
 
 
202
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
203
    {
 
204
      _cogl_matrix_stack_set (state->modelview_stack,
 
205
                              &batch_start->model_view);
 
206
      _cogl_matrix_stack_flush_to_gl (state->modelview_stack,
 
207
                                      COGL_MATRIX_MODELVIEW);
 
208
    }
 
209
 
 
210
#ifdef HAVE_COGL_GL
 
211
 
 
212
  GE (glDrawArrays (GL_QUADS, state->vertex_offset, batch_len * 4));
 
213
 
 
214
#else /* HAVE_COGL_GL */
 
215
 
 
216
  if (batch_len > 1)
 
217
    {
 
218
      int indices_offset = (state->vertex_offset / 4) * 6;
 
219
      GE (glDrawElements (GL_TRIANGLES,
 
220
                          6 * batch_len,
 
221
                          state->indices->type,
 
222
                          (GLvoid*)(indices_offset * state->indices_type_size)));
 
223
    }
 
224
  else
 
225
    {
 
226
      GE (glDrawArrays (GL_TRIANGLE_FAN,
 
227
                        state->vertex_offset, /* first */
 
228
                        4)); /* n vertices */
 
229
    }
 
230
#endif
 
231
 
 
232
  /* DEBUGGING CODE XXX: This path will cause all rectangles to be
 
233
   * drawn with a coloured outline. Each batch will be rendered with
 
234
   * the same color. This may e.g. help with debugging texture slicing
 
235
   * issues, visually seeing what is batched and debugging blending
 
236
   * issues, plus it looks quite cool.
 
237
   */
 
238
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_RECTANGLES))
 
239
    {
 
240
      static CoglHandle outline = COGL_INVALID_HANDLE;
 
241
      guint8 color_intensity;
 
242
      int i;
 
243
 
 
244
      _COGL_GET_CONTEXT (ctxt, NO_RETVAL);
 
245
 
 
246
      if (outline == COGL_INVALID_HANDLE)
 
247
        outline = cogl_material_new ();
 
248
 
 
249
      /* The least significant three bits represent the three
 
250
         components so that the order of colours goes red, green,
 
251
         yellow, blue, magenta, cyan. Black and white are skipped. The
 
252
         next two bits give four scales of intensity for those colours
 
253
         in the order 0xff, 0xcc, 0x99, and 0x66. This gives a total
 
254
         of 24 colours. If there are more than 24 batches on the stage
 
255
         then it will wrap around */
 
256
      color_intensity = 0xff - 0x33 * (ctxt->journal_rectangles_color >> 3);
 
257
      cogl_material_set_color4ub (outline,
 
258
                                  (ctxt->journal_rectangles_color & 1) ?
 
259
                                  color_intensity : 0,
 
260
                                  (ctxt->journal_rectangles_color & 2) ?
 
261
                                  color_intensity : 0,
 
262
                                  (ctxt->journal_rectangles_color & 4) ?
 
263
                                  color_intensity : 0,
 
264
                                  0xff);
 
265
      _cogl_material_flush_gl_state (outline, NULL);
 
266
      cogl_enable (COGL_ENABLE_VERTEX_ARRAY);
 
267
      for (i = 0; i < batch_len; i++)
 
268
        GE( glDrawArrays (GL_LINE_LOOP, 4 * i + state->vertex_offset, 4) );
 
269
 
 
270
      /* Go to the next color */
 
271
      do
 
272
        ctxt->journal_rectangles_color = ((ctxt->journal_rectangles_color + 1) &
 
273
                                          ((1 << 5) - 1));
 
274
      /* We don't want to use black or white */
 
275
      while ((ctxt->journal_rectangles_color & 0x07) == 0
 
276
             || (ctxt->journal_rectangles_color & 0x07) == 0x07);
 
277
    }
 
278
 
 
279
  state->vertex_offset += (4 * batch_len);
 
280
}
 
281
 
 
282
static gboolean
 
283
compare_entry_modelviews (CoglJournalEntry *entry0,
 
284
                          CoglJournalEntry *entry1)
 
285
{
 
286
  /* Batch together quads with the same model view matrix */
 
287
 
 
288
  /* FIXME: this is nasty, there are much nicer ways to track this
 
289
   * (at the add_quad_vertices level) without resorting to a memcmp!
 
290
   *
 
291
   * E.g. If the cogl-current-matrix code maintained an "age" for
 
292
   * the modelview matrix we could simply check in add_quad_vertices
 
293
   * if the age has increased, and if so record the change as a
 
294
   * boolean in the journal.
 
295
   */
 
296
 
 
297
  if (memcmp (&entry0->model_view, &entry1->model_view,
 
298
              sizeof (GLfloat) * 16) == 0)
 
299
    return TRUE;
 
300
  else
 
301
    return FALSE;
 
302
}
 
303
 
 
304
/* At this point we have a run of quads that we know have compatible
 
305
 * materials, but they may not all have the same modelview matrix */
 
306
static void
 
307
_cogl_journal_flush_material_and_entries (CoglJournalEntry *batch_start,
 
308
                                          int               batch_len,
 
309
                                          void             *data)
 
310
{
 
311
  unsigned long enable_flags = 0;
 
312
 
 
313
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
314
 
 
315
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
 
316
    g_print ("BATCHING:   material batch len = %d\n", batch_len);
 
317
 
 
318
  _cogl_material_flush_gl_state (batch_start->material,
 
319
                                 &batch_start->flush_options);
 
320
 
 
321
  /* FIXME: This api is a bit yukky, ideally it will be removed if we
 
322
   * re-work the cogl_enable mechanism */
 
323
  enable_flags |= _cogl_material_get_cogl_enable_flags (batch_start->material);
 
324
 
 
325
  if (ctx->enable_backface_culling)
 
326
    enable_flags |= COGL_ENABLE_BACKFACE_CULLING;
 
327
 
 
328
  enable_flags |= COGL_ENABLE_VERTEX_ARRAY;
 
329
  enable_flags |= COGL_ENABLE_COLOR_ARRAY;
 
330
  cogl_enable (enable_flags);
 
331
  _cogl_flush_face_winding ();
 
332
 
 
333
  /* If we haven't transformed the quads in software then we need to also break
 
334
   * up batches according to changes in the modelview matrix... */
 
335
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
336
    {
 
337
      batch_and_call (batch_start,
 
338
                      batch_len,
 
339
                      compare_entry_modelviews,
 
340
                      _cogl_journal_flush_modelview_and_entries,
 
341
                      data);
 
342
    }
 
343
  else
 
344
    _cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data);
 
345
}
 
346
 
 
347
static gboolean
 
348
compare_entry_materials (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
 
349
{
 
350
  /* batch rectangles using compatible materials */
 
351
 
 
352
  /* XXX: _cogl_material_equal may give false negatives since it avoids
 
353
   * deep comparisons as an optimization. It aims to compare enough so
 
354
   * that we that we are able to batch the 90% common cases, but may not
 
355
   * look at less common differences. */
 
356
  if (_cogl_material_equal (entry0->material,
 
357
                            &entry0->flush_options,
 
358
                            entry1->material,
 
359
                            &entry1->flush_options))
 
360
    return TRUE;
 
361
  else
 
362
    return FALSE;
 
363
}
 
364
 
 
365
/* Since the stride may not reflect the number of texture layers in use
 
366
 * (due to padding) we deal with texture coordinate offsets separately
 
367
 * from vertex and color offsets... */
 
368
static void
 
369
_cogl_journal_flush_texcoord_vbo_offsets_and_entries (
 
370
                                          CoglJournalEntry *batch_start,
 
371
                                          int               batch_len,
 
372
                                          void             *data)
 
373
{
 
374
  CoglJournalFlushState *state = data;
 
375
  int                    prev_n_texcoord_arrays_enabled;
 
376
  int                    i;
 
377
 
 
378
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
379
 
 
380
  for (i = 0; i < batch_start->n_layers; i++)
 
381
    {
 
382
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
 
383
      GE (glEnableClientState (GL_TEXTURE_COORD_ARRAY));
 
384
      /* XXX NB:
 
385
       * Our journal's vertex data is arranged as follows:
 
386
       * 4 vertices per quad:
 
387
       *    2 or 3 GLfloats per position (3 when doing software transforms)
 
388
       *    4 RGBA GLubytes,
 
389
       *    2 GLfloats per tex coord * n_layers
 
390
       * (though n_layers may be padded; see definition of
 
391
       *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
 
392
       */
 
393
      GE (glTexCoordPointer (2, GL_FLOAT, state->stride,
 
394
                             (void *)(state->vbo_offset +
 
395
                                      (POS_STRIDE + COLOR_STRIDE) * 4 +
 
396
                                      TEX_STRIDE * 4 * i)));
 
397
    }
 
398
  prev_n_texcoord_arrays_enabled =
 
399
    ctx->n_texcoord_arrays_enabled;
 
400
  ctx->n_texcoord_arrays_enabled = batch_start->n_layers;
 
401
  for (; i < prev_n_texcoord_arrays_enabled; i++)
 
402
    {
 
403
      GE (glClientActiveTexture (GL_TEXTURE0 + i));
 
404
      GE (glDisableClientState (GL_TEXTURE_COORD_ARRAY));
 
405
    }
 
406
 
 
407
  batch_and_call (batch_start,
 
408
                  batch_len,
 
409
                  compare_entry_materials,
 
410
                  _cogl_journal_flush_material_and_entries,
 
411
                  data);
 
412
}
 
413
 
 
414
static gboolean
 
415
compare_entry_n_layers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
 
416
{
 
417
  if (entry0->n_layers == entry1->n_layers)
 
418
    return TRUE;
 
419
  else
 
420
    return FALSE;
 
421
}
 
422
 
 
423
/* At this point we know the stride has changed from the previous batch
 
424
 * of journal entries */
 
425
static void
 
426
_cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
 
427
                                             int               batch_len,
 
428
                                             void             *data)
 
429
{
 
430
  CoglJournalFlushState   *state = data;
 
431
  gsize                   stride;
 
432
#ifndef HAVE_COGL_GL
 
433
  int                      needed_indices = batch_len * 6;
 
434
  CoglHandle               indices_handle;
 
435
  CoglVertexBufferIndices *indices;
 
436
#endif
 
437
 
 
438
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
439
 
 
440
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
 
441
    g_print ("BATCHING:  vbo offset batch len = %d\n", batch_len);
 
442
 
 
443
  /* XXX NB:
 
444
   * Our journal's vertex data is arranged as follows:
 
445
   * 4 vertices per quad:
 
446
   *    2 or 3 GLfloats per position (3 when doing software transforms)
 
447
   *    4 RGBA GLubytes,
 
448
   *    2 GLfloats per tex coord * n_layers
 
449
   * (though n_layers may be padded; see definition of
 
450
   *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
 
451
   */
 
452
  stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
 
453
  stride *= sizeof (GLfloat);
 
454
  state->stride = stride;
 
455
 
 
456
  GE (glVertexPointer (N_POS_COMPONENTS, GL_FLOAT, stride,
 
457
                       (void *)state->vbo_offset));
 
458
  GE (glColorPointer (4, GL_UNSIGNED_BYTE, stride,
 
459
                      (void *)(state->vbo_offset + (POS_STRIDE * 4))));
 
460
 
 
461
#ifndef HAVE_COGL_GL
 
462
  indices_handle = cogl_vertex_buffer_indices_get_for_quads (needed_indices);
 
463
  indices = _cogl_vertex_buffer_indices_pointer_from_handle (indices_handle);
 
464
  state->indices = indices;
 
465
 
 
466
  if (indices->type == GL_UNSIGNED_BYTE)
 
467
    state->indices_type_size = 1;
 
468
  else if (indices->type == GL_UNSIGNED_SHORT)
 
469
    state->indices_type_size = 2;
 
470
  else
 
471
    g_critical ("unknown indices type %d", indices->type);
 
472
 
 
473
  GE (glBindBuffer (GL_ELEMENT_ARRAY_BUFFER,
 
474
                    GPOINTER_TO_UINT (indices->vbo_name)));
 
475
#endif
 
476
 
 
477
  /* We only call gl{Vertex,Color,Texture}Pointer when the stride within
 
478
   * the VBO changes. (due to a change in the number of material layers)
 
479
   * While the stride remains constant we walk forward through the above
 
480
   * VBO using a vertex offset passed to glDraw{Arrays,Elements} */
 
481
  state->vertex_offset = 0;
 
482
 
 
483
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
 
484
    {
 
485
      guint8 *verts;
 
486
 
 
487
      if (cogl_get_features () & COGL_FEATURE_VBOS)
 
488
        verts = ((guint8 *)ctx->logged_vertices->data) +
 
489
          (size_t)state->vbo_offset;
 
490
      else
 
491
        verts = (guint8 *)state->vbo_offset;
 
492
      _cogl_journal_dump_quad_batch (verts,
 
493
                                     batch_start->n_layers,
 
494
                                     batch_len);
 
495
    }
 
496
 
 
497
  batch_and_call (batch_start,
 
498
                  batch_len,
 
499
                  compare_entry_n_layers,
 
500
                  _cogl_journal_flush_texcoord_vbo_offsets_and_entries,
 
501
                  data);
 
502
 
 
503
  /* progress forward through the VBO containing all our vertices */
 
504
  state->vbo_offset += (stride * 4 * batch_len);
 
505
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
 
506
    g_print ("new vbo offset = %lu\n", (unsigned long)state->vbo_offset);
 
507
}
 
508
 
 
509
static gboolean
 
510
compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
 
511
{
 
512
  /* Currently the only thing that affects the stride for our vertex arrays
 
513
   * is the number of material layers. We need to update our VBO offsets
 
514
   * whenever the stride changes. */
 
515
  /* TODO: We should be padding the n_layers == 1 case as if it were
 
516
   * n_layers == 2 so we can reduce the need to split batches. */
 
517
  if (entry0->n_layers == entry1->n_layers ||
 
518
      (entry0->n_layers <= MIN_LAYER_PADING &&
 
519
       entry1->n_layers <= MIN_LAYER_PADING))
 
520
    return TRUE;
 
521
  else
 
522
    return FALSE;
 
523
}
 
524
 
 
525
static GLuint
 
526
upload_vertices_to_vbo (GArray *vertices, CoglJournalFlushState *state)
 
527
{
 
528
  gsize needed_vbo_len;
 
529
  GLuint journal_vbo;
 
530
 
 
531
  _COGL_GET_CONTEXT (ctx, 0);
 
532
 
 
533
  needed_vbo_len = vertices->len * sizeof (GLfloat);
 
534
 
 
535
  g_assert (needed_vbo_len);
 
536
  GE (glGenBuffers (1, &journal_vbo));
 
537
  GE (glBindBuffer (GL_ARRAY_BUFFER, journal_vbo));
 
538
  GE (glBufferData (GL_ARRAY_BUFFER,
 
539
                    needed_vbo_len,
 
540
                    vertices->data,
 
541
                    GL_STATIC_DRAW));
 
542
 
 
543
  /* As we flush the journal entries in batches we walk forward through the
 
544
   * above VBO starting at offset 0... */
 
545
  state->vbo_offset = 0;
 
546
 
 
547
  return journal_vbo;
 
548
}
 
549
 
 
550
/* XXX NB: When _cogl_journal_flush() returns all state relating
 
551
 * to materials, all glEnable flags and current matrix state
 
552
 * is undefined.
 
553
 */
 
554
void
 
555
_cogl_journal_flush (void)
 
556
{
 
557
  CoglJournalFlushState state;
 
558
  int                   i;
 
559
  GLuint                journal_vbo;
 
560
  gboolean              vbo_fallback =
 
561
    (cogl_get_features () & COGL_FEATURE_VBOS) ? FALSE : TRUE;
 
562
  CoglHandle            framebuffer;
 
563
  CoglMatrixStack      *modelview_stack;
 
564
  COGL_STATIC_TIMER (flush_timer,
 
565
                     "Mainloop", /* parent */
 
566
                     "Journal Flush",
 
567
                     "The time spent flushing the Cogl journal",
 
568
                     0 /* no application private data */);
 
569
 
 
570
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
571
 
 
572
  if (ctx->journal->len == 0)
 
573
    return;
 
574
 
 
575
  COGL_TIMER_START (_cogl_uprof_context, flush_timer);
 
576
 
 
577
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_BATCHING))
 
578
    g_print ("BATCHING: journal len = %d\n", ctx->journal->len);
 
579
 
 
580
  /* Load all the vertex data we have accumulated so far into a single VBO
 
581
   * to minimize memory management costs within the GL driver. */
 
582
  if (!vbo_fallback)
 
583
    journal_vbo = upload_vertices_to_vbo (ctx->logged_vertices, &state);
 
584
  else
 
585
    state.vbo_offset = (char *)ctx->logged_vertices->data;
 
586
 
 
587
  framebuffer = _cogl_get_framebuffer ();
 
588
  modelview_stack = _cogl_framebuffer_get_modelview_stack (framebuffer);
 
589
  state.modelview_stack = modelview_stack;
 
590
 
 
591
  _cogl_matrix_stack_push (modelview_stack);
 
592
 
 
593
  /* If we have transformed all our quads at log time then we ensure no
 
594
   * further model transform is applied by loading the identity matrix
 
595
   * here... */
 
596
  if (G_LIKELY (!(cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
 
597
    {
 
598
      _cogl_matrix_stack_load_identity (modelview_stack);
 
599
      _cogl_matrix_stack_flush_to_gl (modelview_stack, COGL_MATRIX_MODELVIEW);
 
600
    }
 
601
 
 
602
  /* batch_and_call() batches a list of journal entries according to some
 
603
   * given criteria and calls a callback once for each determined batch.
 
604
   *
 
605
   * The process of flushing the journal is staggered to reduce the amount
 
606
   * of driver/GPU state changes necessary:
 
607
   * 1) We split the entries according to the stride of the vertices:
 
608
   *      Each time the stride of our vertex data changes we need to call
 
609
   *      gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
 
610
   *      Currently the only thing that affects the stride of our vertex data
 
611
   *      is the number of material layers.
 
612
   * 2) We split the entries explicitly by the number of material layers:
 
613
   *      We pad our vertex data when the number of layers is < 2 so that we
 
614
   *      can minimize changes in stride. Each time the number of layers
 
615
   *      changes we need to call glTexCoordPointer to inform GL of new VBO
 
616
   *      offsets.
 
617
   * 3) We then split according to compatible Cogl materials:
 
618
   *      This is where we flush material state
 
619
   * 4) Finally we split according to modelview matrix changes:
 
620
   *      This is when we finally tell GL to draw something.
 
621
   *      Note: Splitting by modelview changes is skipped when are doing the
 
622
   *      vertex transformation in software at log time.
 
623
   */
 
624
  batch_and_call ((CoglJournalEntry *)ctx->journal->data, /* first entry */
 
625
                  ctx->journal->len, /* max number of entries to consider */
 
626
                  compare_entry_strides,
 
627
                  _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
 
628
                  &state); /* data */
 
629
 
 
630
  _cogl_matrix_stack_pop (modelview_stack);
 
631
 
 
632
  for (i = 0; i < ctx->journal->len; i++)
 
633
    {
 
634
      CoglJournalEntry *entry =
 
635
        &g_array_index (ctx->journal, CoglJournalEntry, i);
 
636
      _cogl_material_journal_unref (entry->material);
 
637
    }
 
638
 
 
639
  if (!vbo_fallback)
 
640
    GE (glDeleteBuffers (1, &journal_vbo));
 
641
 
 
642
  g_array_set_size (ctx->journal, 0);
 
643
  g_array_set_size (ctx->logged_vertices, 0);
 
644
 
 
645
  COGL_TIMER_STOP (_cogl_uprof_context, flush_timer);
 
646
}
 
647
 
 
648
static void
 
649
_cogl_journal_init (void)
 
650
{
 
651
  /* Here we flush anything that we know must remain constant until the
 
652
   * next the the journal is flushed. Note: This lets up flush things
 
653
   * that themselves depend on the journal, such as clip state. */
 
654
 
 
655
  /* NB: the journal deals with flushing the modelview stack manually */
 
656
  _cogl_framebuffer_flush_state (_cogl_get_framebuffer (),
 
657
                                 COGL_FRAMEBUFFER_FLUSH_SKIP_MODELVIEW);
 
658
}
 
659
 
 
660
void
 
661
_cogl_journal_log_quad (const float  *position,
 
662
                        CoglHandle    material,
 
663
                        int           n_layers,
 
664
                        guint32       fallback_layers,
 
665
                        GLuint        layer0_override_texture,
 
666
                        const float  *tex_coords,
 
667
                        unsigned int  tex_coords_len)
 
668
{
 
669
  gsize            stride;
 
670
  gsize            byte_stride;
 
671
  int               next_vert;
 
672
  GLfloat          *v;
 
673
  GLubyte          *c;
 
674
  GLubyte          *src_c;
 
675
  int               i;
 
676
  int               next_entry;
 
677
  guint32           disable_layers;
 
678
  CoglJournalEntry *entry;
 
679
  COGL_STATIC_TIMER (log_timer,
 
680
                     "Mainloop", /* parent */
 
681
                     "Journal Log",
 
682
                     "The time spent logging in the Cogl journal",
 
683
                     0 /* no application private data */);
 
684
 
 
685
  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
 
686
 
 
687
  COGL_TIMER_START (_cogl_uprof_context, log_timer);
 
688
 
 
689
  if (ctx->logged_vertices->len == 0)
 
690
    _cogl_journal_init ();
 
691
 
 
692
  /* The vertex data is logged into a separate array in a layout that can be
 
693
   * directly passed to OpenGL
 
694
   */
 
695
 
 
696
  /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
 
697
   * about how we pack our vertex data */
 
698
  stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
 
699
  /* NB: stride is in 32bit words */
 
700
  byte_stride = stride * 4;
 
701
 
 
702
  next_vert = ctx->logged_vertices->len;
 
703
  g_array_set_size (ctx->logged_vertices, next_vert + 4 * stride);
 
704
  v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
 
705
  c = (GLubyte *)(v + POS_STRIDE);
 
706
 
 
707
  /* XXX: All the jumping around to fill in this strided buffer doesn't
 
708
   * seem ideal. */
 
709
 
 
710
  /* XXX: we could defer expanding the vertex data for GL until we come
 
711
   * to flushing the journal. */
 
712
 
 
713
  /* FIXME: This is a hacky optimization, since it will break if we
 
714
   * change the definition of CoglColor: */
 
715
  _cogl_material_get_colorubv (material, c);
 
716
  src_c = c;
 
717
  for (i = 0; i < 3; i++)
 
718
    {
 
719
      c += byte_stride;
 
720
      memcpy (c, src_c, 4);
 
721
    }
 
722
 
 
723
#define X0 0
 
724
#define Y0 1
 
725
#define X1 2
 
726
#define Y1 3
 
727
 
 
728
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
729
    {
 
730
      v[0] = position[X0]; v[1] = position[Y0];
 
731
      v += stride;
 
732
      v[0] = position[X0]; v[1] = position[Y1];
 
733
      v += stride;
 
734
      v[0] = position[X1]; v[1] = position[Y1];
 
735
      v += stride;
 
736
      v[0] = position[X1]; v[1] = position[Y0];
 
737
    }
 
738
  else
 
739
    {
 
740
      CoglMatrix  mv;
 
741
      float       x, y, z, w;
 
742
 
 
743
      cogl_get_modelview_matrix (&mv);
 
744
 
 
745
      x = position[X0], y = position[Y0], z = 0; w = 1;
 
746
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
 
747
      v[0] = x; v[1] = y; v[2] = z;
 
748
      v += stride;
 
749
      x = position[X0], y = position[Y1], z = 0; w = 1;
 
750
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
 
751
      v[0] = x; v[1] = y; v[2] = z;
 
752
      v += stride;
 
753
      x = position[X1], y = position[Y1], z = 0; w = 1;
 
754
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
 
755
      v[0] = x; v[1] = y; v[2] = z;
 
756
      v += stride;
 
757
      x = position[X1], y = position[Y0], z = 0; w = 1;
 
758
      cogl_matrix_transform_point (&mv, &x, &y, &z, &w);
 
759
      v[0] = x; v[1] = y; v[2] = z;
 
760
    }
 
761
 
 
762
#undef X0
 
763
#undef Y0
 
764
#undef X1
 
765
#undef Y1
 
766
 
 
767
  for (i = 0; i < n_layers; i++)
 
768
    {
 
769
      /* XXX: See definition of GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details
 
770
       * about how we pack our vertex data */
 
771
      GLfloat *t = &g_array_index (ctx->logged_vertices, GLfloat,
 
772
                                   next_vert +  POS_STRIDE +
 
773
                                   COLOR_STRIDE + TEX_STRIDE * i);
 
774
 
 
775
      t[0] = tex_coords[i * 4 + 0]; t[1] = tex_coords[i * 4 + 1];
 
776
      t += stride;
 
777
      t[0] = tex_coords[i * 4 + 0]; t[1] = tex_coords[i * 4 + 3];
 
778
      t += stride;
 
779
      t[0] = tex_coords[i * 4 + 2]; t[1] = tex_coords[i * 4 + 3];
 
780
      t += stride;
 
781
      t[0] = tex_coords[i * 4 + 2]; t[1] = tex_coords[i * 4 + 1];
 
782
    }
 
783
 
 
784
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_JOURNAL))
 
785
    {
 
786
      g_print ("Logged new quad:\n");
 
787
      v = &g_array_index (ctx->logged_vertices, GLfloat, next_vert);
 
788
      _cogl_journal_dump_quad_vertices ((guint8 *)v, n_layers);
 
789
    }
 
790
 
 
791
  next_entry = ctx->journal->len;
 
792
  g_array_set_size (ctx->journal, next_entry + 1);
 
793
  entry = &g_array_index (ctx->journal, CoglJournalEntry, next_entry);
 
794
 
 
795
  disable_layers = (1 << n_layers) - 1;
 
796
  disable_layers = ~disable_layers;
 
797
 
 
798
  entry->material = _cogl_material_journal_ref (material);
 
799
  entry->n_layers = n_layers;
 
800
  entry->flush_options.flags =
 
801
    COGL_MATERIAL_FLUSH_FALLBACK_MASK |
 
802
    COGL_MATERIAL_FLUSH_DISABLE_MASK |
 
803
    COGL_MATERIAL_FLUSH_SKIP_GL_COLOR;
 
804
  entry->flush_options.fallback_layers = fallback_layers;
 
805
  entry->flush_options.disable_layers = disable_layers;
 
806
  if (layer0_override_texture)
 
807
    {
 
808
      entry->flush_options.flags |= COGL_MATERIAL_FLUSH_LAYER0_OVERRIDE;
 
809
      entry->flush_options.layer0_override_texture = layer0_override_texture;
 
810
    }
 
811
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))
 
812
    cogl_get_modelview_matrix (&entry->model_view);
 
813
 
 
814
  if (G_UNLIKELY (cogl_debug_flags & COGL_DEBUG_DISABLE_BATCHING))
 
815
    _cogl_journal_flush ();
 
816
 
 
817
  COGL_TIMER_STOP (_cogl_uprof_context, log_timer);
 
818
}
 
819