[cogl/wip/rib/master-next: 28/29] debug: support wireframe mode with vertex shaders



commit 4a20a08aa250a06225fb1aaaad859d030d21dec5
Author: Robert Bragg <robert linux intel com>
Date:   Sun Feb 19 22:50:57 2012 +0000

    debug: support wireframe mode with vertex shaders
    
    Previously for the wireframe debug mode we identified the users
    "cogl_position_in" attribute, mapped that, created a replacement
    attribute with a LINE_LIST topology and then drew the attribute with a
    simple pipeline with a green colour. This meant we completely discarded
    the users original pipeline which may have involved vertex processing
    that would be useful to visualize in the wireframe.
    
    The new approach instead keeps the users attributes and instead
    generates CoglIndices that can be used to refererence the original
    attributes in LINE_LIST topology and instead of scrapping the user's
    pipeline we now create a weak copy of the original pipeline and just
    replace the fragment processing with a snippet to force the output color
    to be green.

 cogl/cogl-framebuffer.c |  325 ++++++++++++++++++++++++++---------------------
 1 files changed, 181 insertions(+), 144 deletions(-)
---
diff --git a/cogl/cogl-framebuffer.c b/cogl/cogl-framebuffer.c
index b57abd0..783f2e7 100644
--- a/cogl/cogl-framebuffer.c
+++ b/cogl/cogl-framebuffer.c
@@ -113,6 +113,8 @@ typedef struct _CoglFramebufferStackEntry
 
 extern CoglObjectClass _cogl_onscreen_class;
 
+static CoglUserDataKey wire_pipeline_key;
+
 static void _cogl_offscreen_free (CoglOffscreen *offscreen);
 
 COGL_OBJECT_DEFINE_WITH_CODE (Offscreen, offscreen,
@@ -2442,59 +2444,74 @@ get_index (void *indices,
 }
 
 static void
-add_line (void *vertices,
-          void *indices,
-          CoglIndicesType indices_type,
-          CoglAttribute *attribute,
-          int start,
-          int end,
-          CoglVertexP3 *lines,
-          int *n_line_vertices)
-{
-  int start_index = get_index (indices, indices_type, start);
-  int end_index = get_index (indices, indices_type, end);
-  float *v0 = (float *)((guint8 *)vertices + start_index * attribute->stride);
-  float *v1 = (float *)((guint8 *)vertices + end_index * attribute->stride);
-  float *o = (float *)(&lines[*n_line_vertices]);
-  int i;
+add_line (guint32 *line_indices,
+          int base,
+          void *user_indices,
+          CoglIndicesType user_indices_type,
+          int index0,
+          int index1,
+          int *pos)
+{
+  index0 = get_index (user_indices, user_indices_type, index0);
+  index1 = get_index (user_indices, user_indices_type, index1);
 
-  for (i = 0; i < attribute->n_components; i++)
-    *(o++) = *(v0++);
-  for (;i < 3; i++)
-    *(o++) = 0;
+  line_indices[(*pos)++] = base + index0;
+  line_indices[(*pos)++] = base + index1;
+}
 
-  for (i = 0; i < attribute->n_components; i++)
-    *(o++) = *(v1++);
-  for (;i < 3; i++)
-    *(o++) = 0;
+static int
+get_line_count (CoglVerticesMode mode, int n_vertices)
+{
+  if (mode == COGL_VERTICES_MODE_TRIANGLES &&
+      (n_vertices % 3) == 0)
+    {
+      return n_vertices;
+    }
+  else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
+           n_vertices >= 3)
+    {
+      return 2 * n_vertices - 3;
+    }
+  else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
+           n_vertices >= 3)
+    {
+      return 2 * n_vertices - 3;
+    }
+    /* In the journal we are a bit sneaky and actually use GL_QUADS
+     * which isn't actually a valid CoglVerticesMode! */
+#ifdef HAVE_COGL_GL
+  else if (mode == GL_QUADS && (n_vertices % 4) == 0)
+    {
+      return n_vertices;
+    }
+#endif
 
-  *n_line_vertices += 2;
+  g_return_val_if_reached (0);
 }
 
