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>
This commit is contained in:
Ivan Molodetskikh 2021-05-15 13:56:49 +03:00 committed by Marge Bot
parent cc08af48f6
commit fbe6740df1
10 changed files with 205 additions and 0 deletions

View File

@ -62,6 +62,11 @@ typedef struct
GLubyte c[4];
} CoglTextureGLVertex;
struct _CoglTimestampQuery
{
unsigned int id;
};
struct _CoglContext
{
CoglObject _parent;

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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 ())

View File

@ -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);
}

View File

@ -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 */

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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,
};

View File

@ -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,
};