[mutter] cogl: Add GPU timestamp querying utilities



commit fbe6740df121db60e1dbe0fbc6b01a72a6401461
Author: Ivan Molodetskikh <yalterz gmail com>
Date:   Sat May 15 13:56:49 2021 +0300

    cogl: Add GPU timestamp querying utilities
    
    Add utilities that allow getting the current GPU timestamp and creating
    a query which completes upon completion of all operations currently
    submitted on a framebuffer. Combined, these two allow measuring how long
    it took the GPU to finish rendering something to a framebuffer.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1762>

 cogl/cogl/cogl-context-private.h            |  5 +++
 cogl/cogl/cogl-context.c                    | 24 ++++++++++++
 cogl/cogl/cogl-context.h                    | 23 +++++++++++
 cogl/cogl/cogl-driver.h                     | 14 +++++++
 cogl/cogl/cogl-framebuffer.c                | 25 ++++++++++++
 cogl/cogl/cogl-framebuffer.h                | 13 +++++++
 cogl/cogl/driver/gl/cogl-util-gl-private.h  | 21 ++++++++++
 cogl/cogl/driver/gl/cogl-util-gl.c          | 60 +++++++++++++++++++++++++++++
 cogl/cogl/driver/gl/gl/cogl-driver-gl.c     | 10 +++++
 cogl/cogl/driver/gl/gles/cogl-driver-gles.c | 10 +++++
 10 files changed, 205 insertions(+)
---
diff --git a/cogl/cogl/cogl-context-private.h b/cogl/cogl/cogl-context-private.h
index 25004c3933..5856f76e98 100644
--- a/cogl/cogl/cogl-context-private.h
+++ b/cogl/cogl/cogl-context-private.h
@@ -62,6 +62,11 @@ typedef struct
   GLubyte c[4];
 } CoglTextureGLVertex;
 