-static CoglVertexP3 *
-get_wire_lines (CoglAttribute *attribute,
-                CoglVerticesMode mode,
-                int n_vertices_in,
-                int *n_vertices_out,
-                CoglIndices *_indices)
+static CoglIndices *
+get_wire_line_indices (CoglContext *ctx,
+                       CoglVerticesMode mode,
+                       int first_vertex,
+                       int n_vertices_in,
+                       CoglIndices *user_indices,
+                       int *n_indices)
 {
-  CoglAttributeBuffer *attribute_buffer = cogl_attribute_get_buffer (attribute);
-  void *vertices;
+  int n_lines;
+  guint32 *line_indices;
   CoglIndexBuffer *index_buffer;
   void *indices;
   CoglIndicesType indices_type;
+  int base = first_vertex;
+  int pos;
   int i;
-  int n_lines;
-  CoglVertexP3 *out = NULL;
 
-  vertices = cogl_buffer_map (COGL_BUFFER (attribute_buffer),
-                              COGL_BUFFER_ACCESS_READ, 0);
-  if (_indices)
+  if (user_indices)
     {
-      index_buffer = cogl_indices_get_buffer (_indices);
+      index_buffer = cogl_indices_get_buffer (user_indices);
       indices = cogl_buffer_map (COGL_BUFFER (index_buffer),
                                  COGL_BUFFER_ACCESS_READ, 0);
-      indices_type = cogl_indices_get_type (_indices);
+      indices_type = cogl_indices_get_type (user_indices);
     }
   else
     {
@@ -2503,63 +2520,47 @@ get_wire_lines (CoglAttribute *attribute,
       indices_type = COGL_INDICES_TYPE_UNSIGNED_BYTE;
     }
 
-  *n_vertices_out = 0;
+  n_lines = get_line_count (mode, n_vertices_in);
+
+  /* Note: we are using COGL_INDICES_TYPE_UNSIGNED_INT so 4 bytes per index. */
+  line_indices = g_malloc (4 * n_lines * 2);
+
+  pos = 0;
 
   if (mode == COGL_VERTICES_MODE_TRIANGLES &&
       (n_vertices_in % 3) == 0)
     {
-      n_lines = n_vertices_in;
-      out = g_new (CoglVertexP3, n_lines * 2);
       for (i = 0; i < n_vertices_in; i += 3)
         {
-          add_line (vertices, indices, indices_type, attribute,
-                    i, i+1, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i+1, i+2, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i+2, i, out, n_vertices_out);
+          add_line (line_indices, base, indices, indices_type, i,   i+1, &pos);
+          add_line (line_indices, base, indices, indices_type, i+1, i+2, &pos);
+          add_line (line_indices, base, indices, indices_type, i+2, i,   &pos);
         }
     }
   else if (mode == COGL_VERTICES_MODE_TRIANGLE_FAN &&
            n_vertices_in >= 3)
     {
-      n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
-      add_line (vertices, indices, indices_type, attribute,
-                0, 1, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                1, 2, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                0, 2, out, n_vertices_out);
+      add_line (line_indices, base, indices, indices_type, 0, 1, &pos);
+      add_line (line_indices, base, indices, indices_type, 1, 2, &pos);
+      add_line (line_indices, base, indices, indices_type, 0, 2, &pos);
 
       for (i = 3; i < n_vertices_in; i++)
         {
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 1, i, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    0, i, out, n_vertices_out);
+          add_line (line_indices, base, indices, indices_type, i - 1, i, &pos);
+          add_line (line_indices, base, indices, indices_type, 0,     i, &pos);
         }
     }
   else if (mode == COGL_VERTICES_MODE_TRIANGLE_STRIP &&
            n_vertices_in >= 3)
     {
-      n_lines = 2 * n_vertices_in - 3;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
-      add_line (vertices, indices, indices_type, attribute,
-                0, 1, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                1, 2, out, n_vertices_out);
-      add_line (vertices, indices, indices_type, attribute,
-                0, 2, out, n_vertices_out);
+      add_line (line_indices, base, indices, indices_type, 0, 1, &pos);
+      add_line (line_indices, base, indices, indices_type, 1, 2, &pos);
+      add_line (line_indices, base, indices, indices_type, 0, 2, &pos);
 
       for (i = 3; i < n_vertices_in; i++)
         {
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 1, i, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i - 2, i, out, n_vertices_out);
+          add_line (line_indices, base, indices, indices_type, i - 1, i, &pos);
+          add_line (line_indices, base, indices, indices_type, i - 2, i, &pos);
         }
     }
     /* In the journal we are a bit sneaky and actually use GL_QUADS
@@ -2567,34 +2568,66 @@ get_wire_lines (CoglAttribute *attribute,
 #ifdef HAVE_COGL_GL
   else if (mode == GL_QUADS && (n_vertices_in % 4) == 0)
     {
-      n_lines = n_vertices_in;
-      out = g_new (CoglVertexP3, n_lines * 2);
-
       for (i = 0; i < n_vertices_in; i += 4)
         {
-          add_line (vertices, indices, indices_type, attribute,
-                    i, i + 1, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 1, i + 2, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 2, i + 3, out, n_vertices_out);
-          add_line (vertices, indices, indices_type, attribute,
-                    i + 3, i, out, n_vertices_out);
+          add_line (line_indices,
+                    base, indices, indices_type, i,     i + 1, &pos);
+          add_line (line_indices,
+                    base, indices, indices_type, i + 1, i + 2, &pos);
+          add_line (line_indices,
+                    base, indices, indices_type, i + 2, i + 3, &pos);
+          add_line (line_indices,
+                    base, indices, indices_type, i + 3, i,     &pos);
         }
     }
 #endif
 
-  if (vertices != NULL)
-    cogl_buffer_unmap (COGL_BUFFER (attribute_buffer));
-
-  if (indices != NULL)
+  if (user_indices)
     cogl_buffer_unmap (COGL_BUFFER (index_buffer));
 
-  return out;
+  *n_indices = n_lines * 2;
+
+  return cogl_indices_new (ctx,
+                           COGL_INDICES_TYPE_UNSIGNED_INT,
+                           line_indices,
+                           *n_indices);
+}
+
+static gboolean
+remove_layer_cb (CoglPipeline *pipeline,
+                 int layer_index,
+                 void *user_data)
+{
+  cogl_pipeline_remove_layer (pipeline, layer_index);
+  return TRUE;
+}
+
+static void
+pipeline_destroyed_cb (CoglPipeline *weak_pipeline, void *user_data)
+{
+  CoglPipeline *original_pipeline = user_data;
+
+  /* XXX: I think we probably need to provide a custom unref function for
+   * CoglPipeline because it's possible that we will reach this callback
+   * because original_pipeline is being freed which means cogl_object_unref
+   * will have already freed any associated user data.
+   *
+   * Setting more user data here will *probably* succeed but that may allocate
+   * a new user-data array which could be leaked.
+   *
+   * Potentially we could have a _cogl_object_free_user_data function so
+   * that a custom unref function could be written that can destroy weak
+   * pipeline children before removing user data.
+   */
+  cogl_object_set_user_data (COGL_OBJECT (original_pipeline),
+                             &wire_pipeline_key, NULL, NULL);
+
+  cogl_object_unref (weak_pipeline);
 }
 
 static void
