summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/gallium/auxiliary/util/u_log.c60
-rw-r--r--src/gallium/auxiliary/util/u_log.h17
2 files changed, 75 insertions, 2 deletions
diff --git a/src/gallium/auxiliary/util/u_log.c b/src/gallium/auxiliary/util/u_log.c
index 6d826f0adda..359b3e10a2e 100644
--- a/src/gallium/auxiliary/util/u_log.c
+++ b/src/gallium/auxiliary/util/u_log.c
@@ -36,13 +36,18 @@ struct u_log_page {
unsigned max_entries;
};
+struct u_log_auto_logger {
+ u_auto_log_fn *callback;
+ void *data;
+};
+
/**
* Initialize the given logging context.
*/
void
u_log_context_init(struct u_log_context *ctx)
{
- ctx->cur = NULL;
+ memset(ctx, 0, sizeof(*ctx));
}
/**
@@ -55,7 +60,56 @@ void
u_log_context_destroy(struct u_log_context *ctx)
{
u_log_page_destroy(ctx->cur);
- ctx->cur = NULL;
+ FREE(ctx->auto_loggers);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+/**
+ * Add an auto logger.
+ *
+ * Auto loggers are called each time a chunk is added to the log.
+ */
+void
+u_log_add_auto_logger(struct u_log_context *ctx, u_auto_log_fn *callback,
+ void *data)
+{
+ struct u_log_auto_logger *new_auto_loggers =
+ REALLOC(ctx->auto_loggers,
+ sizeof(*new_auto_loggers) * ctx->num_auto_loggers,
+ sizeof(*new_auto_loggers) * (ctx->num_auto_loggers + 1));
+ if (!new_auto_loggers) {
+ fprintf(stderr, "Gallium u_log: out of memory\n");
+ return;
+ }
+
+ unsigned idx = ctx->num_auto_loggers++;
+ ctx->auto_loggers = new_auto_loggers;
+ ctx->auto_loggers[idx].callback = callback;
+ ctx->auto_loggers[idx].data = data;
+}
+
+/**
+ * Make sure that auto loggers have run.
+ */
+void
+u_log_flush(struct u_log_context *ctx)
+{
+ if (!ctx->num_auto_loggers)
+ return;
+
+ struct u_log_auto_logger *auto_loggers = ctx->auto_loggers;
+ unsigned num_auto_loggers = ctx->num_auto_loggers;
+
+ /* Prevent recursion. */
+ ctx->num_auto_loggers = 0;
+ ctx->auto_loggers = NULL;
+
+ for (unsigned i = 0; i < num_auto_loggers; ++i)
+ auto_loggers[i].callback(auto_loggers[i].data, ctx);
+
+ assert(!ctx->num_auto_loggers);
+ ctx->num_auto_loggers = num_auto_loggers;
+ ctx->auto_loggers = auto_loggers;
}
static void str_print(void *data, FILE *stream)
@@ -96,6 +150,8 @@ u_log_chunk(struct u_log_context *ctx, const struct u_log_chunk_type *type,
{
struct u_log_page *page = ctx->cur;
+ u_log_flush(ctx);
+
if (!page) {
ctx->cur = CALLOC_STRUCT(u_log_page);
page = ctx->cur;
diff --git a/src/gallium/auxiliary/util/u_log.h b/src/gallium/auxiliary/util/u_log.h
index d4e6018c9f7..09c47caee55 100644
--- a/src/gallium/auxiliary/util/u_log.h
+++ b/src/gallium/auxiliary/util/u_log.h
@@ -35,6 +35,11 @@
*
* Chunks are accumulated into "pages". The manager of the log can periodically
* take out the current page using \ref u_log_new_page and dump it to a file.
+ *
+ * Furthermore, "auto loggers" can be added to a context, which are callbacks
+ * that are given the opportunity to add their own logging each time a chunk is
+ * added. Drivers can use this to lazily log chunks of their command stream.
+ * Lazy loggers don't need to be re-entrant.
*/
#ifndef U_LOG_H
@@ -45,6 +50,7 @@
#include "u_debug.h"
struct u_log_page;
+struct u_log_auto_logger;
struct u_log_chunk_type {
void (*destroy)(void *data);
@@ -53,8 +59,12 @@ struct u_log_chunk_type {
struct u_log_context {
struct u_log_page *cur;
+ struct u_log_auto_logger *auto_loggers;
+ unsigned num_auto_loggers;
};
+typedef void (u_auto_log_fn)(void *data, struct u_log_context *ctx);
+
void
u_log_context_init(struct u_log_context *ctx);
@@ -62,6 +72,13 @@ void
u_log_context_destroy(struct u_log_context *ctx);
void
+u_log_add_auto_logger(struct u_log_context *ctx, u_auto_log_fn *callback,
+ void *data);
+
+void
+u_log_flush(struct u_log_context *ctx);
+
+void
u_log_printf(struct u_log_context *ctx, const char *fmt, ...) _util_printf_format(2,3);
void