1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2007,2008,2009 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  *
29  */
30 
31 #ifdef HAVE_CONFIG_H
32 #include "cogl-config.h"
33 #endif
34 
35 #include "cogl-debug.h"
36 #include "cogl-context-private.h"
37 #include "cogl-journal-private.h"
38 #include "cogl-texture-private.h"
39 #include "cogl-pipeline-private.h"
40 #include "cogl-pipeline-opengl-private.h"
41 #include "cogl-vertex-buffer-private.h"
42 #include "cogl-framebuffer-private.h"
43 #include "cogl-profile.h"
44 #include "cogl-attribute-private.h"
45 #include "cogl-point-in-poly-private.h"
46 #include "cogl-private.h"
47 #include "cogl1-context.h"
48 
49 #include <string.h>
50 #include <gmodule.h>
51 #include <math.h>
52 
53 /* XXX NB:
54  * The data logged in logged_vertices is formatted as follows:
55  *
56  * Per entry:
57  *   4 RGBA GLubytes for the color
58  *   2 floats for the top left position
59  *   2 * n_layers floats for the top left texture coordinates
60  *   2 floats for the bottom right position
61  *   2 * n_layers floats for the bottom right texture coordinates
62  */
63 #define GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS(N_LAYERS) \
64   (N_LAYERS * 2 + 2)
65 
66 /* XXX NB:
67  * Once in the vertex array, the journal's vertex data is arranged as follows:
68  * 4 vertices per quad:
69  *    2 or 3 GLfloats per position (3 when doing software transforms)
70  *    4 RGBA GLubytes,
71  *    2 GLfloats per tex coord * n_layers
72  *
73  * Where n_layers corresponds to the number of pipeline layers enabled
74  *
75  * To avoid frequent changes in the stride of our vertex data we always pad
76  * n_layers to be >= 2
77  *
78  * There will be four vertices per quad in the vertex array
79  *
80  * When we are transforming quads in software we need to also track the z
81  * coordinate of transformed vertices.
82  *
83  * So for a given number of layers this gets the stride in 32bit words:
84  */
85 #define SW_TRANSFORM      (!(COGL_DEBUG_ENABLED \
86                              (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
87 #define POS_STRIDE        (SW_TRANSFORM ? 3 : 2) /* number of 32bit words */
88 #define N_POS_COMPONENTS  POS_STRIDE
89 #define COLOR_STRIDE      1 /* number of 32bit words */
90 #define TEX_STRIDE        2 /* number of 32bit words */
91 #define MIN_LAYER_PADING  2
92 #define GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS(N_LAYERS) \
93   (POS_STRIDE + COLOR_STRIDE + \
94    TEX_STRIDE * (N_LAYERS < MIN_LAYER_PADING ? MIN_LAYER_PADING : N_LAYERS))
95 
96 /* If a batch is longer than this threshold then we'll assume it's not
97    worth doing software clipping and it's cheaper to program the GPU
98    to do the clip */
99 #define COGL_JOURNAL_HARDWARE_CLIP_THRESHOLD 8
100 
101 typedef struct _CoglJournalFlushState
102 {
103   CoglContext *ctx;
104 
105   CoglJournal *journal;
106 
107   CoglAttributeBuffer *attribute_buffer;
108   GArray *attributes;
109   int current_attribute;
110 
111   size_t stride;
112   size_t array_offset;
113   GLuint current_vertex;
114 
115   CoglIndices *indices;
116   size_t indices_type_size;
117 
118   CoglPipeline *pipeline;
119 } CoglJournalFlushState;
120 
121 typedef void (*CoglJournalBatchCallback) (CoglJournalEntry *start,
122                                           int n_entries,
123                                           void *data);
124 typedef CoglBool (*CoglJournalBatchTest) (CoglJournalEntry *entry0,
125                                           CoglJournalEntry *entry1);
126 
127 static void _cogl_journal_free (CoglJournal *journal);
128 
129 COGL_OBJECT_INTERNAL_DEFINE (Journal, journal);
130 
131 static void
_cogl_journal_free(CoglJournal * journal)132 _cogl_journal_free (CoglJournal *journal)
133 {
134   int i;
135 
136   if (journal->entries)
137     g_array_free (journal->entries, TRUE);
138   if (journal->vertices)
139     g_array_free (journal->vertices, TRUE);
140 
141   for (i = 0; i < COGL_JOURNAL_VBO_POOL_SIZE; i++)
142     if (journal->vbo_pool[i])
143       cogl_object_unref (journal->vbo_pool[i]);
144 
145   g_slice_free (CoglJournal, journal);
146 }
147 
148 CoglJournal *
_cogl_journal_new(CoglFramebuffer * framebuffer)149 _cogl_journal_new (CoglFramebuffer *framebuffer)
150 {
151   CoglJournal *journal = g_slice_new0 (CoglJournal);
152 
153   /* The journal keeps a pointer back to the framebuffer because there
154      is effectively a 1:1 mapping between journals and framebuffers.
155      However, to avoid a circular reference the journal doesn't take a
156      reference unless it is non-empty. The framebuffer has a special
157      unref implementation to ensure that the journal is flushed when
158      the journal is the only thing keeping it alive */
159   journal->framebuffer = framebuffer;
160 
161   journal->entries = g_array_new (FALSE, FALSE, sizeof (CoglJournalEntry));
162   journal->vertices = g_array_new (FALSE, FALSE, sizeof (float));
163 
164   _cogl_list_init (&journal->pending_fences);
165 
166   return _cogl_journal_object_new (journal);
167 }
168 
169 static void
_cogl_journal_dump_logged_quad(uint8_t * data,int n_layers)170 _cogl_journal_dump_logged_quad (uint8_t *data, int n_layers)
171 {
172   size_t stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (n_layers);
173   int i;
174 
175   g_print ("n_layers = %d; rgba=0x%02X%02X%02X%02X\n",
176            n_layers, data[0], data[1], data[2], data[3]);
177 
178   data += 4;
179 
180   for (i = 0; i < 2; i++)
181     {
182       float *v = (float *)data + (i * stride);
183       int j;
184 
185       g_print ("v%d: x = %f, y = %f", i, v[0], v[1]);
186 
187       for (j = 0; j < n_layers; j++)
188         {
189           float *t = v + 2 + TEX_STRIDE * j;
190           g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
191         }
192       g_print ("\n");
193     }
194 }
195 
196 static void
_cogl_journal_dump_quad_vertices(uint8_t * data,int n_layers)197 _cogl_journal_dump_quad_vertices (uint8_t *data, int n_layers)
198 {
199   size_t stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers);
200   int i;
201 
202   g_print ("n_layers = %d; stride = %d; pos stride = %d; color stride = %d; "
203            "tex stride = %d; stride in bytes = %d\n",
204            n_layers, (int)stride, POS_STRIDE, COLOR_STRIDE,
205            TEX_STRIDE, (int)stride * 4);
206 
207   for (i = 0; i < 4; i++)
208     {
209       float *v = (float *)data + (i * stride);
210       uint8_t *c = data + (POS_STRIDE * 4) + (i * stride * 4);
211       int j;
212 
213       if (G_UNLIKELY (COGL_DEBUG_ENABLED
214                       (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
215         g_print ("v%d: x = %f, y = %f, rgba=0x%02X%02X%02X%02X",
216                  i, v[0], v[1], c[0], c[1], c[2], c[3]);
217       else
218         g_print ("v%d: x = %f, y = %f, z = %f, rgba=0x%02X%02X%02X%02X",
219                  i, v[0], v[1], v[2], c[0], c[1], c[2], c[3]);
220       for (j = 0; j < n_layers; j++)
221         {
222           float *t = v + POS_STRIDE + COLOR_STRIDE + TEX_STRIDE * j;
223           g_print (", tx%d = %f, ty%d = %f", j, t[0], j, t[1]);
224         }
225       g_print ("\n");
226     }
227 }
228 
229 static void
_cogl_journal_dump_quad_batch(uint8_t * data,int n_layers,int n_quads)230 _cogl_journal_dump_quad_batch (uint8_t *data, int n_layers, int n_quads)
231 {
232   size_t byte_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
233   int i;
234 
235   g_print ("_cogl_journal_dump_quad_batch: n_layers = %d, n_quads = %d\n",
236            n_layers, n_quads);
237   for (i = 0; i < n_quads; i++)
238     _cogl_journal_dump_quad_vertices (data + byte_stride * 2 * i, n_layers);
239 }
240 
241 static void
batch_and_call(CoglJournalEntry * entries,int n_entries,CoglJournalBatchTest can_batch_callback,CoglJournalBatchCallback batch_callback,void * data)242 batch_and_call (CoglJournalEntry *entries,
243                 int n_entries,
244                 CoglJournalBatchTest can_batch_callback,
245                 CoglJournalBatchCallback batch_callback,
246                 void *data)
247 {
248   int i;
249   int batch_len = 1;
250   CoglJournalEntry *batch_start = entries;
251 
252   if (n_entries < 1)
253     return;
254 
255   for (i = 1; i < n_entries; i++)
256     {
257       CoglJournalEntry *entry0 = &entries[i - 1];
258       CoglJournalEntry *entry1 = entry0 + 1;
259 
260       if (can_batch_callback (entry0, entry1))
261         {
262           batch_len++;
263           continue;
264         }
265 
266       batch_callback (batch_start, batch_len, data);
267 
268       batch_start = entry1;
269       batch_len = 1;
270     }
271 
272   /* The last batch... */
273   batch_callback (batch_start, batch_len, data);
274 }
275 
276 static void
_cogl_journal_flush_modelview_and_entries(CoglJournalEntry * batch_start,int batch_len,void * data)277 _cogl_journal_flush_modelview_and_entries (CoglJournalEntry *batch_start,
278                                            int               batch_len,
279                                            void             *data)
280 {
281   CoglJournalFlushState *state = data;
282   CoglContext *ctx = state->ctx;
283   CoglFramebuffer *framebuffer = state->journal->framebuffer;
284   CoglAttribute **attributes;
285   CoglDrawFlags draw_flags = (COGL_DRAW_SKIP_JOURNAL_FLUSH |
286                               COGL_DRAW_SKIP_PIPELINE_VALIDATION |
287                               COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
288                               COGL_DRAW_SKIP_LEGACY_STATE);
289 
290   COGL_STATIC_TIMER (time_flush_modelview_and_entries,
291                      "flush: pipeline+entries", /* parent */
292                      "flush: modelview+entries",
293                      "The time spent flushing modelview + entries",
294                      0 /* no application private data */);
295 
296   COGL_TIMER_START (_cogl_uprof_context, time_flush_modelview_and_entries);
297 
298   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
299     g_print ("BATCHING:     modelview batch len = %d\n", batch_len);
300 
301   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
302     _cogl_context_set_current_modelview_entry (ctx,
303                                                batch_start->modelview_entry);
304 
305   attributes = (CoglAttribute **)state->attributes->data;
306 
307   if (!_cogl_pipeline_get_real_blend_enabled (state->pipeline))
308     draw_flags |= COGL_DRAW_COLOR_ATTRIBUTE_IS_OPAQUE;
309 
310 #ifdef HAVE_COGL_GL
311   if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS))
312     {
313       /* XXX: it's rather evil that we sneak in the GL_QUADS enum here... */
314       _cogl_framebuffer_draw_attributes (framebuffer,
315                                          state->pipeline,
316                                          GL_QUADS,
317                                          state->current_vertex, batch_len * 4,
318                                          attributes,
319                                          state->attributes->len,
320                                          draw_flags);
321     }
322   else
323 #endif /* HAVE_COGL_GL */
324     {
325       if (batch_len > 1)
326         {
327           CoglVerticesMode mode = COGL_VERTICES_MODE_TRIANGLES;
328           int first_vertex = state->current_vertex * 6 / 4;
329           _cogl_framebuffer_draw_indexed_attributes (framebuffer,
330                                                      state->pipeline,
331                                                      mode,
332                                                      first_vertex,
333                                                      batch_len * 6,
334                                                      state->indices,
335                                                      attributes,
336                                                      state->attributes->len,
337                                                      draw_flags);
338         }
339       else
340         {
341           _cogl_framebuffer_draw_attributes (framebuffer,
342                                              state->pipeline,
343                                              COGL_VERTICES_MODE_TRIANGLE_FAN,
344                                              state->current_vertex, 4,
345                                              attributes,
346                                              state->attributes->len,
347                                              draw_flags);
348         }
349     }
350 
351   /* DEBUGGING CODE XXX: This path will cause all rectangles to be
352    * drawn with a coloured outline. Each batch will be rendered with
353    * the same color. This may e.g. help with debugging texture slicing
354    * issues, visually seeing what is batched and debugging blending
355    * issues, plus it looks quite cool.
356    */
357   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_RECTANGLES)))
358     {
359       static CoglPipeline *outline = NULL;
360       uint8_t color_intensity;
361       int i;
362       CoglAttribute *loop_attributes[1];
363 
364       if (outline == NULL)
365         outline = cogl_pipeline_new (ctx);
366 
367       /* The least significant three bits represent the three
368          components so that the order of colours goes red, green,
369          yellow, blue, magenta, cyan. Black and white are skipped. The
370          next two bits give four scales of intensity for those colours
371          in the order 0xff, 0xcc, 0x99, and 0x66. This gives a total
372          of 24 colours. If there are more than 24 batches on the stage
373          then it will wrap around */
374       color_intensity = 0xff - 0x33 * (ctx->journal_rectangles_color >> 3);
375       cogl_pipeline_set_color4ub (outline,
376                                   (ctx->journal_rectangles_color & 1) ?
377                                   color_intensity : 0,
378                                   (ctx->journal_rectangles_color & 2) ?
379                                   color_intensity : 0,
380                                   (ctx->journal_rectangles_color & 4) ?
381                                   color_intensity : 0,
382                                   0xff);
383 
384       loop_attributes[0] = attributes[0]; /* we just want the position */
385       for (i = 0; i < batch_len; i++)
386         _cogl_framebuffer_draw_attributes (framebuffer,
387                                            outline,
388                                            COGL_VERTICES_MODE_LINE_LOOP,
389                                            4 * i + state->current_vertex, 4,
390                                            loop_attributes,
391                                            1,
392                                            draw_flags);
393 
394       /* Go to the next color */
395       do
396         ctx->journal_rectangles_color = ((ctx->journal_rectangles_color + 1) &
397                                          ((1 << 5) - 1));
398       /* We don't want to use black or white */
399       while ((ctx->journal_rectangles_color & 0x07) == 0
400              || (ctx->journal_rectangles_color & 0x07) == 0x07);
401     }
402 
403   state->current_vertex += (4 * batch_len);
404 
405   COGL_TIMER_STOP (_cogl_uprof_context, time_flush_modelview_and_entries);
406 }
407 
408 static CoglBool
compare_entry_modelviews(CoglJournalEntry * entry0,CoglJournalEntry * entry1)409 compare_entry_modelviews (CoglJournalEntry *entry0,
410                           CoglJournalEntry *entry1)
411 {
412   /* Batch together quads with the same model view matrix */
413   return entry0->modelview_entry == entry1->modelview_entry;
414 }
415 
416 /* At this point we have a run of quads that we know have compatible
417  * pipelines, but they may not all have the same modelview matrix */
418 static void
_cogl_journal_flush_pipeline_and_entries(CoglJournalEntry * batch_start,int batch_len,void * data)419 _cogl_journal_flush_pipeline_and_entries (CoglJournalEntry *batch_start,
420                                           int               batch_len,
421                                           void             *data)
422 {
423   CoglJournalFlushState *state = data;
424   COGL_STATIC_TIMER (time_flush_pipeline_entries,
425                      "flush: texcoords+pipeline+entries", /* parent */
426                      "flush: pipeline+entries",
427                      "The time spent flushing pipeline + entries",
428                      0 /* no application private data */);
429 
430   COGL_TIMER_START (_cogl_uprof_context, time_flush_pipeline_entries);
431 
432   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
433     g_print ("BATCHING:    pipeline batch len = %d\n", batch_len);
434 
435   state->pipeline = batch_start->pipeline;
436 
437   /* If we haven't transformed the quads in software then we need to also break
438    * up batches according to changes in the modelview matrix... */
439   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
440     {
441       batch_and_call (batch_start,
442                       batch_len,
443                       compare_entry_modelviews,
444                       _cogl_journal_flush_modelview_and_entries,
445                       data);
446     }
447   else
448     _cogl_journal_flush_modelview_and_entries (batch_start, batch_len, data);
449 
450   COGL_TIMER_STOP (_cogl_uprof_context, time_flush_pipeline_entries);
451 }
452 
453 static CoglBool
compare_entry_pipelines(CoglJournalEntry * entry0,CoglJournalEntry * entry1)454 compare_entry_pipelines (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
455 {
456   /* batch rectangles using compatible pipelines */
457 
458   if (_cogl_pipeline_equal (entry0->pipeline,
459                             entry1->pipeline,
460                             (COGL_PIPELINE_STATE_ALL &
461                              ~COGL_PIPELINE_STATE_COLOR),
462                             COGL_PIPELINE_LAYER_STATE_ALL,
463                             0))
464     return TRUE;
465   else
466     return FALSE;
467 }
468 
469 typedef struct _CreateAttributeState
470 {
471   int current;
472   CoglJournalFlushState *flush_state;
473 } CreateAttributeState;
474 
475 static CoglBool
create_attribute_cb(CoglPipeline * pipeline,int layer_number,void * user_data)476 create_attribute_cb (CoglPipeline *pipeline,
477                      int layer_number,
478                      void *user_data)
479 {
480   CreateAttributeState *state = user_data;
481   CoglJournalFlushState *flush_state = state->flush_state;
482   CoglAttribute **attribute_entry =
483     &g_array_index (flush_state->attributes,
484                     CoglAttribute *,
485                     state->current + 2);
486   const char *names[] = {
487       "cogl_tex_coord0_in",
488       "cogl_tex_coord1_in",
489       "cogl_tex_coord2_in",
490       "cogl_tex_coord3_in",
491       "cogl_tex_coord4_in",
492       "cogl_tex_coord5_in",
493       "cogl_tex_coord6_in",
494       "cogl_tex_coord7_in"
495   };
496   char *name;
497 
498   /* XXX NB:
499    * Our journal's vertex data is arranged as follows:
500    * 4 vertices per quad:
501    *    2 or 3 floats per position (3 when doing software transforms)
502    *    4 RGBA bytes,
503    *    2 floats per tex coord * n_layers
504    * (though n_layers may be padded; see definition of
505    *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
506    */
507   name = layer_number < 8 ? (char *)names[layer_number] :
508     g_strdup_printf ("cogl_tex_coord%d_in", layer_number);
509 
510   /* XXX: it may be worth having some form of static initializer for
511    * attributes... */
512   *attribute_entry =
513     cogl_attribute_new (flush_state->attribute_buffer,
514                         name,
515                         flush_state->stride,
516                         flush_state->array_offset +
517                         (POS_STRIDE + COLOR_STRIDE) * 4 +
518                         TEX_STRIDE * 4 * state->current,
519                         2,
520                         COGL_ATTRIBUTE_TYPE_FLOAT);
521 
522   if (layer_number >= 8)
523     free (name);
524 
525   state->current++;
526 
527   return TRUE;
528 }
529 
530 /* Since the stride may not reflect the number of texture layers in use
531  * (due to padding) we deal with texture coordinate offsets separately
532  * from vertex and color offsets... */
533 static void
_cogl_journal_flush_texcoord_vbo_offsets_and_entries(CoglJournalEntry * batch_start,int batch_len,void * data)534 _cogl_journal_flush_texcoord_vbo_offsets_and_entries (
535                                           CoglJournalEntry *batch_start,
536                                           int               batch_len,
537                                           void             *data)
538 {
539   CoglJournalFlushState *state = data;
540   CreateAttributeState create_attrib_state;
541   int i;
542   COGL_STATIC_TIMER (time_flush_texcoord_pipeline_entries,
543                      "flush: vbo+texcoords+pipeline+entries", /* parent */
544                      "flush: texcoords+pipeline+entries",
545                      "The time spent flushing texcoord offsets + pipeline "
546                      "+ entries",
547                      0 /* no application private data */);
548 
549   COGL_TIMER_START (_cogl_uprof_context, time_flush_texcoord_pipeline_entries);
550 
551   /* NB: attributes 0 and 1 are position and color */
552 
553   for (i = 2; i < state->attributes->len; i++)
554     cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i));
555 
556   g_array_set_size (state->attributes, batch_start->n_layers + 2);
557 
558   create_attrib_state.current = 0;
559   create_attrib_state.flush_state = state;
560 
561   cogl_pipeline_foreach_layer (batch_start->pipeline,
562                                create_attribute_cb,
563                                &create_attrib_state);
564 
565   batch_and_call (batch_start,
566                   batch_len,
567                   compare_entry_pipelines,
568                   _cogl_journal_flush_pipeline_and_entries,
569                   data);
570   COGL_TIMER_STOP (_cogl_uprof_context, time_flush_texcoord_pipeline_entries);
571 }
572 
573 static CoglBool
compare_entry_layer_numbers(CoglJournalEntry * entry0,CoglJournalEntry * entry1)574 compare_entry_layer_numbers (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
575 {
576   if (_cogl_pipeline_layer_numbers_equal (entry0->pipeline, entry1->pipeline))
577     return TRUE;
578   else
579     return FALSE;
580 }
581 
582 /* At this point we know the stride has changed from the previous batch
583  * of journal entries */
584 static void
_cogl_journal_flush_vbo_offsets_and_entries(CoglJournalEntry * batch_start,int batch_len,void * data)585 _cogl_journal_flush_vbo_offsets_and_entries (CoglJournalEntry *batch_start,
586                                              int               batch_len,
587                                              void             *data)
588 {
589   CoglJournalFlushState *state = data;
590   CoglContext *ctx = state->journal->framebuffer->context;
591   size_t stride;
592   int i;
593   CoglAttribute **attribute_entry;
594   COGL_STATIC_TIMER (time_flush_vbo_texcoord_pipeline_entries,
595                      "flush: clip+vbo+texcoords+pipeline+entries", /* parent */
596                      "flush: vbo+texcoords+pipeline+entries",
597                      "The time spent flushing vbo + texcoord offsets + "
598                      "pipeline + entries",
599                      0 /* no application private data */);
600 
601   COGL_TIMER_START (_cogl_uprof_context,
602                     time_flush_vbo_texcoord_pipeline_entries);
603 
604   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
605     g_print ("BATCHING:   vbo offset batch len = %d\n", batch_len);
606 
607   /* XXX NB:
608    * Our journal's vertex data is arranged as follows:
609    * 4 vertices per quad:
610    *    2 or 3 GLfloats per position (3 when doing software transforms)
611    *    4 RGBA GLubytes,
612    *    2 GLfloats per tex coord * n_layers
613    * (though n_layers may be padded; see definition of
614    *  GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS for details)
615    */
616   stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (batch_start->n_layers);
617   stride *= sizeof (float);
618   state->stride = stride;
619 
620   for (i = 0; i < state->attributes->len; i++)
621     cogl_object_unref (g_array_index (state->attributes, CoglAttribute *, i));
622 
623   g_array_set_size (state->attributes, 2);
624 
625   attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 0);
626   *attribute_entry = cogl_attribute_new (state->attribute_buffer,
627                                          "cogl_position_in",
628                                          stride,
629                                          state->array_offset,
630                                          N_POS_COMPONENTS,
631                                          COGL_ATTRIBUTE_TYPE_FLOAT);
632 
633   attribute_entry = &g_array_index (state->attributes, CoglAttribute *, 1);
634   *attribute_entry =
635     cogl_attribute_new (state->attribute_buffer,
636                         "cogl_color_in",
637                         stride,
638                         state->array_offset + (POS_STRIDE * 4),
639                         4,
640                         COGL_ATTRIBUTE_TYPE_UNSIGNED_BYTE);
641 
642   if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_QUADS))
643     state->indices = cogl_get_rectangle_indices (ctx, batch_len);
644 
645   /* We only create new Attributes when the stride within the
646    * AttributeBuffer changes. (due to a change in the number of pipeline
647    * layers) While the stride remains constant we walk forward through
648    * the above AttributeBuffer using a vertex offset passed to
649    * cogl_draw_attributes
650    */
651   state->current_vertex = 0;
652 
653   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)) &&
654       cogl_has_feature (ctx, COGL_FEATURE_ID_MAP_BUFFER_FOR_READ))
655     {
656       uint8_t *verts;
657 
658       /* Mapping a buffer for read is probably a really bad thing to
659          do but this will only happen during debugging so it probably
660          doesn't matter */
661       verts = ((uint8_t *)_cogl_buffer_map (COGL_BUFFER (state->attribute_buffer),
662                                             COGL_BUFFER_ACCESS_READ, 0,
663                                             NULL) +
664                state->array_offset);
665 
666       _cogl_journal_dump_quad_batch (verts,
667                                      batch_start->n_layers,
668                                      batch_len);
669 
670       cogl_buffer_unmap (COGL_BUFFER (state->attribute_buffer));
671     }
672 
673   batch_and_call (batch_start,
674                   batch_len,
675                   compare_entry_layer_numbers,
676                   _cogl_journal_flush_texcoord_vbo_offsets_and_entries,
677                   data);
678 
679   /* progress forward through the VBO containing all our vertices */
680   state->array_offset += (stride * 4 * batch_len);
681   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)))
682     g_print ("new vbo offset = %lu\n", (unsigned long)state->array_offset);
683 
684   COGL_TIMER_STOP (_cogl_uprof_context,
685                    time_flush_vbo_texcoord_pipeline_entries);
686 }
687 
688 static CoglBool
compare_entry_strides(CoglJournalEntry * entry0,CoglJournalEntry * entry1)689 compare_entry_strides (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
690 {
691   /* Currently the only thing that affects the stride for our vertex arrays
692    * is the number of pipeline layers. We need to update our VBO offsets
693    * whenever the stride changes. */
694   /* TODO: We should be padding the n_layers == 1 case as if it were
695    * n_layers == 2 so we can reduce the need to split batches. */
696   if (entry0->n_layers == entry1->n_layers ||
697       (entry0->n_layers <= MIN_LAYER_PADING &&
698        entry1->n_layers <= MIN_LAYER_PADING))
699     return TRUE;
700   else
701     return FALSE;
702 }
703 
704 /* At this point we know the batch has a unique clip stack */
705 static void
_cogl_journal_flush_clip_stacks_and_entries(CoglJournalEntry * batch_start,int batch_len,void * data)706 _cogl_journal_flush_clip_stacks_and_entries (CoglJournalEntry *batch_start,
707                                              int               batch_len,
708                                              void             *data)
709 {
710   CoglJournalFlushState *state = data;
711   CoglFramebuffer *framebuffer = state->journal->framebuffer;
712   CoglContext *ctx = framebuffer->context;
713   CoglMatrixStack *projection_stack;
714 
715   COGL_STATIC_TIMER (time_flush_clip_stack_pipeline_entries,
716                      "Journal Flush", /* parent */
717                      "flush: clip+vbo+texcoords+pipeline+entries",
718                      "The time spent flushing clip + vbo + texcoord offsets + "
719                      "pipeline + entries",
720                      0 /* no application private data */);
721 
722   COGL_TIMER_START (_cogl_uprof_context,
723                     time_flush_clip_stack_pipeline_entries);
724 
725   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
726     g_print ("BATCHING:  clip stack batch len = %d\n", batch_len);
727 
728   _cogl_clip_stack_flush (batch_start->clip_stack, framebuffer);
729 
730   /* XXX: Because we are manually flushing clip state here we need to
731    * make sure that the clip state gets updated the next time we flush
732    * framebuffer state by marking the current framebuffer's clip state
733    * as changed. */
734   ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_CLIP;
735 
736   /* If we have transformed all our quads at log time then we ensure
737    * no further model transform is applied by loading the identity
738    * matrix here. We need to do this after flushing the clip stack
739    * because the clip stack flushing code can modify the current
740    * modelview matrix entry */
741   if (G_LIKELY (!(COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM))))
742     _cogl_context_set_current_modelview_entry (ctx, &ctx->identity_entry);
743 
744   /* Setting up the clip state can sometimes also update the current
745    * projection matrix entry so we should update it again. This will have
746    * no affect if the clip code didn't modify the projection */
747   projection_stack =
748     _cogl_framebuffer_get_projection_stack (framebuffer);
749   _cogl_context_set_current_projection_entry (ctx,
750                                               projection_stack->last_entry);
751 
752   batch_and_call (batch_start,
753                   batch_len,
754                   compare_entry_strides,
755                   _cogl_journal_flush_vbo_offsets_and_entries, /* callback */
756                   data);
757 
758   COGL_TIMER_STOP (_cogl_uprof_context,
759                    time_flush_clip_stack_pipeline_entries);
760 }
761 
762 typedef struct
763 {
764   float x_1, y_1;
765   float x_2, y_2;
766 } ClipBounds;
767 
768 static CoglBool
can_software_clip_entry(CoglJournalEntry * journal_entry,CoglJournalEntry * prev_journal_entry,CoglClipStack * clip_stack,ClipBounds * clip_bounds_out)769 can_software_clip_entry (CoglJournalEntry *journal_entry,
770                          CoglJournalEntry *prev_journal_entry,
771                          CoglClipStack *clip_stack,
772                          ClipBounds *clip_bounds_out)
773 {
774   CoglPipeline *pipeline = journal_entry->pipeline;
775   CoglClipStack *clip_entry;
776   int layer_num;
777 
778   clip_bounds_out->x_1 = -G_MAXFLOAT;
779   clip_bounds_out->y_1 = -G_MAXFLOAT;
780   clip_bounds_out->x_2 = G_MAXFLOAT;
781   clip_bounds_out->y_2 = G_MAXFLOAT;
782 
783   /* Check the pipeline is usable. We can short-cut here for
784      entries using the same pipeline as the previous entry */
785   if (prev_journal_entry == NULL || pipeline != prev_journal_entry->pipeline)
786     {
787       /* If the pipeline has a user program then we can't reliably modify
788          the texture coordinates */
789       if (cogl_pipeline_get_user_program (pipeline))
790         return FALSE;
791 
792       /* If any of the pipeline layers have a texture matrix then we can't
793          reliably modify the texture coordinates */
794       for (layer_num = cogl_pipeline_get_n_layers (pipeline) - 1;
795            layer_num >= 0;
796            layer_num--)
797         if (_cogl_pipeline_layer_has_user_matrix (pipeline, layer_num))
798           return FALSE;
799     }
800 
801   /* Now we need to verify that each clip entry's matrix is just a
802      translation of the journal entry's modelview matrix. We can
803      also work out the bounds of the clip in modelview space using
804      this translation */
805   for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent)
806     {
807       float rect_x1, rect_y1, rect_x2, rect_y2;
808       CoglClipStackRect *clip_rect;
809       float tx, ty, tz;
810       CoglMatrixEntry *modelview_entry;
811 
812       clip_rect = (CoglClipStackRect *) clip_entry;
813 
814       modelview_entry = journal_entry->modelview_entry;
815       if (!cogl_matrix_entry_calculate_translation (clip_rect->matrix_entry,
816                                                      modelview_entry,
817                                                      &tx, &ty, &tz))
818         return FALSE;
819 
820       if (clip_rect->x0 < clip_rect->x1)
821         {
822           rect_x1 = clip_rect->x0;
823           rect_x2 = clip_rect->x1;
824         }
825       else
826         {
827           rect_x1 = clip_rect->x1;
828           rect_x2 = clip_rect->x0;
829         }
830       if (clip_rect->y0 < clip_rect->y1)
831         {
832           rect_y1 = clip_rect->y0;
833           rect_y2 = clip_rect->y1;
834         }
835       else
836         {
837           rect_y1 = clip_rect->y1;
838           rect_y2 = clip_rect->y0;
839         }
840 
841       clip_bounds_out->x_1 = MAX (clip_bounds_out->x_1, rect_x1 - tx);
842       clip_bounds_out->y_1 = MAX (clip_bounds_out->y_1, rect_y1 - ty);
843       clip_bounds_out->x_2 = MIN (clip_bounds_out->x_2, rect_x2 - tx);
844       clip_bounds_out->y_2 = MIN (clip_bounds_out->y_2, rect_y2 - ty);
845     }
846 
847   if (clip_bounds_out->x_2 <= clip_bounds_out->x_1 ||
848       clip_bounds_out->y_2 <= clip_bounds_out->y_1)
849     memset (clip_bounds_out, 0, sizeof (ClipBounds));
850 
851   return TRUE;
852 }
853 
854 static void
software_clip_entry(CoglJournalEntry * journal_entry,float * verts,ClipBounds * clip_bounds)855 software_clip_entry (CoglJournalEntry *journal_entry,
856                      float *verts,
857                      ClipBounds *clip_bounds)
858 {
859   size_t stride =
860     GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (journal_entry->n_layers);
861   float rx1, ry1, rx2, ry2;
862   float vx1, vy1, vx2, vy2;
863   int layer_num;
864 
865   /* Remove the clip on the entry */
866   _cogl_clip_stack_unref (journal_entry->clip_stack);
867   journal_entry->clip_stack = NULL;
868 
869   vx1 = verts[0];
870   vy1 = verts[1];
871   vx2 = verts[stride];
872   vy2 = verts[stride + 1];
873 
874   if (vx1 < vx2)
875     {
876       rx1 = vx1;
877       rx2 = vx2;
878     }
879   else
880     {
881       rx1 = vx2;
882       rx2 = vx1;
883     }
884   if (vy1 < vy2)
885     {
886       ry1 = vy1;
887       ry2 = vy2;
888     }
889   else
890     {
891       ry1 = vy2;
892       ry2 = vy1;
893     }
894 
895   rx1 = CLAMP (rx1, clip_bounds->x_1, clip_bounds->x_2);
896   ry1 = CLAMP (ry1, clip_bounds->y_1, clip_bounds->y_2);
897   rx2 = CLAMP (rx2, clip_bounds->x_1, clip_bounds->x_2);
898   ry2 = CLAMP (ry2, clip_bounds->y_1, clip_bounds->y_2);
899 
900   /* Check if the rectangle intersects the clip at all */
901   if (rx1 == rx2 || ry1 == ry2)
902     /* Will set all of the vertex data to 0 in the hope that this
903        will create a degenerate rectangle and the GL driver will
904        be able to clip it quickly */
905     memset (verts, 0, sizeof (float) * stride * 2);
906   else
907     {
908       if (vx1 > vx2)
909         {
910           float t = rx1;
911           rx1 = rx2;
912           rx2 = t;
913         }
914       if (vy1 > vy2)
915         {
916           float t = ry1;
917           ry1 = ry2;
918           ry2 = t;
919         }
920 
921       verts[0] = rx1;
922       verts[1] = ry1;
923       verts[stride] = rx2;
924       verts[stride + 1] = ry2;
925 
926       /* Convert the rectangle coordinates to a fraction of the original
927          rectangle */
928       rx1 = (rx1 - vx1) / (vx2 - vx1);
929       ry1 = (ry1 - vy1) / (vy2 - vy1);
930       rx2 = (rx2 - vx1) / (vx2 - vx1);
931       ry2 = (ry2 - vy1) / (vy2 - vy1);
932 
933       for (layer_num = 0; layer_num < journal_entry->n_layers; layer_num++)
934         {
935           float *t = verts + 2 + 2 * layer_num;
936           float tx1 = t[0], ty1 = t[1];
937           float tx2 = t[stride], ty2 = t[stride + 1];
938           t[0] = rx1 * (tx2 - tx1) + tx1;
939           t[1] = ry1 * (ty2 - ty1) + ty1;
940           t[stride] = rx2 * (tx2 - tx1) + tx1;
941           t[stride + 1] = ry2 * (ty2 - ty1) + ty1;
942         }
943     }
944 }
945 
946 static void
maybe_software_clip_entries(CoglJournalEntry * batch_start,int batch_len,CoglJournalFlushState * state)947 maybe_software_clip_entries (CoglJournalEntry      *batch_start,
948                              int                    batch_len,
949                              CoglJournalFlushState *state)
950 {
951   CoglContext *ctx;
952   CoglJournal *journal;
953   CoglClipStack *clip_stack, *clip_entry;
954   int entry_num;
955 
956   /* This tries to find cases where the entry is logged with a clip
957      but it would be faster to modify the vertex and texture
958      coordinates rather than flush the clip so that it can batch
959      better */
960 
961   /* If the batch is reasonably long then it's worthwhile programming
962      the GPU to do the clip */
963   if (batch_len >= COGL_JOURNAL_HARDWARE_CLIP_THRESHOLD)
964     return;
965 
966   clip_stack = batch_start->clip_stack;
967 
968   if (clip_stack == NULL)
969     return;
970 
971   /* Verify that all of the clip stack entries are a simple rectangle
972      clip */
973   for (clip_entry = clip_stack; clip_entry; clip_entry = clip_entry->parent)
974     if (clip_entry->type != COGL_CLIP_STACK_RECT)
975       return;
976 
977   ctx = state->ctx;
978   journal = state->journal;
979 
980   /* This scratch buffer is used to store the translation for each
981      entry in the journal. We store it in a separate buffer because
982      it's expensive to calculate but at this point we still don't know
983      whether we can clip all of the entries so we don't want to do the
984      rest of the dependant calculations until we're sure we can. */
985   if (ctx->journal_clip_bounds == NULL)
986     ctx->journal_clip_bounds = g_array_new (FALSE, FALSE, sizeof (ClipBounds));
987   g_array_set_size (ctx->journal_clip_bounds, batch_len);
988 
989   for (entry_num = 0; entry_num < batch_len; entry_num++)
990     {
991       CoglJournalEntry *journal_entry = batch_start + entry_num;
992       CoglJournalEntry *prev_journal_entry =
993         entry_num ? batch_start + (entry_num - 1) : NULL;
994       ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds,
995                                                 ClipBounds, entry_num);
996 
997       if (!can_software_clip_entry (journal_entry, prev_journal_entry,
998                                     clip_stack,
999                                     clip_bounds))
1000         return;
1001     }
1002 
1003   /* If we make it here then we know we can software clip the entire batch */
1004 
1005   COGL_NOTE (CLIPPING, "Software clipping a batch of length %i", batch_len);
1006 
1007   for (entry_num = 0; entry_num < batch_len; entry_num++)
1008     {
1009       CoglJournalEntry *journal_entry = batch_start + entry_num;
1010       float *verts = &g_array_index (journal->vertices, float,
1011                                      journal_entry->array_offset + 1);
1012       ClipBounds *clip_bounds = &g_array_index (ctx->journal_clip_bounds,
1013                                                 ClipBounds, entry_num);
1014 
1015       software_clip_entry (journal_entry, verts, clip_bounds);
1016     }
1017 
1018   return;
1019 }
1020 
1021 static void
_cogl_journal_maybe_software_clip_entries(CoglJournalEntry * batch_start,int batch_len,void * data)1022 _cogl_journal_maybe_software_clip_entries (CoglJournalEntry *batch_start,
1023                                            int               batch_len,
1024                                            void             *data)
1025 {
1026   CoglJournalFlushState *state = data;
1027 
1028   COGL_STATIC_TIMER (time_check_software_clip,
1029                      "Journal Flush", /* parent */
1030                      "flush: software clipping",
1031                      "Time spent software clipping",
1032                      0 /* no application private data */);
1033 
1034   COGL_TIMER_START (_cogl_uprof_context,
1035                     time_check_software_clip);
1036 
1037   maybe_software_clip_entries (batch_start, batch_len, state);
1038 
1039   COGL_TIMER_STOP (_cogl_uprof_context,
1040                    time_check_software_clip);
1041 }
1042 
1043 static CoglBool
compare_entry_clip_stacks(CoglJournalEntry * entry0,CoglJournalEntry * entry1)1044 compare_entry_clip_stacks (CoglJournalEntry *entry0, CoglJournalEntry *entry1)
1045 {
1046   return entry0->clip_stack == entry1->clip_stack;
1047 }
1048 
1049 /* Gets a new vertex array from the pool. A reference is taken on the
1050    array so it can be treated as if it was just newly allocated */
1051 static CoglAttributeBuffer *
create_attribute_buffer(CoglJournal * journal,size_t n_bytes)1052 create_attribute_buffer (CoglJournal *journal,
1053                          size_t n_bytes)
1054 {
1055   CoglAttributeBuffer *vbo;
1056   CoglContext *ctx = journal->framebuffer->context;
1057 
1058   /* If CoglBuffers are being emulated with malloc then there's not
1059      really any point in using the pool so we'll just allocate the
1060      buffer directly */
1061   if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_VBOS))
1062     return cogl_attribute_buffer_new_with_size (ctx, n_bytes);
1063 
1064   vbo = journal->vbo_pool[journal->next_vbo_in_pool];
1065 
1066   if (vbo == NULL)
1067     {
1068       vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes);
1069       journal->vbo_pool[journal->next_vbo_in_pool] = vbo;
1070     }
1071   else if (cogl_buffer_get_size (COGL_BUFFER (vbo)) < n_bytes)
1072     {
1073       /* If the buffer is too small then we'll just recreate it */
1074       cogl_object_unref (vbo);
1075       vbo = cogl_attribute_buffer_new_with_size (ctx, n_bytes);
1076       journal->vbo_pool[journal->next_vbo_in_pool] = vbo;
1077     }
1078 
1079   journal->next_vbo_in_pool = ((journal->next_vbo_in_pool + 1) %
1080                                COGL_JOURNAL_VBO_POOL_SIZE);
1081 
1082   return cogl_object_ref (vbo);
1083 }
1084 
1085 static CoglAttributeBuffer *
upload_vertices(CoglJournal * journal,const CoglJournalEntry * entries,int n_entries,size_t needed_vbo_len,GArray * vertices)1086 upload_vertices (CoglJournal *journal,
1087                  const CoglJournalEntry *entries,
1088                  int n_entries,
1089                  size_t needed_vbo_len,
1090                  GArray *vertices)
1091 {
1092   CoglAttributeBuffer *attribute_buffer;
1093   CoglBuffer *buffer;
1094   const float *vin;
1095   float *vout;
1096   int entry_num;
1097   int i;
1098   CoglMatrixEntry *last_modelview_entry = NULL;
1099   CoglMatrix modelview;
1100 
1101   g_assert (needed_vbo_len);
1102 
1103   attribute_buffer = create_attribute_buffer (journal, needed_vbo_len * 4);
1104   buffer = COGL_BUFFER (attribute_buffer);
1105   cogl_buffer_set_update_hint (buffer, COGL_BUFFER_UPDATE_HINT_DYNAMIC);
1106 
1107   vout = _cogl_buffer_map_range_for_fill_or_fallback (buffer,
1108                                                       0, /* offset */
1109                                                       needed_vbo_len * 4);
1110   vin = &g_array_index (vertices, float, 0);
1111 
1112   /* Expand the number of vertices from 2 to 4 while uploading */
1113   for (entry_num = 0; entry_num < n_entries; entry_num++)
1114     {
1115       const CoglJournalEntry *entry = entries + entry_num;
1116       size_t vb_stride = GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (entry->n_layers);
1117       size_t array_stride =
1118         GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers);
1119 
1120       /* Copy the color to all four of the vertices */
1121       for (i = 0; i < 4; i++)
1122         memcpy (vout + vb_stride * i + POS_STRIDE, vin, 4);
1123       vin++;
1124 
1125       if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_TRANSFORM)))
1126         {
1127           vout[vb_stride * 0] = vin[0];
1128           vout[vb_stride * 0 + 1] = vin[1];
1129           vout[vb_stride * 1] = vin[0];
1130           vout[vb_stride * 1 + 1] = vin[array_stride + 1];
1131           vout[vb_stride * 2] = vin[array_stride];
1132           vout[vb_stride * 2 + 1] = vin[array_stride + 1];
1133           vout[vb_stride * 3] = vin[array_stride];
1134           vout[vb_stride * 3 + 1] = vin[1];
1135         }
1136       else
1137         {
1138           float v[8];
1139 
1140           v[0] = vin[0];
1141           v[1] = vin[1];
1142           v[2] = vin[0];
1143           v[3] = vin[array_stride + 1];
1144           v[4] = vin[array_stride];
1145           v[5] = vin[array_stride + 1];
1146           v[6] = vin[array_stride];
1147           v[7] = vin[1];
1148 
1149           if (entry->modelview_entry != last_modelview_entry)
1150             cogl_matrix_entry_get (entry->modelview_entry, &modelview);
1151           cogl_matrix_transform_points (&modelview,
1152                                         2, /* n_components */
1153                                         sizeof (float) * 2, /* stride_in */
1154                                         v, /* points_in */
1155                                         /* strideout */
1156                                         vb_stride * sizeof (float),
1157                                         vout, /* points_out */
1158                                         4 /* n_points */);
1159         }
1160 
1161       for (i = 0; i < entry->n_layers; i++)
1162         {
1163           const float *tin = vin + 2;
1164           float *tout = vout + POS_STRIDE + COLOR_STRIDE;
1165 
1166           tout[vb_stride * 0 + i * 2] = tin[i * 2];
1167           tout[vb_stride * 0 + 1 + i * 2] = tin[i * 2 + 1];
1168           tout[vb_stride * 1 + i * 2] = tin[i * 2];
1169           tout[vb_stride * 1 + 1 + i * 2] = tin[array_stride + i * 2 + 1];
1170           tout[vb_stride * 2 + i * 2] = tin[array_stride + i * 2];
1171           tout[vb_stride * 2 + 1 + i * 2] = tin[array_stride + i * 2 + 1];
1172           tout[vb_stride * 3 + i * 2] = tin[array_stride + i * 2];
1173           tout[vb_stride * 3 + 1 + i * 2] = tin[i * 2 + 1];
1174         }
1175 
1176       vin += array_stride * 2;
1177       vout += vb_stride * 4;
1178     }
1179 
1180   _cogl_buffer_unmap_for_fill_or_fallback (buffer);
1181 
1182   return attribute_buffer;
1183 }
1184 
1185 void
_cogl_journal_discard(CoglJournal * journal)1186 _cogl_journal_discard (CoglJournal *journal)
1187 {
1188   int i;
1189 
1190   if (journal->entries->len <= 0)
1191     return;
1192 
1193   for (i = 0; i < journal->entries->len; i++)
1194     {
1195       CoglJournalEntry *entry =
1196         &g_array_index (journal->entries, CoglJournalEntry, i);
1197       _cogl_pipeline_journal_unref (entry->pipeline);
1198       cogl_matrix_entry_unref (entry->modelview_entry);
1199       _cogl_clip_stack_unref (entry->clip_stack);
1200     }
1201 
1202   g_array_set_size (journal->entries, 0);
1203   g_array_set_size (journal->vertices, 0);
1204   journal->needed_vbo_len = 0;
1205   journal->fast_read_pixel_count = 0;
1206 
1207   /* The journal only holds a reference to the framebuffer while the
1208      journal is not empty */
1209   cogl_object_unref (journal->framebuffer);
1210 }
1211 
1212 /* Note: A return value of FALSE doesn't mean 'no' it means
1213  * 'unknown' */
1214 CoglBool
_cogl_journal_all_entries_within_bounds(CoglJournal * journal,float clip_x0,float clip_y0,float clip_x1,float clip_y1)1215 _cogl_journal_all_entries_within_bounds (CoglJournal *journal,
1216                                          float clip_x0,
1217                                          float clip_y0,
1218                                          float clip_x1,
1219                                          float clip_y1)
1220 {
1221   CoglJournalEntry *entry = (CoglJournalEntry *)journal->entries->data;
1222   CoglClipStack *clip_entry;
1223   CoglClipStack *reference = NULL;
1224   int bounds_x0;
1225   int bounds_y0;
1226   int bounds_x1;
1227   int bounds_y1;
1228   int i;
1229 
1230   if (journal->entries->len == 0)
1231     return TRUE;
1232 
1233   /* Find the shortest clip_stack ancestry that leaves us in the
1234    * required bounds */
1235   for (clip_entry = entry->clip_stack;
1236        clip_entry;
1237        clip_entry = clip_entry->parent)
1238     {
1239       _cogl_clip_stack_get_bounds (clip_entry,
1240                                    &bounds_x0, &bounds_y0,
1241                                    &bounds_x1, &bounds_y1);
1242 
1243       if (bounds_x0 >= clip_x0 && bounds_y0 >= clip_y0 &&
1244           bounds_x1 <= clip_x1 && bounds_y1 <= clip_y1)
1245         reference = clip_entry;
1246       else
1247         break;
1248     }
1249 
1250   if (!reference)
1251     return FALSE;
1252 
1253   /* For the remaining journal entries we will only verify they share
1254    * 'reference' as an ancestor in their clip stack since that's
1255    * enough to know that they would be within the required bounds.
1256    */
1257   for (i = 1; i < journal->entries->len; i++)
1258     {
1259       CoglBool found_reference = FALSE;
1260       entry = &g_array_index (journal->entries, CoglJournalEntry, i);
1261 
1262       for (clip_entry = entry->clip_stack;
1263            clip_entry;
1264            clip_entry = clip_entry->parent)
1265         {
1266           if (clip_entry == reference)
1267             {
1268               found_reference = TRUE;
1269               break;
1270             }
1271         }
1272 
1273       if (!found_reference)
1274         return FALSE;
1275     }
1276 
1277   return TRUE;
1278 }
1279 
1280 static void
post_fences(CoglJournal * journal)1281 post_fences (CoglJournal *journal)
1282 {
1283   CoglFenceClosure *fence, *tmp;
1284 
1285   _cogl_list_for_each_safe (fence, tmp, &journal->pending_fences, link)
1286     {
1287       _cogl_list_remove (&fence->link);
1288       _cogl_fence_submit (fence);
1289     }
1290 }
1291 
1292 /* XXX NB: When _cogl_journal_flush() returns all state relating
1293  * to pipelines, all glEnable flags and current matrix state
1294  * is undefined.
1295  */
1296 void
_cogl_journal_flush(CoglJournal * journal)1297 _cogl_journal_flush (CoglJournal *journal)
1298 {
1299   CoglFramebuffer *framebuffer;
1300   CoglContext *ctx;
1301   CoglJournalFlushState state;
1302   int i;
1303   COGL_STATIC_TIMER (flush_timer,
1304                      "Mainloop", /* parent */
1305                      "Journal Flush",
1306                      "The time spent flushing the Cogl journal",
1307                      0 /* no application private data */);
1308   COGL_STATIC_TIMER (discard_timer,
1309                      "Journal Flush", /* parent */
1310                      "flush: discard",
1311                      "The time spent discarding the Cogl journal after a flush",
1312                      0 /* no application private data */);
1313 
1314   if (journal->entries->len == 0)
1315     {
1316       post_fences (journal);
1317       return;
1318     }
1319 
1320   framebuffer = journal->framebuffer;
1321   ctx = framebuffer->context;
1322 
1323   /* The entries in this journal may depend on images in other
1324    * framebuffers which may require that we flush the journals
1325    * associated with those framebuffers before we can flush
1326    * this journal... */
1327   _cogl_framebuffer_flush_dependency_journals (framebuffer);
1328 
1329   /* Note: we start the timer after flushing dependency journals so
1330    * that the timer isn't started recursively. */
1331   COGL_TIMER_START (_cogl_uprof_context, flush_timer);
1332 
1333   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_BATCHING)))
1334     g_print ("BATCHING: journal len = %d\n", journal->entries->len);
1335 
1336   /* NB: the journal deals with flushing the modelview stack and clip
1337      state manually */
1338   _cogl_framebuffer_flush_state (framebuffer,
1339                                  framebuffer,
1340                                  COGL_FRAMEBUFFER_STATE_ALL &
1341                                  ~(COGL_FRAMEBUFFER_STATE_MODELVIEW |
1342                                    COGL_FRAMEBUFFER_STATE_CLIP));
1343 
1344   /* We need to mark the current modelview state of the framebuffer as
1345    * dirty because we are going to manually replace it */
1346   ctx->current_draw_buffer_changes |= COGL_FRAMEBUFFER_STATE_MODELVIEW;
1347 
1348   state.ctx = ctx;
1349   state.journal = journal;
1350 
1351   state.attributes = ctx->journal_flush_attributes_array;
1352 
1353   if (G_UNLIKELY ((COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_SOFTWARE_CLIP)) == 0))
1354     {
1355       /* We do an initial walk of the journal to analyse the clip stack
1356          batches to see if we can do software clipping. We do this as a
1357          separate walk of the journal because we can modify entries and
1358          this may end up joining together clip stack batches in the next
1359          iteration. */
1360       batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */
1361                       journal->entries->len, /* max number of entries to consider */
1362                       compare_entry_clip_stacks,
1363                       _cogl_journal_maybe_software_clip_entries, /* callback */
1364                       &state); /* data */
1365     }
1366 
1367   /* We upload the vertices after the clip stack pass in case it
1368      modifies the entries */
1369   state.attribute_buffer =
1370     upload_vertices (journal,
1371                      &g_array_index (journal->entries, CoglJournalEntry, 0),
1372                      journal->entries->len,
1373                      journal->needed_vbo_len,
1374                      journal->vertices);
1375   state.array_offset = 0;
1376 
1377   /* batch_and_call() batches a list of journal entries according to some
1378    * given criteria and calls a callback once for each determined batch.
1379    *
1380    * The process of flushing the journal is staggered to reduce the amount
1381    * of driver/GPU state changes necessary:
1382    * 1) We split the entries according to the clip state.
1383    * 2) We split the entries according to the stride of the vertices:
1384    *      Each time the stride of our vertex data changes we need to call
1385    *      gl{Vertex,Color}Pointer to inform GL of new VBO offsets.
1386    *      Currently the only thing that affects the stride of our vertex data
1387    *      is the number of pipeline layers.
1388    * 3) We split the entries explicitly by the number of pipeline layers:
1389    *      We pad our vertex data when the number of layers is < 2 so that we
1390    *      can minimize changes in stride. Each time the number of layers
1391    *      changes we need to call glTexCoordPointer to inform GL of new VBO
1392    *      offsets.
1393    * 4) We then split according to compatible Cogl pipelines:
1394    *      This is where we flush pipeline state
1395    * 5) Finally we split according to modelview matrix changes:
1396    *      This is when we finally tell GL to draw something.
1397    *      Note: Splitting by modelview changes is skipped when are doing the
1398    *      vertex transformation in software at log time.
1399    */
1400   batch_and_call ((CoglJournalEntry *)journal->entries->data, /* first entry */
1401                   journal->entries->len, /* max number of entries to consider */
1402                   compare_entry_clip_stacks,
1403                   _cogl_journal_flush_clip_stacks_and_entries, /* callback */
1404                   &state); /* data */
1405 
1406   for (i = 0; i < state.attributes->len; i++)
1407     cogl_object_unref (g_array_index (state.attributes, CoglAttribute *, i));
1408   g_array_set_size (state.attributes, 0);
1409 
1410   cogl_object_unref (state.attribute_buffer);
1411 
1412   COGL_TIMER_START (_cogl_uprof_context, discard_timer);
1413   _cogl_journal_discard (journal);
1414   COGL_TIMER_STOP (_cogl_uprof_context, discard_timer);
1415 
1416   post_fences (journal);
1417 
1418   COGL_TIMER_STOP (_cogl_uprof_context, flush_timer);
1419 }
1420 
1421 static CoglBool
add_framebuffer_deps_cb(CoglPipelineLayer * layer,void * user_data)1422 add_framebuffer_deps_cb (CoglPipelineLayer *layer, void *user_data)
1423 {
1424   CoglFramebuffer *framebuffer = user_data;
1425   CoglTexture *texture = _cogl_pipeline_layer_get_texture_real (layer);
1426   const GList *l;
1427 
1428   if (!texture)
1429     return TRUE;
1430 
1431   for (l = _cogl_texture_get_associated_framebuffers (texture); l; l = l->next)
1432     _cogl_framebuffer_add_dependency (framebuffer, l->data);
1433 
1434   return TRUE;
1435 }
1436 
1437 void
_cogl_journal_log_quad(CoglJournal * journal,const float * position,CoglPipeline * pipeline,int n_layers,CoglTexture * layer0_override_texture,const float * tex_coords,unsigned int tex_coords_len)1438 _cogl_journal_log_quad (CoglJournal  *journal,
1439                         const float  *position,
1440                         CoglPipeline *pipeline,
1441                         int           n_layers,
1442                         CoglTexture  *layer0_override_texture,
1443                         const float  *tex_coords,
1444                         unsigned int  tex_coords_len)
1445 {
1446   CoglFramebuffer *framebuffer = journal->framebuffer;
1447   size_t stride;
1448   int next_vert;
1449   float *v;
1450   int i;
1451   int next_entry;
1452   uint32_t disable_layers;
1453   CoglJournalEntry *entry;
1454   CoglPipeline *final_pipeline;
1455   CoglClipStack *clip_stack;
1456   CoglPipelineFlushOptions flush_options;
1457   CoglMatrixStack *modelview_stack;
1458   COGL_STATIC_TIMER (log_timer,
1459                      "Mainloop", /* parent */
1460                      "Journal Log",
1461                      "The time spent logging in the Cogl journal",
1462                      0 /* no application private data */);
1463 
1464   COGL_TIMER_START (_cogl_uprof_context, log_timer);
1465 
1466   /* Adding something to the journal should mean that we are in the
1467    * middle of the scene. Although this will also end up being set
1468    * when the journal is actually flushed, we set it here explicitly
1469    * so that we will know sooner */
1470   _cogl_framebuffer_mark_mid_scene (framebuffer);
1471 
1472   /* If the framebuffer was previously empty then we'll take a
1473      reference to the current framebuffer. This reference will be
1474      removed when the journal is flushed */
1475   if (journal->vertices->len == 0)
1476     cogl_object_ref (framebuffer);
1477 
1478   /* The vertex data is logged into a separate array. The data needs
1479      to be copied into a vertex array before it's given to GL so we
1480      only store two vertices per quad and expand it to four while
1481      uploading. */
1482 
1483   /* XXX: See definition of GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS for details
1484    * about how we pack our vertex data */
1485   stride = GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (n_layers);
1486 
1487   next_vert = journal->vertices->len;
1488   g_array_set_size (journal->vertices, next_vert + 2 * stride + 1);
1489   v = &g_array_index (journal->vertices, float, next_vert);
1490 
1491   /* We calculate the needed size of the vbo as we go because it
1492      depends on the number of layers in each entry and it's not easy
1493      calculate based on the length of the logged vertices array */
1494   journal->needed_vbo_len += GET_JOURNAL_VB_STRIDE_FOR_N_LAYERS (n_layers) * 4;
1495 
1496   /* XXX: All the jumping around to fill in this strided buffer doesn't
1497    * seem ideal. */
1498 
1499   /* FIXME: This is a hacky optimization, since it will break if we
1500    * change the definition of CoglColor: */
1501   _cogl_pipeline_get_colorubv (pipeline, (uint8_t *) v);
1502   v++;
1503 
1504   memcpy (v, position, sizeof (float) * 2);
1505   memcpy (v + stride, position + 2, sizeof (float) * 2);
1506 
1507   for (i = 0; i < n_layers; i++)
1508     {
1509       /* XXX: See definition of GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS
1510        * for details about how we pack our vertex data */
1511       GLfloat *t = v + 2 + i * 2;
1512 
1513       memcpy (t, tex_coords + i * 4, sizeof (float) * 2);
1514       memcpy (t + stride, tex_coords + i * 4 + 2, sizeof (float) * 2);
1515     }
1516 
1517   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_JOURNAL)))
1518     {
1519       g_print ("Logged new quad:\n");
1520       v = &g_array_index (journal->vertices, float, next_vert);
1521       _cogl_journal_dump_logged_quad ((uint8_t *)v, n_layers);
1522     }
1523 
1524   next_entry = journal->entries->len;
1525   g_array_set_size (journal->entries, next_entry + 1);
1526   entry = &g_array_index (journal->entries, CoglJournalEntry, next_entry);
1527 
1528   entry->n_layers = n_layers;
1529   entry->array_offset = next_vert;
1530 
1531   final_pipeline = pipeline;
1532 
1533   flush_options.flags = 0;
1534   if (G_UNLIKELY (cogl_pipeline_get_n_layers (pipeline) != n_layers))
1535     {
1536       disable_layers = (1 << n_layers) - 1;
1537       disable_layers = ~disable_layers;
1538       flush_options.disable_layers = disable_layers;
1539       flush_options.flags |= COGL_PIPELINE_FLUSH_DISABLE_MASK;
1540     }
1541   if (G_UNLIKELY (layer0_override_texture))
1542     {
1543       flush_options.flags |= COGL_PIPELINE_FLUSH_LAYER0_OVERRIDE;
1544       flush_options.layer0_override_texture = layer0_override_texture;
1545     }
1546 
1547   if (G_UNLIKELY (flush_options.flags))
1548     {
1549       final_pipeline = cogl_pipeline_copy (pipeline);
1550       _cogl_pipeline_apply_overrides (final_pipeline, &flush_options);
1551     }
1552 
1553   entry->pipeline = _cogl_pipeline_journal_ref (final_pipeline);
1554 
1555   clip_stack = _cogl_framebuffer_get_clip_stack (framebuffer);
1556   entry->clip_stack = _cogl_clip_stack_ref (clip_stack);
1557 
1558   if (G_UNLIKELY (final_pipeline != pipeline))
1559     cogl_object_unref (final_pipeline);
1560 
1561   modelview_stack =
1562     _cogl_framebuffer_get_modelview_stack (framebuffer);
1563   entry->modelview_entry = cogl_matrix_entry_ref (modelview_stack->last_entry);
1564 
1565   _cogl_pipeline_foreach_layer_internal (pipeline,
1566                                          add_framebuffer_deps_cb,
1567                                          framebuffer);
1568 
1569   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_DISABLE_BATCHING)))
1570     _cogl_journal_flush (journal);
1571 
1572   COGL_TIMER_STOP (_cogl_uprof_context, log_timer);
1573 }
1574 
1575 static void
entry_to_screen_polygon(CoglFramebuffer * framebuffer,const CoglJournalEntry * entry,float * vertices,float * poly)1576 entry_to_screen_polygon (CoglFramebuffer *framebuffer,
1577                          const CoglJournalEntry *entry,
1578                          float *vertices,
1579                          float *poly)
1580 {
1581   size_t array_stride =
1582     GET_JOURNAL_ARRAY_STRIDE_FOR_N_LAYERS (entry->n_layers);
1583   CoglMatrixStack *projection_stack;
1584   CoglMatrix projection;
1585   CoglMatrix modelview;
1586   int i;
1587   float viewport[4];
1588 
1589   poly[0] = vertices[0];
1590   poly[1] = vertices[1];
1591   poly[2] = 0;
1592   poly[3] = 1;
1593 
1594   poly[4] = vertices[0];
1595   poly[5] = vertices[array_stride + 1];
1596   poly[6] = 0;
1597   poly[7] = 1;
1598 
1599   poly[8] = vertices[array_stride];
1600   poly[9] = vertices[array_stride + 1];
1601   poly[10] = 0;
1602   poly[11] = 1;
1603 
1604   poly[12] = vertices[array_stride];
1605   poly[13] = vertices[1];
1606   poly[14] = 0;
1607   poly[15] = 1;
1608 
1609   /* TODO: perhaps split the following out into a more generalized
1610    * _cogl_transform_points utility...
1611    */
1612 
1613   cogl_matrix_entry_get (entry->modelview_entry, &modelview);
1614   cogl_matrix_transform_points (&modelview,
1615                                 2, /* n_components */
1616                                 sizeof (float) * 4, /* stride_in */
1617                                 poly, /* points_in */
1618                                 /* strideout */
1619                                 sizeof (float) * 4,
1620                                 poly, /* points_out */
1621                                 4 /* n_points */);
1622 
1623   projection_stack =
1624     _cogl_framebuffer_get_projection_stack (framebuffer);
1625   cogl_matrix_stack_get (projection_stack, &projection);
1626 
1627   cogl_matrix_project_points (&projection,
1628                               3, /* n_components */
1629                               sizeof (float) * 4, /* stride_in */
1630                               poly, /* points_in */
1631                               /* strideout */
1632                               sizeof (float) * 4,
1633                               poly, /* points_out */
1634                               4 /* n_points */);
1635 
1636   cogl_framebuffer_get_viewport4fv (framebuffer, viewport);
1637 
1638 /* Scale from OpenGL normalized device coordinates (ranging from -1 to 1)
1639  * to Cogl window/framebuffer coordinates (ranging from 0 to buffer-size) with
1640  * (0,0) being top left. */
1641 #define VIEWPORT_TRANSFORM_X(x, vp_origin_x, vp_width) \
1642     (  ( ((x) + 1.0) * ((vp_width) / 2.0) ) + (vp_origin_x)  )
1643 /* Note: for Y we first flip all coordinates around the X axis while in
1644  * normalized device coodinates */
1645 #define VIEWPORT_TRANSFORM_Y(y, vp_origin_y, vp_height) \
1646     (  ( ((-(y)) + 1.0) * ((vp_height) / 2.0) ) + (vp_origin_y)  )
1647 
1648   /* Scale from normalized device coordinates (in range [-1,1]) to
1649    * window coordinates ranging [0,window-size] ... */
1650   for (i = 0; i < 4; i++)
1651     {
1652       float w = poly[4 * i + 3];
1653 
1654       /* Perform perspective division */
1655       poly[4 * i] /= w;
1656       poly[4 * i + 1] /= w;
1657 
1658       /* Apply viewport transform */
1659       poly[4 * i] = VIEWPORT_TRANSFORM_X (poly[4 * i],
1660                                           viewport[0], viewport[2]);
1661       poly[4 * i + 1] = VIEWPORT_TRANSFORM_Y (poly[4 * i + 1],
1662                                               viewport[1], viewport[3]);
1663     }
1664 
1665 #undef VIEWPORT_TRANSFORM_X
1666 #undef VIEWPORT_TRANSFORM_Y
1667 }
1668 
1669 static CoglBool
try_checking_point_hits_entry_after_clipping(CoglFramebuffer * framebuffer,CoglJournalEntry * entry,float * vertices,float x,float y,CoglBool * hit)1670 try_checking_point_hits_entry_after_clipping (CoglFramebuffer *framebuffer,
1671                                               CoglJournalEntry *entry,
1672                                               float *vertices,
1673                                               float x,
1674                                               float y,
1675                                               CoglBool *hit)
1676 {
1677   CoglBool can_software_clip = TRUE;
1678   CoglBool needs_software_clip = FALSE;
1679   CoglClipStack *clip_entry;
1680 
1681   *hit = TRUE;
1682 
1683   /* Verify that all of the clip stack entries are simple rectangle
1684    * clips */
1685   for (clip_entry = entry->clip_stack;
1686        clip_entry;
1687        clip_entry = clip_entry->parent)
1688     {
1689       if (x < clip_entry->bounds_x0 ||
1690           x >= clip_entry->bounds_x1 ||
1691           y < clip_entry->bounds_y0 ||
1692           y >= clip_entry->bounds_y1)
1693         {
1694           *hit = FALSE;
1695           return TRUE;
1696         }
1697 
1698       if (clip_entry->type == COGL_CLIP_STACK_WINDOW_RECT)
1699         {
1700           /* XXX: technically we could still run the software clip in
1701            * this case because for our purposes we know this clip
1702            * can be ignored now, but [can_]sofware_clip_entry() doesn't
1703            * know this and will bail out. */
1704           can_software_clip = FALSE;
1705         }
1706       else if (clip_entry->type == COGL_CLIP_STACK_RECT)
1707         {
1708           CoglClipStackRect *rect_entry = (CoglClipStackRect *)entry;
1709 
1710           if (rect_entry->can_be_scissor == FALSE)
1711             needs_software_clip = TRUE;
1712           /* If can_be_scissor is TRUE then we know it's screen
1713            * aligned and the hit test we did above has determined
1714            * that we are inside this clip. */
1715         }
1716       else
1717         return FALSE;
1718     }
1719 
1720   if (needs_software_clip)
1721     {
1722       ClipBounds clip_bounds;
1723       float poly[16];
1724 
1725       if (!can_software_clip)
1726         return FALSE;
1727 
1728       if (!can_software_clip_entry (entry, NULL,
1729                                     entry->clip_stack, &clip_bounds))
1730         return FALSE;
1731 
1732       software_clip_entry (entry, vertices, &clip_bounds);
1733       entry_to_screen_polygon (framebuffer, entry, vertices, poly);
1734 
1735       *hit = _cogl_util_point_in_screen_poly (x, y, poly, sizeof (float) * 4, 4);
1736       return TRUE;
1737     }
1738 
1739   return TRUE;
1740 }
1741 
1742 CoglBool
_cogl_journal_try_read_pixel(CoglJournal * journal,int x,int y,CoglBitmap * bitmap,CoglBool * found_intersection)1743 _cogl_journal_try_read_pixel (CoglJournal *journal,
1744                               int x,
1745                               int y,
1746                               CoglBitmap *bitmap,
1747                               CoglBool *found_intersection)
1748 {
1749   CoglContext *ctx;
1750   CoglPixelFormat format;
1751   int i;
1752 
1753   /* XXX: this number has been plucked out of thin air, but the idea
1754    * is that if so many pixels are being read from the same un-changed
1755    * journal than we expect that it will be more efficient to fail
1756    * here so we end up flushing and rendering the journal so that
1757    * further reads can directly read from the framebuffer. There will
1758    * be a bit more lag to flush the render but if there are going to
1759    * continue being lots of arbitrary single pixel reads they will end
1760    * up faster in the end. */
1761   if (journal->fast_read_pixel_count > 50)
1762     return FALSE;
1763 
1764   format = cogl_bitmap_get_format (bitmap);
1765 
1766   if (format != COGL_PIXEL_FORMAT_RGBA_8888_PRE &&
1767       format != COGL_PIXEL_FORMAT_RGBA_8888)
1768     return FALSE;
1769 
1770   ctx = _cogl_bitmap_get_context (bitmap);
1771 
1772   *found_intersection = FALSE;
1773 
1774   /* NB: The most recently added journal entry is the last entry, and
1775    * assuming this is a simple scene only comprised of opaque coloured
1776    * rectangles with no special pipelines involved (e.g. enabling
1777    * depth testing) then we can assume painter's algorithm for the
1778    * entries and so our fast read-pixel just needs to walk backwards
1779    * through the journal entries trying to intersect each entry with
1780    * the given point of interest. */
1781   for (i = journal->entries->len - 1; i >= 0; i--)
1782     {
1783       CoglJournalEntry *entry =
1784         &g_array_index (journal->entries, CoglJournalEntry, i);
1785       uint8_t *color = (uint8_t *)&g_array_index (journal->vertices, float,
1786                                                 entry->array_offset);
1787       float *vertices = (float *)color + 1;
1788       float poly[16];
1789       CoglFramebuffer *framebuffer = journal->framebuffer;
1790       uint8_t *pixel;
1791       CoglError *ignore_error;
1792 
1793       entry_to_screen_polygon (framebuffer, entry, vertices, poly);
1794 
1795       if (!_cogl_util_point_in_screen_poly (x, y, poly, sizeof (float) * 4, 4))
1796         continue;
1797 
1798       if (entry->clip_stack)
1799         {
1800           CoglBool hit;
1801 
1802           if (!try_checking_point_hits_entry_after_clipping (framebuffer,
1803                                                              entry,
1804                                                              vertices,
1805                                                              x, y, &hit))
1806             return FALSE; /* hit couldn't be determined */
1807 
1808           if (!hit)
1809             continue;
1810         }
1811 
1812       *found_intersection = TRUE;
1813 
1814       /* If we find that the rectangle the point of interest
1815        * intersects has any state more complex than a constant opaque
1816        * color then we bail out. */
1817       if (!_cogl_pipeline_equal (ctx->opaque_color_pipeline, entry->pipeline,
1818                                  (COGL_PIPELINE_STATE_ALL &
1819                                   ~COGL_PIPELINE_STATE_COLOR),
1820                                  COGL_PIPELINE_LAYER_STATE_ALL,
1821                                  0))
1822         return FALSE;
1823 
1824 
1825       /* we currently only care about cases where the premultiplied or
1826        * unpremultipled colors are equivalent... */
1827       if (color[3] != 0xff)
1828         return FALSE;
1829 
1830       pixel = _cogl_bitmap_map (bitmap,
1831                                 COGL_BUFFER_ACCESS_WRITE,
1832                                 COGL_BUFFER_MAP_HINT_DISCARD,
1833                                 &ignore_error);
1834       if (pixel == NULL)
1835         {
1836           cogl_error_free (ignore_error);
1837           return FALSE;
1838         }
1839 
1840       pixel[0] = color[0];
1841       pixel[1] = color[1];
1842       pixel[2] = color[2];
1843       pixel[3] = color[3];
1844 
1845       _cogl_bitmap_unmap (bitmap);
1846 
1847       goto success;
1848     }
1849 
1850 success:
1851   journal->fast_read_pixel_count++;
1852   return TRUE;
1853 }
1854