-draw_wireframe (CoglFramebuffer *framebuffer,
+draw_wireframe (CoglContext *ctx,
+                CoglFramebuffer *framebuffer,
                 CoglPipeline *pipeline,
                 CoglVerticesMode mode,
                 int first_vertex,
@@ -2603,68 +2636,70 @@ draw_wireframe (CoglFramebuffer *framebuffer,
                 int n_attributes,
                 CoglIndices *indices)
 {
-  CoglAttribute *position = NULL;
-  int i;
-  int n_line_vertices;
-  static CoglPipeline *wire_pipeline;
-  CoglAttribute *wire_attribute[1];
-  CoglVertexP3 *lines;
-  CoglAttributeBuffer *attribute_buffer;
-
-  _COGL_GET_CONTEXT (ctx, NO_RETVAL);
+  CoglIndices *wire_indices;
+  CoglPipeline *wire_pipeline;
+  int n_indices;
 
-  for (i = 0; i < n_attributes; i++)
-    {
-      if (attributes[i]->name_state->name_id ==
-          COGL_ATTRIBUTE_NAME_ID_POSITION_ARRAY)
-        {
-          position = attributes[i];
-          break;
-        }
-    }
-  if (!position)
-    return;
+  wire_indices = get_wire_line_indices (ctx,
+                                        mode,
+                                        first_vertex,
+                                        n_vertices,
+                                        indices,
+                                        &n_indices);
 
-  lines = get_wire_lines (position,
-                          mode,
-                          n_vertices,
-                          &n_line_vertices,
-                          indices);
-  attribute_buffer =
-    cogl_attribute_buffer_new (ctx, sizeof (CoglVertexP3) * n_line_vertices,
-                               lines);
-  wire_attribute[0] =
-    cogl_attribute_new (attribute_buffer, "cogl_position_in",
-                        sizeof (CoglVertexP3),
-                        0,
-                        3,
-                        COGL_ATTRIBUTE_TYPE_FLOAT);
-  cogl_object_unref (attribute_buffer);
+  wire_pipeline = cogl_object_get_user_data (COGL_OBJECT (pipeline),
+                                             &wire_pipeline_key);
 
   if (!wire_pipeline)
     {
-      wire_pipeline = cogl_pipeline_new (ctx);
-      cogl_pipeline_set_color4ub (wire_pipeline,
-                                  0x00, 0xff, 0x00, 0xff);
+      wire_pipeline =
+        _cogl_pipeline_weak_copy (pipeline, pipeline_destroyed_cb, NULL);
+
+      cogl_object_set_user_data (COGL_OBJECT (pipeline),
+                                 &wire_pipeline_key, wire_pipeline,
+                                 NULL);
+
+      /* If we have glsl then the pipeline may have an associated
+       * vertex program and since we'd like to see the results of the
+       * vertex program in the wireframe we just add a final clobber
+       * of the wire color leaving the rest of the state untouched. */
+      if (cogl_has_feature (framebuffer->context, COGL_FEATURE_ID_GLSL))
+        {
+          CoglSnippet *snippet = cogl_snippet_new (COGL_SNIPPET_HOOK_FRAGMENT,
+                                                   NULL,
+                                                   NULL);
+          cogl_snippet_set_replace (snippet,
+                                    "cogl_color_out = "
+                                      "vec4 (0.0, 1.0, 0.0, 1.0);\n");
+
+          cogl_pipeline_add_snippet (wire_pipeline, snippet);
+          cogl_object_unref (snippet);
+        }
+      else
+        {
+          cogl_pipeline_foreach_layer (wire_pipeline, remove_layer_cb, NULL);
+          cogl_pipeline_set_color4f (wire_pipeline, 0, 1, 0, 1);
+        }
     }
 
   /* temporarily disable the wireframe to avoid recursion! */
   COGL_DEBUG_CLEAR_FLAG (COGL_DEBUG_WIREFRAME);
-  _cogl_framebuffer_draw_attributes (framebuffer,
-                                     wire_pipeline,
-                                     COGL_VERTICES_MODE_LINES,
-                                     0,
-                                     n_line_vertices,
-                                     wire_attribute,
-                                     1,
-                                     COGL_DRAW_SKIP_JOURNAL_FLUSH |
-                                     COGL_DRAW_SKIP_PIPELINE_VALIDATION |
-                                     COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
-                                     COGL_DRAW_SKIP_LEGACY_STATE);
-
+  _cogl_framebuffer_draw_indexed_attributes (
+                                           framebuffer,
+                                           wire_pipeline,
+                                           COGL_VERTICES_MODE_LINES,
+                                           0,
+                                           n_indices,
+                                           wire_indices,
+                                           attributes,
+                                           n_attributes,
+                                           COGL_DRAW_SKIP_JOURNAL_FLUSH |
+                                           COGL_DRAW_SKIP_PIPELINE_VALIDATION |
+                                           COGL_DRAW_SKIP_FRAMEBUFFER_FLUSH |
+                                           COGL_DRAW_SKIP_LEGACY_STATE);
   COGL_DEBUG_SET_FLAG (COGL_DEBUG_WIREFRAME);
 
-  cogl_object_unref (wire_attribute[0]);
+  cogl_object_unref (wire_indices);
 }
 #endif
 
@@ -2683,7 +2718,8 @@ _cogl_framebuffer_draw_attributes (CoglFramebuffer *framebuffer,
 {
 #ifdef COGL_ENABLE_DEBUG
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
-    draw_wireframe (framebuffer, pipeline,
+    draw_wireframe (framebuffer->context,
+                    framebuffer, pipeline,
                     mode, first_vertex, n_vertices,
                     attributes, n_attributes, NULL);
   else
@@ -2776,7 +2812,8 @@ _cogl_framebuffer_draw_indexed_attributes (CoglFramebuffer *framebuffer,
 {
 #ifdef COGL_ENABLE_DEBUG
   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_WIREFRAME)))
-    draw_wireframe (framebuffer, pipeline,
+    draw_wireframe (framebuffer->context,
+                    framebuffer, pipeline,
                     mode, first_vertex, n_vertices,
                     attributes, n_attributes, indices);
   else



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]