+struct _CoglTimestampQuery
+{
+  unsigned int id;
+};
+
 struct _CoglContext
 {
   CoglObject _parent;
diff --git a/cogl/cogl/cogl-context.c b/cogl/cogl/cogl-context.c
index b7bf14f87e..89019e908d 100644
--- a/cogl/cogl/cogl-context.c
+++ b/cogl/cogl/cogl-context.c
@@ -491,3 +491,27 @@ cogl_context_get_named_pipeline (CoglContext     *context,
 {
   return g_hash_table_lookup (context->named_pipelines, key);
 }
+
+void
+cogl_context_free_timestamp_query (CoglContext        *context,
+                                   CoglTimestampQuery *query)
+{
+  context->driver_vtable->free_timestamp_query (context, query);
+}
+
+int64_t
+cogl_context_timestamp_query_get_time_ns (CoglContext        *context,
+                                          CoglTimestampQuery *query)
+{
+  return context->driver_vtable->timestamp_query_get_time_ns (context, query);
+}
+
+int64_t
+cogl_context_get_gpu_time_ns (CoglContext *context)
+{
+  g_return_val_if_fail (cogl_has_feature (context,
+                                          COGL_FEATURE_ID_GET_GPU_TIME),
+                        0);
+
+  return context->driver_vtable->get_gpu_time_ns (context);
+}
diff --git a/cogl/cogl/cogl-context.h b/cogl/cogl/cogl-context.h
index 20b9561b94..38ac11be83 100644
--- a/cogl/cogl/cogl-context.h
+++ b/cogl/cogl/cogl-context.h
@@ -41,6 +41,7 @@
  * dependency issues with the following headers.
  */
 typedef struct _CoglContext CoglContext;
+typedef struct _CoglTimestampQuery CoglTimestampQuery;
 
 #include <cogl/cogl-defines.h>
 #include <cogl/cogl-display.h>
@@ -208,6 +209,8 @@ typedef enum _CoglFeatureID
   COGL_FEATURE_ID_BUFFER_AGE,
   COGL_FEATURE_ID_TEXTURE_EGL_IMAGE_EXTERNAL,
   COGL_FEATURE_ID_BLIT_FRAMEBUFFER,
+  COGL_FEATURE_ID_TIMESTAMP_QUERY,
+  COGL_FEATURE_ID_GET_GPU_TIME,
 
   /*< private >*/
   _COGL_N_FEATURE_IDS   /*< skip >*/
@@ -370,6 +373,26 @@ COGL_EXPORT CoglPipeline *
 cogl_context_get_named_pipeline (CoglContext     *context,
                                  CoglPipelineKey *key);
 
+COGL_EXPORT void
+cogl_context_free_timestamp_query (CoglContext        *context,
+                                   CoglTimestampQuery *query);
+
+COGL_EXPORT int64_t
+cogl_context_timestamp_query_get_time_ns (CoglContext        *context,
+                                          CoglTimestampQuery *query);
+
+/**
+ * cogl_context_get_gpu_time_ns:
+ * @context: a #CoglContext pointer
+ *
+ * This function should only be called if the COGL_FEATURE_ID_GET_GPU_TIME
+ * feature is advertised.
+ *
+ * Return value: Current GPU time in nanoseconds
+ */
+COGL_EXPORT int64_t
+cogl_context_get_gpu_time_ns (CoglContext *context);
+
 G_END_DECLS
 
 #endif /* __COGL_CONTEXT_H__ */
diff --git a/cogl/cogl/cogl-driver.h b/cogl/cogl/cogl-driver.h
index 21519085b2..aeabfe0e75 100644
--- a/cogl/cogl/cogl-driver.h
+++ b/cogl/cogl/cogl-driver.h
@@ -231,6 +231,20 @@ struct _CoglDriverVtable
   (* set_uniform) (CoglContext *ctx,
                    GLint location,
                    const CoglBoxedValue *value);
+
+  CoglTimestampQuery *
+  (* create_timestamp_query) (CoglContext *context);
+
+  void
+  (* free_timestamp_query) (CoglContext *context,
+                            CoglTimestampQuery *query);
+
+  int64_t
+  (* timestamp_query_get_time_ns) (CoglContext *context,
+                                   CoglTimestampQuery *query);
+
+  int64_t
+  (* get_gpu_time_ns) (CoglContext *context);
 };
 
 #define COGL_DRIVER_ERROR (_cogl_driver_error_quark ())
diff --git a/cogl/cogl/cogl-framebuffer.c b/cogl/cogl/cogl-framebuffer.c
index 7a8acecb96..525b24293f 100644
--- a/cogl/cogl/cogl-framebuffer.c
+++ b/cogl/cogl/cogl-framebuffer.c
@@ -2656,3 +2656,28 @@ cogl_framebuffer_get_driver (CoglFramebuffer *framebuffer)
 
   return priv->driver;
 }
+
+CoglTimestampQuery *
+cogl_framebuffer_create_timestamp_query (CoglFramebuffer *framebuffer)
+{
+  CoglFramebufferPrivate *priv =
+    cogl_framebuffer_get_instance_private (framebuffer);
+  const CoglDriverVtable *driver_vtable = priv->context->driver_vtable;
+
+  g_return_val_if_fail (cogl_has_feature (priv->context,
+                                          COGL_FEATURE_ID_TIMESTAMP_QUERY),
+                        NULL);
+
+  /* The timestamp query completes upon completion of all previously submitted
+   * GL commands. So make sure those commands are indeed submitted by flushing
+   * the journal.
+   */
+  _cogl_framebuffer_flush_journal (framebuffer);
+
+  cogl_context_flush_framebuffer_state (priv->context,
+                                        framebuffer,
+                                        framebuffer,
+                                        COGL_FRAMEBUFFER_STATE_BIND);
+
+  return driver_vtable->create_timestamp_query (priv->context);
+}
diff --git a/cogl/cogl/cogl-framebuffer.h b/cogl/cogl/cogl-framebuffer.h
index 993de7a25f..571b489988 100644
--- a/cogl/cogl/cogl-framebuffer.h
+++ b/cogl/cogl/cogl-framebuffer.h
@@ -1564,6 +1564,19 @@ cogl_blit_framebuffer (CoglFramebuffer *framebuffer,
 COGL_EXPORT void
 cogl_framebuffer_flush (CoglFramebuffer *framebuffer);
 
+/**
+ * cogl_framebuffer_create_timestamp_query: (skip)
+ *
+ * Creates a query for the GPU timestamp that will complete upon completion of
+ * all previously submitted GL commands related to this framebuffer. E.g. when
+ * the rendering is finished on this framebuffer.
+ *
+ * This function should only be called if the COGL_FEATURE_ID_TIMESTAMP_QUERY
+ * feature is advertised.
+ */
+COGL_EXPORT CoglTimestampQuery *
+cogl_framebuffer_create_timestamp_query (CoglFramebuffer *framebuffer);
+
 G_END_DECLS
 
 #endif /* __COGL_FRAMEBUFFER_H */
diff --git a/cogl/cogl/driver/gl/cogl-util-gl-private.h b/cogl/cogl/driver/gl/cogl-util-gl-private.h
index 0b7eaa772e..be8fa1eeb9 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl-private.h
+++ b/cogl/cogl/driver/gl/cogl-util-gl-private.h
@@ -146,6 +146,20 @@ _cogl_gl_util_parse_gl_version (const char *version_string,
 CoglGraphicsResetStatus
 _cogl_gl_get_graphics_reset_status (CoglContext *context);
 
+CoglTimestampQuery *
+cogl_gl_create_timestamp_query (CoglContext *context);
+
+void
+cogl_gl_free_timestamp_query (CoglContext        *context,
+                              CoglTimestampQuery *query);
+
+int64_t
+cogl_gl_timestamp_query_get_time_ns (CoglContext        *context,
+                                     CoglTimestampQuery *query);
+
+int64_t
+cogl_gl_get_gpu_time_ns (CoglContext *context);
+
 #ifndef GL_FRAMEBUFFER
 #define GL_FRAMEBUFFER         0x8D40
 #endif
@@ -229,4 +243,11 @@ _cogl_gl_get_graphics_reset_status (CoglContext *context);
 #define GL_STENCIL 0x1802
 #endif
 
+#ifndef GL_TIMESTAMP
+#define GL_TIMESTAMP 0x8E28
+#endif
+#ifndef GL_QUERY_RESULT
+#define GL_QUERY_RESULT 0x8866
+#endif
+
 #endif /* _COGL_UTIL_GL_PRIVATE_H_ */
diff --git a/cogl/cogl/driver/gl/cogl-util-gl.c b/cogl/cogl/driver/gl/cogl-util-gl.c
index 9b59bef1d6..096fcb7886 100644
--- a/cogl/cogl/driver/gl/cogl-util-gl.c
+++ b/cogl/cogl/driver/gl/cogl-util-gl.c
@@ -493,3 +493,63 @@ _cogl_gl_get_graphics_reset_status (CoglContext *context)
       return COGL_GRAPHICS_RESET_STATUS_NO_ERROR;
     }
 }
+
+CoglTimestampQuery *
+cogl_gl_create_timestamp_query (CoglContext *context)
+{
+  CoglTimestampQuery *query;
+
+  g_return_val_if_fail (cogl_has_feature (context,
+                                          COGL_FEATURE_ID_TIMESTAMP_QUERY),
+                        NULL);
+
+  query = g_new0 (CoglTimestampQuery, 1);
+
+  GE (context, glGenQueries (1, &query->id));
+  GE (context, glQueryCounter (query->id, GL_TIMESTAMP));
+
+  /* Flush right away so GL knows about our timestamp query.
+   *
+   * E.g. the direct scanout path doesn't call SwapBuffers or any other
+   * glFlush-inducing operation, and skipping explicit glFlush here results in
+   * the timestamp query being placed at the point of glGetQueryObject much
+   * later, resulting in a GPU timestamp much later on in time.
+   */
+  GE (context, glFlush ());
+
+  return query;
+}
+
+void
+cogl_gl_free_timestamp_query (CoglContext        *context,
+                              CoglTimestampQuery *query)
+{
+  GE (context, glDeleteQueries (1, &query->id));
+  g_free (query);
+}
+
+int64_t
+cogl_gl_timestamp_query_get_time_ns (CoglContext        *context,
+                                     CoglTimestampQuery *query)
+{
+  int64_t query_time_ns;
+
+  GE (context, glGetQueryObjecti64v (query->id,
+                                     GL_QUERY_RESULT,
+                                     &query_time_ns));
+
+  return query_time_ns;
+}
+
+int64_t
+cogl_gl_get_gpu_time_ns (CoglContext *context)
+{
+  int64_t gpu_time_ns;
+
+  g_return_val_if_fail (cogl_has_feature (context,
+                                          COGL_FEATURE_ID_GET_GPU_TIME),
+                        0);
+
+  GE (context, glGetInteger64v (GL_TIMESTAMP, &gpu_time_ns));
+  return gpu_time_ns;
+}
diff --git a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
index 35577518d0..ef4a61a09a 100644
--- a/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
+++ b/cogl/cogl/driver/gl/gl/cogl-driver-gl.c
@@ -539,6 +539,12 @@ _cogl_driver_update_features (CoglContext *ctx,
                     COGL_PRIVATE_FEATURE_TEXTURE_FORMAT_HALF_FLOAT,
                     TRUE);
 
+  if (ctx->glGenQueries && ctx->glQueryCounter)
+    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_TIMESTAMP_QUERY, TRUE);
+
+  if (ctx->glGetInteger64v)
+    COGL_FLAGS_SET (ctx->features, COGL_FEATURE_ID_GET_GPU_TIME, TRUE);
+
   /* Cache features */
   for (i = 0; i < G_N_ELEMENTS (private_features); i++)
     ctx->private_features[i] |= private_features[i];
@@ -591,4 +597,8 @@ _cogl_driver_gl =
     _cogl_sampler_gl_init,
     _cogl_sampler_gl_free,
     _cogl_gl_set_uniform, /* XXX name is weird... */
+    cogl_gl_create_timestamp_query,
+    cogl_gl_free_timestamp_query,
+    cogl_gl_timestamp_query_get_time_ns,
+    cogl_gl_get_gpu_time_ns,
   };
diff --git a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
index 3e8ea8a0a2..633e2c4157 100644
--- a/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
+++ b/cogl/cogl/driver/gl/gles/cogl-driver-gles.c
@@ -432,6 +432,12 @@ _cogl_driver_update_features (CoglContext *context,
                     COGL_FEATURE_ID_TEXTURE_RG,
                     TRUE);
 
+  if (context->glGenQueries && context->glQueryCounter)
+    COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_TIMESTAMP_QUERY, TRUE);
+
+  if (context->glGetInteger64v)
+    COGL_FLAGS_SET (context->features, COGL_FEATURE_ID_GET_GPU_TIME, TRUE);
+
   /* Cache features */
   for (i = 0; i < G_N_ELEMENTS (private_features); i++)
     context->private_features[i] |= private_features[i];
@@ -479,4 +485,8 @@ _cogl_driver_gles =
     _cogl_sampler_gl_init,
     _cogl_sampler_gl_free,
     _cogl_gl_set_uniform,
+    cogl_gl_create_timestamp_query,
+    cogl_gl_free_timestamp_query,
+    cogl_gl_timestamp_query_get_time_ns,
+    cogl_gl_get_gpu_time_ns,
   };


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